RcppAnnoy/0000755000176200001440000000000014553747041012175 5ustar liggesusersRcppAnnoy/NAMESPACE0000644000176200001440000000022613132210432013371 0ustar liggesusersuseDynLib(RcppAnnoy, .registration=TRUE) import(methods, Rcpp) exportPattern("^[[:alpha:]]+") # export all identifiers starting with letters RcppAnnoy/demo/0000755000176200001440000000000012427557230013116 5ustar liggesusersRcppAnnoy/demo/simpleExample.R0000644000176200001440000000104612427546253016052 0ustar liggesusers ## cf the simple example at https://github.com/spotify/annoy library(RcppAnnoy) set.seed(123) # be reproducible f <- 40 a <- new(AnnoyEuclidean, f) n <- 50 # not specified for (i in seq(n)) { v <- rnorm(f) a$addItem(i-1, v) } a$build(50) # 50 trees a$save("/tmp/test.tree") b <- new(AnnoyEuclidean, f) # new object, could be in another process b$load("/tmp/test.tree") # super fast, will just mmap the file print(b$getNNsByItem(0, 40)) RcppAnnoy/demo/00Index0000644000176200001440000000005412427504071014242 0ustar liggesuserssimpleExample A first introductory example RcppAnnoy/ChangeLog0000644000176200001440000004267314553605701013757 0ustar liggesusers2024-01-23 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.22 * inst/include/RcppAnnoy.h: Idem * man/RcppAnnoy-package.Rd: Remove reference to example left from auto-generated stanza (to satisfy a CRAN request) 2023-07-02 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.21 * inst/include/RcppAnnoy.h: Idem 2023-07-01 Dirk Eddelbuettel * src/Makevars (USE_MULTITTHREADING): Revert back to not enabling multithreading by default to remain consistent with prior behaviour 2023-06-30 Dirk Eddelbuettel * README.md: Add r-universe badge 2023-06-15 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll micro version * inst/include/RcppAnnoy.h: Idem * inst/include/annoylib.h: Sync with upstream 1.17.3 * src/annoy.cpp: Accomodate updated upstream changes * inst/include/RcppAnnoy.h: Idem * inst/rmd/UsingAnnoyInCpp.Rmd (Annoy): Idem 2023-03-17 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/RcppAnnoy.h: Idem * src/Makevars: No longer restrict build to C++11, also turn on multithreading and switch to C++17 (instead of minimum C++14) 2022-10-27 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.20 * src/init.c: And 'void' to six prototypes to make clang-15 happy * inst/include/annoylib.h (set_error_from_errno): Use snprint to make xcode/macos 14 happy * .github/workflows/ci.yaml (jobs): Update to actions/checkout@v3 2021-11-30 Dirk Eddelbuettel * README.md: Remove depcreated CI badge * .travis/: Removed 2021-07-30 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.19 2021-04-13 Dirk Eddelbuettel * DESCRIPTION (URL, BugRreports): Added to DESCRIPTION file 2020-12-25 Dirk Eddelbuettel * .github/workflows/ci.yaml: Small tweaks to CI YAML file 2020-12-15 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.18 * src/version.cpp: Export as .annoy_version as we have an R wrapper * .github/workflows/ci.yaml: Add CI runner using r-ci * README.md: Add new badge 2020-12-06 Aaron Lun * src/version.cpp: Helper function to report Annoy version * src/init.c: Register helper * R/version.R: R wrapper * man/getAnnoyVersion.Rd: Documentation 2020-12-04 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/RcppAnnoy.h: Idem * inst/include/annoylib.h: Upstream sync post PR #522 * inst/include/kissrandom.h: Idem 2020-11-23 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/RcppAnnoy.h: Idem * .travis.yml: Switch to r-ci 2020-11-22 Dirk Eddelbuettel * inst/tinytest/testVignette.R: New test file * inst/rmd/: Moved from vignettes/rmd * inst/rmd/UsingAnnoyInCpp.Rmd: Allow for index file 2020-11-22 Aaron Lun * vignettes/rmd/UsingAnnoyInCpp.Rmd: Allow compilation of vignette without adding more dependencies 2020-11-19 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/RcppAnnoy.h: Idem * inst/include/RcppAnnoy.h: Additional typedefs for threading policy * src/annoy.cpp: Threading policy typedef removed 2020-11-15 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.17 2020-11-12 Dirk Eddelbuettel * inst/include/RcppAnnoy.h: New header file for includes and defines * src/annoy.cpp: Use new header file RcppAnnoy.h * inst/include/annoylib.h: Add a temporary define to identify version 2020-10-19 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * src/Makevars: Default to serial use (and C++11) but add comment to detail how enable multithreaded indexing * src/annoy.cpp: Default to serial use * inst/tinytest/testSeeds.R: Re-enable test 2020-10-18 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/annoylib.h: Update to Annoy 1.17 * inst/include/mman.h: Idem * src/annoy.cpp: Idem, also enable multithreaded build * src/Makevars: Switch to C++14 for shared_timed_mutex * .travis.yml: Switch Travis CI to bspm use and focal * README.md: Update two URLs * inst/tinytest/testSeeds.R: Disable (already optional) test on seeding does not pass in multi-threaded mode 2020-05-30 Dirk Eddelbuettel * README.md: Add 'last commit' badge * .travis.yml: Switch to bionic and R 4.0.0 2020-03-12 Dirk Eddelbuettel * README.md: Standardize header and badges 2020-03-06 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.16 2020-03-03 Dirk Eddelbuettel * src/arch.cpp (getArchictectureStatus): Add simple helper function to show AVX and compiler status now that pragma has been removed 2020-03-02 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/annoylib.h: Updated to upstream PR #462 which removes the (optional and no longer needed) packing and one set of warnings 2020-03-01 Dirk Eddelbuettel * inst/include/annoylib.h: Updated upstream PRs PRs #460 (which uses int not size_t in one interface) and #461 (which inlines two helpers) 2020-02-27 Aaron Lun * inst/include/annoylib.h: Replace two size_t interfaces with int 2020-02-25 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.15 * inst/include/annoylib.h: Use alloca() portably 2020-02-24 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/annoylib.h: Updated upstream master post PR455 * inst/include/mmap.h: Idem * .travis.yml: Use r-cran-tinytest, no longer need edd/r-3.5 2019-11-12 Dirk Eddelbuettel * R/annoy.R: Small help page correction thanks to Bill Venables * man/AnnoyIndex.Rd: Idem 2019-11-11 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.14 2019-11-10 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * cleanup: Make safe for checkbashism by using only /bin/sh * inst/include/annoylib.h: New upstream v1.16.2 (plus up to pr436) 2019-09-23 Dirk Eddelbuettel * DESCRIPTION (Date, Version): Release 0.0.13 2019-09-22 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * src/annoy.cpp: Add unbuild() and onDiskBuild() functions * inst/tinytest/testOnDiskBuild.R: Add tests for onDiskBuild() * inst/tinytest/testIndex.R: Can now use tinytest::exit_file() * inst/tinytest/testSeeds.R: Idem * inst/include/annoylib.h: Use return code * inst/include/mman.h: Only conditionally define ftruncate * README.md: Small edits 2019-09-21 Peter Hickey * vignettes/rmd/UsingAnnoyInCpp.Rmd: Remove spurious comma 2019-09-21 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/annoylib.h: New upstream v1.16 (plus up to pr410) * inst/include/mman.h: Idem * src/annoy.cpp: Add getNTrees(), use error message in addItem() 2019-09-15 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * R/annoy.R: Use a tempfile() in example to save + load an annoy tree * man/AnnoyIndex.Rd: Ditto 2019-05-12 Dirk Eddelbuettel * DESCRIPTION (Date, Version): Release 0.0.12 2019-05-11 Dirk Eddelbuettel * vignettes/UsingAnnoyInCcppWrapper.Rnw: Vignette wrapper with tip of the hat to Mark van der Loo for his January 2019 blog post * vignettes/rmd/UsingAnnoyInCpp.Rmd (vignette): Moved * vignettes/rmd/rcppannoy.bib: Idem * DESCRIPTION (Suggests): Remove three packages needed for vignette * .travis.yml (install): Idem * .Rbuildignore: Exclude vignettes/rmd/ from build 2019-05-10 Dirk Eddelbuettel * tests/tinytest.R: New test runner using tinytest * inst/tinytest/testIndex.R: New test file using tinytest * inst/tinytest/testAngular.R: Idem * inst/tinytest/testEuclidean.R: Idem * inst/tinytest/testHamming.R: Idem * inst/tinytest/testManhattan.R: Idem * .travis.yml (install): Add tinytest to Travis setup * local/: Old RUnit test files in source but not in package * .Rbuildignore: Exclude local/ from build 2019-05-06 Adam Spannbauer * R/annoy.R: Added documentation * man/AnnoyIndex.Rd: Rendered documentation 2019-04-12 Dirk Eddelbuettel * inst/tests/runit.seeds.R (test01seeds): Simplified 2019-04-11 Dirk Eddelbuettel * inst/tests/runit.seeds.R (test01seeds): Add tests 2019-04-11 James Melville * vignettes/UsingAnnoyInCpp.Rmd: Document setSeed 2019-04-10 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * src/annoy.cpp: Support setting of seed for KISS RNG 2018-10-30 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.11 2018-10-29 Dirk Eddelbuettel * inst/include/annoylib.h: Only define NOMINMAX if not defined * vignettes/UsingAnnoyInCpp.Rmd: Simplified by having C++ snippets typeset by pandoc instead of attempting OS-dependent compilation 2018-10-28 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/annoylib.h: New upstream version 1.13 past pr325 * inst/include/kissrandom.h: Idem * vignettes/UsingAnnoyInCpp: Renamed vignette, one size_t use 2018-10-17 Dirk Eddelbuettel * README.md: Added dependency count badge 2018-10-16 Dirk Eddelbuettel * vignettes/UsingAnnoyInC++.Rmd: Renamed vignette, minor edits * vignettes/rcppannoy.bib: Expanded, sorted (thanks, Emacs) 2018-10-14 Dirk Eddelbuettel * vignettes/rcppannoy.Rmd: Minor edits 2018-10-09 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version 2018-10-09 Aaron Lun * vignettes/rcppannoy.Rmd: Minor fixes 2018-10-07 Dirk Eddelbuettel * inst/include/annoylib.h: New upstream version 1.13 plus two PRs by Aaron and Dirk, respectively. * inst/include/mman.h: Idem 2018-10-06 Aaron Lun * vignettes/rcppannoy.Rmd: New vignette on using Annoy from C++ * DESCRIPTION: Added required Suggests: and VignetteBuilder: * .travis.yml: Added r-cran-knitr and r-cran-rmarkdown 2018-09-01 Dirk Eddelbuettel * .travis.yml: Switch Travis CI to R 3.5 repo 2017-12-16 Dirk Eddelbuettel * inst/include/kissrandom.h: New upstream version * inst/include/annoylib.h: Idem; plus some small changes to avoid g++ warnings, also sent upstream * inst/tests/runit.euclidean.R: Relaxed one '<' comparison to '<=' * inst/tests/runit.manhattan.R: Idem * src/init.c: Added new Hamming distance measure (via template) * src/annoy.cpp: Idem; plus more use of template type * inst/tests/runit.hamming.R: Unit tests for 'AnnoyHamming' * man/RcppAnnoy-package.Rd: Documentation alias for 'AnnoyHamming' * .Rbuildignore: Ignore top-level *tar.gz file * .gitignore: Idem 2017-09-25 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.10 * inst/tests/runit.index.R (test03getVectors): New test function * tests/doRUnit.R: Small edits and improvements 2017-09-23 Dirk Eddelbuettel * src/annoy.cpp (getItemsVector): Initialized vector (#24) 2017-08-31 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.9 2017-07-21 Dirk Eddelbuettel * inst/tests/runit.angular.R: Additional tests from upstream * inst/tests/runit.euclidean.R: Idem * inst/tests/runit.manhattan.R: Idem 2017-07-18 Dirk Eddelbuettel * src/annoy.cpp (RCPP_MODULE): New Manhattan distance module * inst/tests/runit.manhattan.R: New test file * R/annoy.R: Load module AnnoyManhattan * src/init.c: Register module boot function * man/RcppAnnoy-package.Rd: Aliases for AnnoyManhattan 2017-07-17 Dirk Eddelbuettel * inst/include/annoylib.h: New upstream version annoy 1.9.1 * inst/include/kissrandom.h: Idem * src/annoy.cpp (Annoy): Update call to match updated interface * inst/tests/runit.angular.R: Update three tests as the returned distance metric is now the square root of the previous value * .travis.yml (group): Added per Travis blog 2017-07-14 Dirk Eddelbuettel * .travis.yml (before_install): Use https for curl fetch 2017-07-02 Dirk Eddelbuettel * README.md: Use alternate for img.shields.io GPL-2+ badge 2017-07-01 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * inst/include/annoylib.h (>): Ensure we write as binary 2017-04-09 Dirk Eddelbuettel * src/init.c (R_init_RcppAnnoy): Call R_registerRoutines() and R_useDynamicSymbols() * NAMESPACE: Use .registration=TRUE on useDynLib 2016-10-01 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.0.8 * .travis.yml: Switch to using run.sh for Travis CI * README.md: More canonical URLs * src/annoy.cpp: Use unsigned int for vector size * src/annoy.cpp: Added index admissibility test to addItem() * inst/tests/runit.index.R (test02badvalues): New test 2016-09-29 Dirk Eddelbuettel * inst/NEWS.Rd: Added 2016-09-28 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll minor version * src/annoy.cpp (RCPP_MODULE): New List returning functions from #12 2016-02-02 Michael Phan-Ba * src/annoy.cpp: Added explicit destructor 2015-11-17 Daniel C. Dillon * src/annoy.cpp: Templating Annoy classes * inst/include/annoylib.h: Ditto 2015-11-15 Dirk Eddelbuettel * DESCRIPTION: Version 0.0.7 * src/annoy.cpp: Changes to adapt to new Annoy interface 2015-11-14 Dirk Eddelbuettel * DESCRIPTION: Rolled Date and Version * inst/include/annoylib.h: Upgraded to new version from Annoy 1.6.2 2015-05-26 Dirk Eddelbuettel * DESCRIPTION: Rolled Date and Version * inst/include/annoylib.h: Upgraded to new version from Annoy 1.3.1 2015-05-03 Dirk Eddelbuettel * DESCRIPTION: Version 0.0.6 * inst/include/annoylib.h: Upgraded to new version from Annoy 1.2.2 based on our pull request (and fix) to support supplying an RNG * src/annoy.cpp: Supply R's own RNG instead of the default of rand * .travis.yml: No longer need BH, and install Rcpp via PPA 2015-05-02 Dirk Eddelbuettel * inst/include/annoylib.h: Upgraded to Annoy 1.1.1 (which no longer needs Boost) * inst/include/annoylib.h: Replace rand() with random() * src/annoy.cpp: Call save() + load() with use const char* arguments * DESCRIPTION: Roll Version: and Date:, remove BH dependency * cleanup: Clean a bit more in src/ 2015-01-22 Dirk Eddelbuettel * DESCRIPTION: Version 0.0.5 2015-01-21 Dirk Eddelbuettel * inst/include/annoylib.h: Synced once more with upstream; this version addresses the UBSAN runtime issue 2015-01-10 Dirk Eddelbuettel * inst/include/annoylib.h: Synced with upstream repo 2015-01-06 Dirk Eddelbuettel * DESCRIPTION: Bumped Version: and Date: * src/Makevars: One char correction requested by CRAN Maintainers 2014-12-07 Dirk Eddelbuettel * DESCRIPTION: Version 0.0.4 * DESCRIPTION: Added Depends: R (>= 3.1) as need for C++11 prohibits deployment on R-oldrel 2014-11-17 Dirk Eddelbuettel * DESCRIPTION: Version 0.0.3 * inst/include/annoylib.h: Updated to new version from Annoy 2014-11-16 Qiang Kou * inst/include/annoylib.h: Added Windows support for mmap * inst/include/mman.h: Windows implementation of mmap * src/annoy.cpp: Add two #undef needed on Windows 2014-11-16 Dirk Eddelbuettel * README.md: Updated to note CRAN package, possible Windows port 2014-11-15 Dirk Eddelbuettel * inst/include/annoylib.h: New upstream version 2014-11-14 Dirk Eddelbuettel * inst/include/annoylib.h: New upstream version with templated int * src/annoy.cpp: Updated for new Annoy library 2014-11-13 Dirk Eddelbuettel * DESCRIPTION: Version 0.0.2 * inst/include/annoylib.h: New version with verbosity toggle * src/annoy.cpp: Added setter for verbosity 2014-11-12 Dirk Eddelbuettel * .travis.yml: Enable binary index test 2014-11-11 Dirk Eddelbuettel * inst/tests/runit.index.R: New test against binary index * inst/tests/data/test.tree: Binary file used by test * inst/tests/runit.euclidean.R: Added more tests 2014-11-10 Dirk Eddelbuettel * tests/runUnitTests.R: Added RUnit unit test caller * inst/tests/runit.angular.R: First set of unit tests * inst/tests/runit.euclidean.R: Idem * DESCRIPTION: Added Suggests: RUnit * .travis.yml: Added to enable Travis CI 2014-11-09 Dirk Eddelbuettel * inst/include/annoylib.h: Updated to new version from annoy 2014-11-08 Dirk Eddelbuettel * DESCRIPTION: Initial version 0.0.1 RcppAnnoy/README.md0000644000176200001440000000467314447713301013460 0ustar liggesusers## RcppAnnoy: Rcpp bindings for [Annoy](https://github.com/spotify/annoy) [![CI](https://github.com/eddelbuettel/rcppannoy/workflows/ci/badge.svg)](https://github.com/eddelbuettel/rcppannoy/actions?query=workflow%3Aci) [![License](https://eddelbuettel.github.io/badges/GPL2+.svg)](http://www.gnu.org/licenses/gpl-2.0.html) [![CRAN](http://www.r-pkg.org/badges/version/RcppAnnoy)](https://cran.r-project.org/package=RcppAnnoy) [![r-universe](https://eddelbuettel.r-universe.dev/badges/RcppAnnoy)](https://eddelbuettel.r-universe.dev/RcppAnnoy) [![Dependencies](https://tinyverse.netlify.com/badge/RcppAnnoy)](https://cran.r-project.org/package=RcppAnnoy) [![Downloads](http://cranlogs.r-pkg.org/badges/RcppAnnoy?color=brightgreen)](https://www.r-pkg.org:443/pkg/RcppAnnoy) [![Last Commit](https://img.shields.io/github/last-commit/eddelbuettel/rcppannoy)](https://github.com/eddelbuettel/rcppannoy) ### What is Annoy? [Annoy](https://github.com/spotify/annoy) is a small, fast and lightweight library for Approximate Nearest Neighbours with a particular focus on efficient memory use and the ability to load a pre-saved index. [Annoy](https://github.com/spotify/annoy) is written by [Erik Bernhardsson](https://erikbern.com/). See its page for more on features, its (Python) API, and the other language ports. [Annoy](https://github.com/spotify/annoy) is part of the esteemed _let us find other music you may like_ algorithm by [Spotify](https://github.com/spotify/). ### Why this package? It provides a nice example for Rcpp Modules and use of templates: Annoy uses a clean C++ core with templated data type, as well as several distance measures. This package shows that it is easy to wrap both aspects from R giving us multi-lingual approaches to data discovery and machine learning. ### Status The package matches the behaviour of the original Python package in the original Python wrapper for the [Annoy](https://github.com/spotify/annoy) library. It also replicates all unit tests written for the Python frontend, including a test for efficiently `mmap`-ing a binary index file. The package originally built on Linux and OS X, and thanks to a patch by [Qiang Kou](https://github.com/thirdwing) now also builds on Windows. ### Installation You can either install from source via this repo, or install [the CRAN package](https://cran.r-project.org/package=RcppAnnoy) the usual way from [R](https://www.r-project.org). ### Author Dirk Eddelbuettel ### License GPL (>= 2) RcppAnnoy/man/0000755000176200001440000000000013763265274012755 5ustar liggesusersRcppAnnoy/man/getArchictectureStatus.Rd0000644000176200001440000000077513627327743017745 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/RcppExports.R \name{getArchictectureStatus} \alias{getArchictectureStatus} \title{Report CPU Architecture and Compiler} \usage{ getArchictectureStatus() } \value{ A constant direct created at compile-time describing the extent of AVX instructions (512 bit, 128 bit, or none) and compiler use where currently recognised are MSC (unlikely for R), GCC, Clang, or \sQuote{other}. } \description{ Report CPU Architecture and Compiler } RcppAnnoy/man/getAnnoyVersion.Rd0000644000176200001440000000113213763265274016373 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/version.R \name{getAnnoyVersion} \alias{getAnnoyVersion} \title{Get the Annoy library version} \usage{ getAnnoyVersion(compact = FALSE) } \arguments{ \item{compact}{Logical scalar indicating whether a compact \code{\link{package_version}} should be returned.} } \value{ An integer vector containing the major, minor and patch version numbers; or if \code{compact=TRUE}, a \code{\link{package_version}} object. } \description{ Get the version of the Annoy C++ library that RcppAnnoy was compiled with. } \author{ Aaron Lun } RcppAnnoy/man/RcppAnnoy-package.Rd0000644000176200001440000000123214553527625016543 0ustar liggesusers\name{RcppAnnoy-package} \alias{RcppAnnoy-package} \alias{RcppAnnoy} \alias{Rcpp_Annoy} \docType{package} \title{ Rcpp bindings for the Annoy C++ library for approximate nearest neighbors. } \description{ Annoy is a small library written to provide fast and memory-efficient nearest neigbor lookup from a possibly static index which can be shared across processes. } \details{ Details about Annoy are available at the reference listed below. } \author{ Dirk Eddelbuettel for the R interface; Erik Bernhardsson for Annoy itself. Maintainer: Dirk Eddelbuettel } \references{ \url{https://github.com/spotify/annoy} } \keyword{package} RcppAnnoy/man/AnnoyIndex.Rd0000644000176200001440000001252713562654000015311 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/annoy.R \name{AnnoyIndex} \alias{AnnoyIndex} \alias{AnnoyEuclidean} \alias{Rcpp_AnnoyEuclidean-class} \alias{Rcpp_AnnoyEuclidean} \alias{AnnoyAngular} \alias{Rcpp_AnnoyAngular-class} \alias{Rcpp_AnnoyAngular} \alias{AnnoyManhattan} \alias{Rcpp_AnnoyManhattan-class} \alias{Rcpp_AnnoyManhattan} \alias{AnnoyHamming} \alias{Rcpp_AnnoyHamming-class} \alias{Rcpp_AnnoyHamming} \title{Approximate Nearest Neighbors with Annoy} \description{ Annoy is a small library written to provide fast and memory-efficient nearest neighbor lookup from a possibly static index which can be shared across processes. } \section{Usage}{ \preformatted{ a <- new(AnnoyEuclidean, vectorsz) a$setSeed(0) a$setVerbose(0) a$addItem(i, dv) a$getNItems() a$getItemsVector(i) a$getDistance(i, j) a$build(n_trees) a$getNNsByItem(i, n) a$getNNsByItemList(i, n, search_k, include_distances) a$getNNsByVector(v, n) a$getNNsByVectorList(v, n, search_k, include_distances) a$save(fn) a$load(fn) a$unload() } } \section{Details}{ \code{new(Class, vectorsz)} Create a new Annoy instance of type \code{Class} where \code{Class} is on of the following: \code{AnnoyEuclidean}, \code{AnnoyAngular}, \code{AnnoyManhattan}, \code{AnnoyHamming}. \code{vectorsz} denotes the length of the vectors that the Annoy instance will be indexing. \code{$addItem(i, v)} Adds item \code{i} (any nonnegative integer) with vector \code{v}. Note that it will allocate memory for \code{max(i) + 1} items. \code{$build(n_trees)} Builds a forest of \code{n_trees} trees. More trees gives higher precision when querying. After calling \code{build}, no more items can be added. \code{$save(fn)} Saves the index to disk as filename \code{fn}. After saving, no more items can be added. \code{$load(fn)} Loads (mmaps) an index from filename \code{fn} on disk. \code{$unload()} Unloads index. \code{$getDistance(i, j)} Returns the distance between items \code{i} and \code{j} \code{$getNNsByItem(i, n)} Returns the \code{n} closest items as an integer vector of indices. \code{$getNNsByVector(v, n)} Same as \code{$getNNsByItem}, but queries by vector \code{v} rather than index \code{i}. \code{$getNNsByItemList(i, n, search_k = -1, include_distances = FALSE)} Returns the n closest items to item \code{i} as a list. During the query it will inspect up to \code{search_k} nodes which defaults to \code{n_trees * n} if not provided. \code{search_k} gives you a run-time tradeoff between better accuracy and speed. If you set \code{include_distances} to \code{TRUE}, it will return a length 2 list with elements \code{"item"} & \code{"distance"}. The \code{"item"} element contains the \code{n} closest items as an integer vector of indices. The optional \code{"distance"} element contains the corresponding distances to \code{"item"} as a numeric vector. \code{$getNNsByVectorList(i, n, search_k = -1, include_distances = FALSE)} Same as \code{$getNNsByItemList}, but queries by vector \code{v} rather than index \code{i} \code{$getItemsVector(i)} Returns the vector for item \code{i} that was previously added. \code{$getNItems()} Returns the number of items in the index. \code{$setVerbose()} If \code{1} then messages will be printed during processing. If \code{0} then messages will be suppressed during processing. \code{$setSeed()} Set random seed for annoy (integer). } \examples{ library(RcppAnnoy) # BUILDING ANNOY INDEX --------------------------------------------------------- vector_size <- 10 a <- new(AnnoyEuclidean, vector_size) a$setSeed(42) # Turn on verbose status messages (0 to turn off) a$setVerbose(1) # Load 100 random vectors into index for (i in 1:100) a$addItem(i - 1, runif(vector_size)) # Annoy uses zero indexing # Display number of items in index a$getNItems() # Retrieve item at postition 0 in index a$getItemsVector(0) # Calculate distance between items at postitions 0 & 1 in index a$getDistance(0, 1) # Build forest with 50 trees a$build(50) # PERFORMING ANNOY SEARCH ------------------------------------------------------ # Retrieve 5 nearest neighbors to item 0 # Returned as integer vector of indices a$getNNsByItem(0, 5) # Retrieve 5 nearest neighbors to item 0 # search_k = -1 will invoke default search_k value of n_trees * n # Return results as list with an element for distance a$getNNsByItemList(0, 5, -1, TRUE) # Retrieve 5 nearest neighbors to item 0 # search_k = -1 will invoke default search_k value of n_trees * n # Return results as list without an element for distance a$getNNsByItemList(0, 5, -1, FALSE) v <- runif(vector_size) # Retrieve 5 nearest neighbors to vector v # Returned as integer vector of indices a$getNNsByVector(v, 5) # Retrieve 5 nearest neighbors to vector v # search_k = -1 will invoke default search_k value of n_trees * n # Return results as list with an element for distance a$getNNsByVectorList(v, 5, -1, TRUE) # Retrieve 5 nearest neighbors to vector v # search_k = -1 will invoke default search_k value of n_trees * n # Return results as list with an element for distance a$getNNsByVectorList(v, 5, -1, TRUE) # SAVING/LOADING ANNOY INDEX --------------------------------------------------- # Create a tempfile, replace with a local file to keep treefile <- tempfile(pattern="annoy", fileext="tree") # Save annoy tree to disk a$save(treefile) # Load annoy tree from disk a$load(treefile) # Unload index from memory a$unload() } RcppAnnoy/DESCRIPTION0000644000176200001440000000220014553747040013674 0ustar liggesusersPackage: RcppAnnoy Type: Package Title: 'Rcpp' Bindings for 'Annoy', a Library for Approximate Nearest Neighbors Version: 0.0.22 Date: 2024-01-23 Author: Dirk Eddelbuettel Maintainer: Dirk Eddelbuettel Description: 'Annoy' is a small C++ library for Approximate Nearest Neighbors written for efficient memory usage as well an ability to load from / save to disk. This package provides an R interface by relying on the 'Rcpp' package, exposing the same interface as the original Python wrapper to 'Annoy'. See for more on 'Annoy'. 'Annoy' is released under Version 2.0 of the Apache License. Also included is a small Windows port of 'mmap' which is released under the MIT license. License: GPL (>= 2) Depends: R (>= 3.1) Imports: methods, Rcpp LinkingTo: Rcpp Suggests: tinytest URL: https://github.com/eddelbuettel/rcppannoy, https://dirk.eddelbuettel.com/code/rcpp.annoy.html BugReports: https://github.com/eddelbuettel/rcppannoy/issues NeedsCompilation: yes RoxygenNote: 7.1.1 Packaged: 2024-01-23 00:46:29 UTC; edd Repository: CRAN Date/Publication: 2024-01-23 14:33:04 UTC RcppAnnoy/build/0000755000176200001440000000000014553606145013273 5ustar liggesusersRcppAnnoy/build/vignette.rds0000644000176200001440000000040614553606145015632 0ustar liggesusersk0Ӧo{ "@l̞H*o˧^.s YCrJB3El@뇕j7UJ*E\&T)_je\Kct2,̷V޽w8z3@PyuwIm݌)Ix SDQ/Ar'coHţa= "0.9.3") { tinytest::test_package("RcppAnnoy") } } RcppAnnoy/src/0000755000176200001440000000000014553606145012763 5ustar liggesusersRcppAnnoy/src/arch.cpp0000644000176200001440000000164513753267105014412 0ustar liggesusers #include "RcppAnnoy.h" #if defined(USE_AVX512) #define AVX_INFO "Using 512-bit AVX instructions" #elif defined(USE_AVX128) #define AVX_INFO "Using 128-bit AVX instructions" #else #define AVX_INFO "Not using AVX instructions" #endif #if defined(_MSC_VER) #define COMPILER_INFO "Compiled using MSC" #elif defined(__GNUC__) #define COMPILER_INFO "Compiled using GCC" #elif defined(__clang__) #define COMPILER_INFO "Compiled using Clang" #else #define COMPILER_INFO "Compiled on unknown platform" #endif #define ANNOY_DOC (COMPILER_INFO ". " AVX_INFO ".") //' Report CPU Architecture and Compiler //' //' @return A constant direct created at compile-time describing //' the extent of AVX instructions (512 bit, 128 bit, or none) //' and compiler use where currently recognised are MSC (unlikely //' for R), GCC, Clang, or \sQuote{other}. // [[Rcpp::export]] std::string getArchictectureStatus() { return std::string(ANNOY_DOC); } RcppAnnoy/src/init.c0000644000176200001440000000231414326626772014100 0ustar liggesusers#include #include #include // for NULL #include /* FIXME: Check these declarations against the C/Fortran source code. */ /* .Call calls */ extern SEXP _rcpp_module_boot_AnnoyAngular(void); extern SEXP _rcpp_module_boot_AnnoyEuclidean(void); extern SEXP _rcpp_module_boot_AnnoyManhattan(void); extern SEXP _rcpp_module_boot_AnnoyHamming(void); extern SEXP _RcppAnnoy_getArchictectureStatus(void); extern SEXP _RcppAnnoy_annoy_version(void); static const R_CallMethodDef CallEntries[] = { {"_rcpp_module_boot_AnnoyAngular", (DL_FUNC) &_rcpp_module_boot_AnnoyAngular, 0}, {"_rcpp_module_boot_AnnoyEuclidean", (DL_FUNC) &_rcpp_module_boot_AnnoyEuclidean, 0}, {"_rcpp_module_boot_AnnoyManhattan", (DL_FUNC) &_rcpp_module_boot_AnnoyManhattan, 0}, {"_rcpp_module_boot_AnnoyHamming", (DL_FUNC) &_rcpp_module_boot_AnnoyHamming, 0}, {"_RcppAnnoy_getArchictectureStatus",(DL_FUNC) &_RcppAnnoy_getArchictectureStatus,0}, {"_RcppAnnoy_annoy_version",(DL_FUNC) &_RcppAnnoy_annoy_version,0}, {NULL, NULL, 0} }; void R_init_RcppAnnoy(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } RcppAnnoy/src/annoy.cpp0000644000176200001440000003037014442705672014620 0ustar liggesusers // RcppAnnoy -- Rcpp bindings to Annoy library for Approximate Nearest Neighbours // // Copyright (C) 2014 - 2023 Dirk Eddelbuettel // // This file is part of RcppAnnoy // // RcppAnnoy is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // RcppAnnoy is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with RcppAnnoy. If not, see . // simple C++ modules to wrap to templated classes from Annoy // // uses annoylib.h (from Annoy) and provides R access via Rcpp // // Dirk Eddelbuettel, Nov 2014 #include "RcppAnnoy.h" namespace Annoy { template< typename S, typename T, typename Distance, typename Random, class ThreadedBuildPolicy > class Annoy { protected: AnnoyIndex *ptr; unsigned int vectorsz; public: Annoy(int n) : vectorsz(n) { ptr = new AnnoyIndex(n); } ~Annoy() { if (ptr != NULL) delete ptr; } void addItem(S item, Rcpp::NumericVector dv) { if (item < 0) Rcpp::stop("Inadmissible item value %d", item); std::vector fv(dv.size()); std::copy(dv.begin(), dv.end(), fv.begin()); char *errormsg; if (!ptr->add_item(item, &fv[0], &errormsg)) Rcpp::stop(errormsg); } void callBuild(int n) { ptr->build(n); } void callUnbuild() { ptr->unbuild(); } void callSave(std::string filename) { ptr->save(filename.c_str()); } void callLoad(std::string filename) { ptr->load(filename.c_str()); } void callUnload() { ptr->unload(); } int getNItems() { return ptr->get_n_items(); } int getNTrees() { return ptr->get_n_trees(); } double getDistance(int i, int j) { return ptr->get_distance(i, j); } void verbose(bool v) { ptr->verbose(v); } void setSeed(int s) { ptr->set_seed(s); } std::vector getNNsByItem(S item, size_t n) { std::vector result; ptr->get_nns_by_item(item, n, -1, &result, NULL); return result; } Rcpp::List getNNsByItemList(S item, size_t n, int search_k, bool include_distances) { if (include_distances) { std::vector result; std::vector distances; ptr->get_nns_by_item(item, n, search_k, &result, &distances); return Rcpp::List::create(Rcpp::Named("item") = result, Rcpp::Named("distance") = distances); } else { std::vector result; ptr->get_nns_by_item(item, n, search_k, &result, NULL); return Rcpp::List::create(Rcpp::Named("item") = result); } } std::vector getNNsByVector(std::vector dv, size_t n) { std::vector fv(dv.size()); std::copy(dv.begin(), dv.end(), fv.begin()); std::vector result; ptr->get_nns_by_vector(&fv[0], n, -1, &result, NULL); return result; } Rcpp::List getNNsByVectorList(std::vector fv, size_t n, int search_k, bool include_distances) { if (fv.size() != vectorsz) { Rcpp::stop("fv.size() != vector_size"); } if (include_distances) { std::vector result; std::vector distances; ptr->get_nns_by_vector(&fv[0], n, search_k, &result, &distances); return Rcpp::List::create( Rcpp::Named("item") = result, Rcpp::Named("distance") = distances); } else { std::vector result; ptr->get_nns_by_vector(&fv[0], n, search_k, &result, NULL); return Rcpp::List::create(Rcpp::Named("item") = result); } } std::vector getItemsVector(S item) { std::vector fv(vectorsz); ptr->get_item(item, &fv[0]); std::vector dv(fv.size()); std::copy(fv.begin(), fv.end(), dv.begin()); return dv; } bool onDiskBuild(std::string fname) { char *errormsg; if (!ptr->on_disk_build(fname.c_str(), &errormsg)) Rcpp::stop(errormsg); return true; } }; } typedef Annoy::Annoy AnnoyAngular; typedef Annoy::Annoy AnnoyEuclidean; typedef Annoy::Annoy AnnoyManhattan; typedef Annoy::Annoy AnnoyHamming; RCPP_EXPOSED_CLASS_NODECL(AnnoyAngular) RCPP_MODULE(AnnoyAngular) { Rcpp::class_("AnnoyAngular") .constructor("constructor with integer count") .method("addItem", &AnnoyAngular::addItem, "add item") .method("build", &AnnoyAngular::callBuild, "build an index") .method("unbuild", &AnnoyAngular::callUnbuild, "unbuild an index") .method("save", &AnnoyAngular::callSave, "save index to file") .method("load", &AnnoyAngular::callLoad, "load index from file") .method("unload", &AnnoyAngular::callUnload, "unload index") .method("getDistance", &AnnoyAngular::getDistance, "get distance between i and j") .method("getNNsByItem", &AnnoyAngular::getNNsByItem, "retrieve Nearest Neigbours given item") .method("getNNsByItemList", &AnnoyAngular::getNNsByItemList, "retrieve Nearest Neigbours given item") .method("getNNsByVector", &AnnoyAngular::getNNsByVector, "retrieve Nearest Neigbours given vector") .method("getNNsByVectorList", &AnnoyAngular::getNNsByVectorList, "retrieve Nearest Neigbours given vector") .method("getItemsVector", &AnnoyAngular::getItemsVector, "retrieve item vector") .method("getNItems", &AnnoyAngular::getNItems, "get number of items") .method("getNTrees", &AnnoyAngular::getNTrees, "get number of trees") .method("setVerbose", &AnnoyAngular::verbose, "set verbose") .method("setSeed", &AnnoyAngular::setSeed, "set seed") .method("onDiskBuild", &AnnoyAngular::onDiskBuild, "build in given file") ; } RCPP_EXPOSED_CLASS_NODECL(AnnoyEuclidean) RCPP_MODULE(AnnoyEuclidean) { Rcpp::class_("AnnoyEuclidean") .constructor("constructor with integer count") .method("addItem", &AnnoyEuclidean::addItem, "add item") .method("build", &AnnoyEuclidean::callBuild, "build an index") .method("unbuild", &AnnoyEuclidean::callUnbuild, "unbuild an index") .method("save", &AnnoyEuclidean::callSave, "save index to file") .method("load", &AnnoyEuclidean::callLoad, "load index from file") .method("unload", &AnnoyEuclidean::callUnload, "unload index") .method("getDistance", &AnnoyEuclidean::getDistance, "get distance between i and j") .method("getNNsByItem", &AnnoyEuclidean::getNNsByItem, "retrieve Nearest Neigbours given item") .method("getNNsByItemList", &AnnoyEuclidean::getNNsByItemList, "retrieve Nearest Neigbours given item") .method("getNNsByVector", &AnnoyEuclidean::getNNsByVector, "retrieve Nearest Neigbours given vector") .method("getNNsByVectorList",&AnnoyEuclidean::getNNsByVectorList, "retrieve Nearest Neigbours given vector") .method("getItemsVector", &AnnoyEuclidean::getItemsVector, "retrieve item vector") .method("getNItems", &AnnoyEuclidean::getNItems, "get number of items") .method("getNTrees", &AnnoyEuclidean::getNTrees, "get number of trees") .method("setVerbose", &AnnoyEuclidean::verbose, "set verbose") .method("setSeed", &AnnoyEuclidean::setSeed, "set seed") .method("onDiskBuild", &AnnoyEuclidean::onDiskBuild, "build in given file") ; } RCPP_EXPOSED_CLASS_NODECL(AnnoyManhattan) RCPP_MODULE(AnnoyManhattan) { Rcpp::class_("AnnoyManhattan") .constructor("constructor with integer count") .method("addItem", &AnnoyManhattan::addItem, "add item") .method("build", &AnnoyManhattan::callBuild, "build an index") .method("unbuild", &AnnoyManhattan::callUnbuild, "unbuild an index") .method("save", &AnnoyManhattan::callSave, "save index to file") .method("load", &AnnoyManhattan::callLoad, "load index from file") .method("unload", &AnnoyManhattan::callUnload, "unload index") .method("getDistance", &AnnoyManhattan::getDistance, "get distance between i and j") .method("getNNsByItem", &AnnoyManhattan::getNNsByItem, "retrieve Nearest Neigbours given item") .method("getNNsByItemList", &AnnoyManhattan::getNNsByItemList, "retrieve Nearest Neigbours given item") .method("getNNsByVector", &AnnoyManhattan::getNNsByVector, "retrieve Nearest Neigbours given vector") .method("getNNsByVectorList",&AnnoyManhattan::getNNsByVectorList, "retrieve Nearest Neigbours given vector") .method("getItemsVector", &AnnoyManhattan::getItemsVector, "retrieve item vector") .method("getNItems", &AnnoyManhattan::getNItems, "get number of items") .method("getNTrees", &AnnoyManhattan::getNTrees, "get number of trees") .method("setVerbose", &AnnoyManhattan::verbose, "set verbose") .method("setSeed", &AnnoyManhattan::setSeed, "set seed") .method("onDiskBuild", &AnnoyManhattan::onDiskBuild, "build in given file") ; } RCPP_EXPOSED_CLASS_NODECL(AnnoyHamming) RCPP_MODULE(AnnoyHamming) { Rcpp::class_("AnnoyHamming") .constructor("constructor with integer count") .method("addItem", &AnnoyHamming::addItem, "add item") .method("build", &AnnoyHamming::callBuild, "build an index") .method("unbuild", &AnnoyHamming::callUnbuild, "unbuild an index") .method("save", &AnnoyHamming::callSave, "save index to file") .method("load", &AnnoyHamming::callLoad, "load index from file") .method("unload", &AnnoyHamming::callUnload, "unload index") .method("getDistance", &AnnoyHamming::getDistance, "get distance between i and j") .method("getNNsByItem", &AnnoyHamming::getNNsByItem, "retrieve Nearest Neigbours given item") .method("getNNsByItemList", &AnnoyHamming::getNNsByItemList, "retrieve Nearest Neigbours given item") .method("getNNsByVector", &AnnoyHamming::getNNsByVector, "retrieve Nearest Neigbours given vector") .method("getNNsByVectorList",&AnnoyHamming::getNNsByVectorList, "retrieve Nearest Neigbours given vector") .method("getItemsVector", &AnnoyHamming::getItemsVector, "retrieve item vector") .method("getNItems", &AnnoyHamming::getNItems, "get number of items") .method("getNTrees", &AnnoyHamming::getNTrees, "get number of trees") .method("setVerbose", &AnnoyHamming::verbose, "set verbose") .method("setSeed", &AnnoyHamming::setSeed, "set seed") .method("onDiskBuild", &AnnoyHamming::onDiskBuild, "build in given file") ; } RcppAnnoy/src/Makevars0000644000176200001440000000074314450047144014455 0ustar liggesusers ## Multithreaded indexing for Annoy (version 1.17 or later) ## requires this define to be set # USE_MULTITTHREADING=-DANNOYLIB_MULTITHREADED_BUILD ## and also requires C++14 for std::shared_timed_mutex CXX_STD = CXX17 ## So to use multithreaded indexing, comment out the setting above ## Note that it may alter your result (or their order) slightly due ## to the use of multithreading which alters the sequence of RNG draws PKG_CPPFLAGS = -I../inst/include/ ${USE_MULTITTHREADING} RcppAnnoy/src/version.cpp0000644000176200001440000000054413766143544015163 0ustar liggesusers#include "RcppAnnoy.h" // [[Rcpp::export(.annoy_version)]] Rcpp::IntegerVector annoy_version() { return Rcpp::IntegerVector::create(Rcpp::Named("major")=RCPPANNOY_VERSION_MAJOR, Rcpp::Named("minor")=RCPPANNOY_VERSION_MINOR, Rcpp::Named("patch")=RCPPANNOY_VERSION_PATCH); } RcppAnnoy/src/RcppExports.cpp0000644000176200001440000000142013766143621015755 0ustar liggesusers// Generated by using Rcpp::compileAttributes() -> do not edit by hand // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 #include "../inst/include/RcppAnnoy.h" #include using namespace Rcpp; // getArchictectureStatus std::string getArchictectureStatus(); RcppExport SEXP _RcppAnnoy_getArchictectureStatus() { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; rcpp_result_gen = Rcpp::wrap(getArchictectureStatus()); return rcpp_result_gen; END_RCPP } // annoy_version Rcpp::IntegerVector annoy_version(); RcppExport SEXP _RcppAnnoy_annoy_version() { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; rcpp_result_gen = Rcpp::wrap(annoy_version()); return rcpp_result_gen; END_RCPP } RcppAnnoy/vignettes/0000755000176200001440000000000014553606145014204 5ustar liggesusersRcppAnnoy/vignettes/UsingAnnoyInCppWrapper.Rnw0000644000176200001440000000042514442705672021264 0ustar liggesusers\documentclass{article} \usepackage{pdfpages} %\VignetteIndexEntry{Using Annoy in C++} %\VignetteKeywords{Rcpp, Annoy, R, Cpp, Approximate Nearest Neighbours} %\VignettePackage{RcppAnnoy} \begin{document} \includepdf[pages=-, fitpaper=true]{UsingAnnoyInCpp.pdf} \end{document}RcppAnnoy/vignettes/UsingAnnoyInCpp.pdf0000644000176200001440000014523214442705672017734 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 3307 /Filter /FlateDecode /N 49 /First 391 >> stream x[rF}8zoZ)EmR~HDL | XH bA{9h ˆ$ERDjb>I gFp=ᡖs"4g '\iO"RRUO4P8 Z*!@=*C'F- RI|ϊacCBE@! !qrhG J($%nDHBȌ]c- h@'Y`40*cB@pϹ>*`P B0 GA0 j{pa`ޡfɴǯz j0'r02XpzdL޼E$Iɫ!%y̎yD^"p%OT2M| @iA{2[y2z4͇GN,φiz~G4m7q>a2D@1; __Q(<%9慵\ +&a|חޠ58qG*_&5jM*@s4Τ֘"lo[RgX gC\.di'#L.+O:C:Ә~30g4OCUjO``!P~l _]I<-r1֭5z@ . ~Σ`KU~.|݆קO>\o4kLE?&&4*sjJb+ة^lG͕so =^˞]/S\9P)~џ8Wڴ> X㈞3h^-e,ghMXD hJ-Yt89V,+ќ4h=sNw&5!Lu{K CSMڭcFԗCo&g"og'qb(='YxՈ[GudA:tf n65EUn}Zyт2lǪGyW%ԗ UʡV[T\Je.]*f!ZC͖%׹*{}H?Ҧ뉭0Qw9B?.{kdq4/`W#M5&s>Z3W/45V0l6K-MQtUAibTFY&5&-?>?>hl,Ka2+AbW926pyN⺼g yl.nt_,B޻q9q a$$Md ~~~@m_jN޽8-+@ ͬԁV%x\}иVjD)^16%p7 O jAJ5e_7`f1*! 2j"ssf۫# Y|Ah嗏^UXֆDg((*Xi{v. PLBMexI0rT &泊UV-*fckꜨ/mu,M,EEg/i׿w~̒z)@j&Z1:1MT.nSY -y]Մ9T*di좜=Rx8;VlhESPNƏw>Ei6LhS(,$kURv"jMbuϹC(Vo_?+mUi jk 9ڞ)x V1j& tV3%570,?c|)(FYf>Nubq2<E1\+] ;GYzWEC|pm+%t*OUxHzf^&xK18g()<0/'%=uB9 *5*}My,(Q ,ʲ[QDw!qu4HrRSoʵRlr(zݨ=mvVۧojC $745t?{[V~ۉD(BߵN }߻tT` e(6M(|*S>m,-vt,EVSQP͠>%ҸãMpEX_޻SK]Hd۹a2͇UHMla= `xxS2_pvOSbN;>fY0xVIAPdC]:}߿{Hl t^L<a.e6 0|X0B&i-QQƘ3`ZC2趆J _.]Zub(4?&_U4m070|f Jj?GC(BO Q@!nBJW *aR˾2C-A-wwDc~?^,.|CWQ͠8YE3vou Kendstream endobj 51 0 obj << /Subtype /XML /Type /Metadata /Length 1387 >> stream GPL Ghostscript 9.56.1 2023-06-14T22:57:37-05:00 2023-06-14T22:57:37-05:00 LaTeX with hyperref endstream endobj 52 0 obj << /Filter /FlateDecode /Length 7169 >> stream x=ےuU~JM#X΃hE_^۩lW\) !|ERޜK7rCLj }N>>x7R1./4sZB*81:mn.]j0W_#)R'bty}isR]M`(J1\m,OV7㉲y%DKVfDe*秽M3ɺ=)o*|fM~C)tfZ%IVdV__^Gvb0$:U1H~Yn0vIV.w7A{Z@Jd!F*Jrv=^Z&"Oe&rF.50 l!S!w7nk :I7c!>˘ W:10(A/fv,MRmuGP܍I3dRWs^TVusP43s~U]"3)<*?Q8-a #րicljvȉRÝHf,42JڷDεod췾`d7ool%ʈp$עMhJd5~4ЬK ^7c"hU'?ҏ+yUjA_2iLUtIm- ͓ɷp'i2T,(8TY f(hn@7~VGhZaT2YZ4m "%; LYϘi}'"tʳt *G(1>H`x>=|N:BS];? b=P Bf[v)Fjq&ō4wb TW"ٯ;-{pEt̘ҚB<` FJ  )DBh ?`D O_XܫuRq\PtWD]$x~Ujڬf݂(b<عKh?{D> ťFP;yKH.Sf5n\/1Z ,ϲZP(8^Mn_w|dHUPNs "9}NcY͌ѡ,Fjxzk *ht6E*crH`@N1M]NJdS,&Vxs*#bsu%)0-e4hl׳YڃйTM^烉H DTG@-!m6K%]<$ 4hlPXEII룼l$iS.꿓O?34y7Vf mMIt ';3}z]Qo殍4!Kts"㺾m.'=jrk0= /:GD@EQADT=T9M䂵f'%Б:O,AG+U ?^uF][BH1W1:HYf@q)(8^QrLcI&H [-y<-"nj)FQBbuoǽ^#@%ƅ2-!dɜca { #{ &pTNw/}ueD!>}U{R(1HnM eb<14pqۉ7@bAͱPieP.g TJ"%Wm3۲^WSV tT }+{ YDmT5`P${9Ga[{Z"fdiZwrwT)>ۦ: !+I"YcLŶ9ʍH<퇺j<7bs6w@22Kf_[U5['Tn$Gyы"ByN| ]"Y)+)&XT,0qUr۫ۺoa:= h7H'kp6s#.$DЧjm'u5?5Dpt;EޭV^$7mRm6( %*حZuTY3 (r2ni7CN뿌D!'~yEFR";Բ!%%XD6r;P6 MUAX1D"g.i|r^0!-,!C5\h*9!Bp*MH P_{܅T?!#һ2dk}E0p[}\zqFKbCt1>il;4-psRGæaN zMwQ ܜ4H` m_G+dF .cL9| p\bF˚1-@&S{ߓQ56C ?PBW'TG&HU-(Gsd3>h" Nz]C{$<^Ū20g'|!czsFc2#5M~ oBb$k@D{U?jZhB!qc*cZ&. 6Xw$ra3MiY}}]m@+2WI@tDjn* YݕVS~0NHaFPlqi.wͦmlZ%4asZ)x,i]y:`D6W [Rݞo,t@n i+å*V|Rs#F$Ů1T35Ng^䎔^I\mkInHsbK2?ŀl^ԓick7hZE(}} ; N$]g2ąɺgKb,@v #ND&C1%Pev5I *+Ygqy \.r vo:S Ka 9_zt2z,jVQjBJB4LHjmN[֮I1v6ĺtRh 0;iyЮ P9;g Yd}3W߾:2|LDO EIiѧ||?ǖEʋǹS=[<*O'Яϝڣ܊ ?&TÃ4tƳ3,}< O"`4ByWY/C¥#6Bvkk*]%C1xIa#t%ߡ:0Ǡl-/]*9+4&*z~QOdX´ %9b8<,ͥ8 cSkM'^B-X"g>9,}i4e&3ɑb l[ bhia~͚=.vߔVE(T͸R ZkCƫIgk3 7>[; }tEpɰBݢ]oj(~7R3**6{LɄb<yR7yvI8C eR;|ox 8e t!]MRڔӟZ.$R5ՆB8!b:%& *:do(Y};Fq2~z nTz4?"J&R -Dk}պܴYЩL W(s##|=V^W AMC\ս)ˍQĴː"Wp( v?Tv W&h@`¤p{VͲ^V\9b9VRpeSCOf;̟pq@rw>~Az`Tn-gZ¢<|yN6g(-p]WѯXAk4>Q̳ oV[]Bl_\ OFfBI~.X~?.-S1HFP ?`#> cҎ1q%zW3G`a>?t4]& %ILӢdpeF]j}E.טT>S=cjM 킷ϮNc[h;KNzW-~櫂ċd E wV)վ^D+X 9!Ûa@||~j9y\-qL[?*Frʿ4*W'9Ȟū?M!p 섟e$CY>T>0QOdU! L sYvsCZ_99m6ݸs̃vgJjE~L B2,[8ۃrT V Xᔶ1ɻ @ tfۤ(Zuej?gjE//mT#`p6(>0!;(LBΆE|!SO[v"g6T{FP=7@iB&_|q~˞[MJ'A6

$1fM2 3GpN3d9t `(8Sw7xZρ }L||Xb2C)OEeIi6n<+8 @,չJp<'C:+.Gt`G13D,qwWM=ldʙSOHiK=QfOt I蠃.Zҭ ~RFWd=Zlz3(¥ThJh Q K yاQ|!rqOyΑ,O\< s`Bә>ʴ*$z NT03g䃋( #ADp[~ Y9F}:>CN%_T9ZL=ի+!:n=.'Ӿjۆmƹ/Tgm܄sg\~?7WR}XX,W_C|TN(e$ݦx1jŧbj]rx'F/WzPvp7on@Ef.SB#6 ,CGef]0ķ0; Hn-XÂPvQ5k~SN!EM!P!q%/B|[Gj4 R\V,%*s5C[؏#UN6lWO&rEׇ[‹TQHX{=㑋x"F&z00qw8Oey;G,}]/ܻwQ;$?cOZI ׾0 lESZ yf.4aG+~޽85ӎEWBzRi<@g{x}T7>Bg< *k 9pņ"g[^Z`%/= dO-`9Kopߓ1qO[E; CXwz/?}Lj^B?C 1؟ӧ45(+?0JRՠkFw_MrxnZ~ ]ƽԓ6ٸ/6|Ut,{gjC;6lq vQ:n})ntvmS (n[חj$oˋ!u^záWR|T-spVf Xwpg|PZ7 WվWu鄭:w  x$p'C3l77~+tLa4~IiY}O>x!(;7tokL;(e7]_tNB|rWR!5g[ة)E!Jxz7| mCs-aigk)}hã3'{p޶SU]b1tjȀ}ޟۖ-/S_ecn|Y]P.Isb F$OF=3ЖdGr참:q#=k 1‡Xt AMPˆ4^faP৩mŚ6xBG~<_`ߴRoѦl i_~?a<{?ϭu"ծ=✿yy<<'VX{P41$jQ])7Bcs2"&ME?QWendstream endobj 53 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1924 >> stream xeUiPga%k[An.ha,ɮ(1ZH%7r \oOpkDE.U<;7VTQZ1͚J<ϊ菭}u==󾟂 Eu #+'e*䱮M_ gBUH=(Ϛ"o¤Ҕԝ)j:CfRTImVQQT4ZCHSoT/UN}U\YsOEy7ָz-$Uv:\vb,X$]zT>`ȃDi~@BMh8Շ |G')g>O)ˤ+i _UzmewuwXzpog]E[8r\(@ŇnE !JY\l,">x,$F#1#q1GB0owH9 7()Ǧ\cj&iY s&u)g.0 .鋧n6߄ah׶k[ˎ0h6`;k8 V%.˕eϴgZ f.Y0%t8'Bvu6w-쯅$+J#7~{W.1?S˞%TT2^_ שN_`00j.,GT蘟&w,e^o/f!ɹ˺@Eqi2ȓ+?6*\~]Bt_9օ";:$HwUKAp(h$ȭ\0H ͘y\h~Cv V. HQendstream endobj 54 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3019 >> stream xViT-N#***qAAŧ" (* Ȣ ,.A# D* @DE{i\hAogIy?sk~ﻷhŒi˴X͢+EJsұzG ͑ܢNma}.:)C;ygzEJU~IɋDD.8kif#]\ LQt/@fP@j5M͡ j05QT0IyQjʛ|BR4JARJ+S)9:QZ3L@YP J':73_fzqG/?klLS(˖=`3Wl?v%er\VwXﰮI-OoCMGҁ!:ZZ<@ ա ]#Y kAP)Dg6=,nʚ&Q>ƒ%ST  ־71lzJ“33 B?uS?6_R))}Ut݊A^'m}|=O[1ҧɼ*~s;ë1MP-]׃ Bv#`G&9`3 F¨o 'Sb9u,+j5$ڛ}N>syXioϨ VBn}[*hWO(L߷JQ둳 WnA C`fFKp[w'[,ł;]ݱL{!$nJ'TʀZ6#k3ڂp5Θ@!PHvy |5DVfft-z!C.ۀقGy޸UBA a\PT[ZwMȿyUeUeϡ:SYwMۍr%e_R%$#xqs ~̌ QZcw5n[Ff pkԜ3qNԓ) ½kʮglo7mRMam:ttDMlNAXߪL2" q.S?ȇ]IA>F ԌqJdD!^^!-o~mK/Z,U|V.څQ}ƹѯ]U!IP}UȄ(-=T^|꫄:/Vo\^N/9q[Sܼmvvd9/X8L|#Xo7]bCsqɎ~-؟:+8[@ʂ kNTGVx^|dLGD6nR/ L< >UfrQ|^9Tr8ue*7e:G抚SjJ,ؿ]Ad,o˵FEUcT`ۻh˶O)rU-??r?X:kf{%FJ0tҰE!aŁ_>ӲJO5V^ n؋7z7¹̢K:fxR3ƥiׄk#PXWqBv9wpID RtqoXG> stream xWw\Tg>rp@ZbX!EDJ" "M4)Eb 5\b/\ro3333+Q2LynYb}:d9~;KD#m9*eA@w]JḰl]dd[Ⱥ뗅zmhqɌ>3lbʤpSQXʆGRv=5rVP(GcʉL9S.ʕJRn"j:eAP%5ZB͢RʔZF}B->9VQ<DPéHjQ>`jO Ԕ5Gȁ2SY AryV6zƘI`XC֏mdr^\უ_b:D`}2otugJ];]_vzzz= SE7mb:PQx5ßX9TkcE:*ig p!"{Hk4 :Vx5#^AU"_UtMPŸ%emȯN+Gb*| wPvjZ /KO9oz 'tuWJ QG!GfەIaRt,|;P?ث|;F0h)uf&D8*`ݙ "#i<!Xi.,L ^QAh{twfu±]U̢ޒհuE(e 1lO A_bPoFo=^;I(^ՠow7W Gܰ )yeCO_rտ*NzHarGcIِWGnQ{fl¸ʔqFGcqupM;h $o㓠&1h˟꘰jUF()T ),fIU5 J< {c+Zx>)x]OWA,q&cuG']'g.iڟ٢fvl҂bN[7:mdr5ÁZŏlƄ:vyRX ~d[I0Z^Nh:՝UaYvEX9c㼤PNluzt႒rIU{Rh-Zx.?;FZH❨N|\+뤞돦C&ك+9bPh^-` L{ |%ZO"/tBJ8`ՖHW:ݣɐyt9z03L8N<;)]

44Ŋy[S ` 8kct4+w#ZQ[z}/\+ߺ\ cjHO#T-W$;㏰},vլ`sq|8bfmRDTۺ+e  R{3BMm`Q+{{~&HȄn3~C֬ rSABKf+RKIZzXic ⷣH٨Y^r-m%y=aL:oe_#fceuzP2·8J[.KY@w`m 5ZY3yp]> qKn0P\|ܙy펵xtny:F>]~$$6Y$h@IC>@4 DAcTCﰪM Xy8G )^Lʤ+@:Qkfؖݴ?1̒)cF0 ;Ӛ[wRůtZwkHXS F 0{tΣ*ͪfNwcCYQ }U|:t˃s(eqx.¶R+"ԲۭcIQ14ɪAS`⊸ w@UMC(a oc66Mᗯ^P΄g;ہkkƣ](D&v58HP0Em,6@XF*M]~m?6Wlڿ,5EO31-這d[S*MV-_DV1˥Ҋn[,!TC3gBܯh$8!>?-y-Z3 @`#ls_M<{ +o^mF0?ZkIJkSֱޱvoFӑ{{  H/Cz8 crI /G\x?K[Mc'uSg'zq2'.92u ٝggI *<}="Mf~4Y%2{s$ X{Wh(ޫAV`?7 0M"n;pQyya?]"`T^$%,%mQm ݞCOD[\C.E$K iVV59f5ƭѭ+K"aSS0q8 31= nD܁̽=t"Gɫ=S2QҶ`u?'M!<гE]&%:j; O,Q6'Hwd?̥J(un2,4˲΀3:#"ig،4LĄFZJeԱID\ilFD4 L# R)`-yQF_0;Ѿ`r]^wH{ދmJyv1ؓ;%zI[+#{XsZ^4N,LZQ~lmۥǚkZ΢[Hs[94r^X2RŸ~J3T ?G ȵkc+ ?sŞZYf<7(zE_g Lu)MxI^l+Mh}]FRJ\j,X!mK6ppYx~cuZ G| ؼcc/;ؾ/mAk+u&je,9\c`420K|w-$^JC{|^`Ӟ<,S2. "d"i?Z-n8/9i xTR@؍y㺁@ [}C"ӢH%B6 "9X7.e)C*a ʼ[ %T.e(5o;Lnݬ#zr@^1>Âިĵ9aဓ$vpQ֤8b\@pp<c|rF}Iů]GJ3QW~̉x6(^4-UKr:Opbe6x-9Qa.*))((9TVZIʮ _ ;26w pa[B֜ hAWz0?J)d, [&x\@KFle˲%`QM8[B8{p6@lx0 C>@ڃM>((endstream endobj 56 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3846 >> stream xmW Xڞ23"! +"(`*""XPD"U*.#Z-(UjEZETj]"0D`ib7O&y3'sswD %RX.<.-hĤ܈\߭ϕ s127-ah EV0IJq%|y]1o]9+rBW.H K^*eH=O6q'8<ŕPʑZ@¨*K-"HʉZLM>)g*KM)ʗrQ~dʟr(w*OM`j*BYQT %>8ʆʦRvpJNQf9eA=%5EpSt*O4X@Tm"3 35D#o_4T/q$H%M-OW/O&e} o" 0~3Op,';<mfqEttDzUL̷mYgzW%j~JħA:׊%}4.+%؜ƥJotK 57`/$R-*6簻VM33yU7_>uLW1QJ-#=ؠnA.Dg+m@C7/UU7n C: V?8{0T]x>B!_ZZr|뉜_*Qy`u03ׯSnZX(wnUtA]N}0<./a. @ַ:T2SjDWub4pUc4L 䈰散|n=^<旣N 6ڐ ^I ,By!7T8Msռں^`zq$}%v#W 3LB!{Nf۽ ~n^Zw5W:~NC6daS`>Os]N8G)ܺ[QN ǏFB>?Ic(W*K>9*&V$B`P'{{UoݵixZz'+kzHy A{΁c1+ul5]KRmlAؕ r*(DzP]ttңY^ɺ{ţ09jEvW>zXH.-#ыN1#Hixߏ{:By_*OR%#D]  {:gt|-d؇z]'iq2]=Uz3TDozWr=l#"h1D3xb{ޓ ZdAaR2rWDoB E|gZ_a1_Qd4=lO~L\%('S]mٹmGlڧO*{Fw s'$׭٬ܹ}NbUQ JP6X1$#u)cXȓQ*-:cCyRW|iju _*s5=v6|`r$`B:5cA"%.$g[8΁ 5,80`bHziw.q=_RBbKM򹟬Yr#n KO%WgTb`{@3D!mpÈCh5[=mʜdd_͔m)qBG<|*K9gIڬ܎e'{M7joJS|뺨m++K d / &OBEx"ک*=apuߚA[pw yR~'c2:節kad?w6X:ɘ~ҼA+yo$ G/vuåU/gON3 g4Ƃy#$&Hx3[`qz{X=); cd-"-q }A}QaygӮ9\w,l"fOZdlz7կ;4: {k mMO `Hp\ #|x{ 2.&I씂Xd]G}dp>l&fxG(9Pj$Cl̤N"7qԖ * ڠseΏÙ5t)=zJwVOVe_Ė*@rN>B0ϩy^suɂ&(ǯ7%b=g e*MA؄qd3߾~|QEMD2p+M:<'/KbA5zyy|Ю<SR^Q` tC'mlzzF#/IS?c?\7PMbqb3g+%hA qΐŊ^f:1_+tbfO([z"Yt:5| p90 Lz`/f8=3Y<_I#l`/ѐhЏS~X5)?/Fʪ 4i^H~aBx"!@x?dz"nZ-Ow˂XY?{Z-n1Gq(4metLp3¶,.2p' |y&Yif)11ǻ,"!EH cR({6JQ7*wN,A]|)=w]a]|ʮoVu;.]\?W'f$n9һ-?pXw'ѸpVxʒ$bk]{?txb51r *mN\9vtZ:^Zz/'հPvgА:@ ]jp3%kk &tF|9uc^"F+I?rb>p{_-ĵdWǫ̮5Dsߡ-ooĦ24^FcOmd_?ujn($7[;~8?\9^p=DX{bqwx6N{;_cWcDΙ}+O읶1|SBouv6{N4O )}c1) Ϳ7gsѦ@>ZrTZo Sx)KLv {lvb6mp “vߐj1f"@^ Zp`\su8{ dnA8lE;♈"ah2f6YL885yL 1{N ߾T p7OT |*LN>bre_re_r9wZǡbũc[ R}z`ᄁȮ,?smfNjFc-{VKiMŭQ|ⵗ;"J-sa_>G222KXƛ7Khج,"s3d>[SCendstream endobj 57 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1794 >> stream xMTkPWa#c lX C`y !AGeGQPFQ(>.L40 U.U٬6ŭTwsD%?ڙ_z6mZ_Q_:hd-F+-ڂ͓%cK)Ii WE,u-E9R*bTG%PH}@Sۨ*ZDYR2Pj\,24;.N׋1_iDt#=0u̸ґ` n]µbgLY4e{%,6 p^ZƒaEm$׸h]j2L)XB Q7P#t~#t2}v`js"r]$Oh=$4wc" r_b/<2&>($ 6JO@i1'@?-2rft,8ڗ|PJ_t%JIg)ތk9g;@CCP̥]Okscʴ3wh3 M{:}Ecu;W1 t%]\"65 vw]34"Đ\:b<_YQ}L!́|sLؙd I&?U>Ylo;6~UW hZ}]bG?Sp O nA/:i"-튻pq"T$x+⠷%N qth[*fta 쥳u娫Gۖٙ@xaab1M%hM'% mXO@%' >"?7eqC7+q;Q&pݠ8.Ò͘kpf9nh=֏zPc9ŵ%(ڴ`; X{Z1c*RF# "lbf1,;=؎{~{6ÎEB@X&Į ѣ3O(O|dz kB: $E<dUܶ ƹӅD!t.1dhORTKEWGl@ 4؁o$gWs*}[9}ye<z  \@Ih޲25q$MW;P G?j[QqG[cr䷠986"x0&xL.\Mf\I7 ?ɻWnpJDp1$;Q{UqNgm ڮ+BP&2~2EhΘ J /^8 #:1u/b3Z^ $iV8yg^gWba1 b&?䎰}:ߌWTnrb%v>e;%8[!kKdM?cendstream endobj 58 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1706 >> stream xuTkTTpQQ3#( U4&򈱉lc5d6q;L ^۫9Zd :rrlmնڂl7613qg>aS,Ɗ6y2e/fͺ(_*?(n%X'_spAa ^F, K?URU3 XHmɥ&PIRM!,(:s _P+v\TqF ߣU0ekHrPF&# ->DȣnQAZP8R&NlW)m g >2pWh j4WNFiiy7x0 O?!oO_sy󏍻6YE r Pۑc﵄OO+*Jҽy@ "dJ&)_ ;uj9 kWDVX'vQ+5[dq}V6A@/ cܩ~0N|ig@l6{|Fr+Ө^YDٻ7x|kwJ"ލ3S+\߅.0?~y87>(,huIMea%O'ÂF>"s|pKax7w^Mƒ vxoV vֶ5㙰|~/;=:"iWu`FϿH[dH[fp.udy u]&WVB2*)ܢXY^y%椾;w3GJ~im uK9{/?^luo%PqyzL\tHTu3-,'L,u8!zM =_tv'tFR^ KhFz!3Q RKabn`6(`7llMlzm5endstream endobj 59 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2082 >> stream xMiTSg%䢘Vb w7sEkǪjm]-(IXD@0, 5l K@p!beqjml|y/s~=>?0Ǘ~:=h*Rm?\P"38;.pҙw >!1ILJ;z<6N&x5`b,ۇav, ;vcǜE;26/戝b!'3ޱ'sqyy7xa+̵E.9Wz3ByJ$/_"GB`Է[S3Ϩ5䗧.HTtS\7@Ti֘7EmҎL٤!~t/9sYӅ7943)]?`p^FDߏ)0M%ޏ>3cck~D|FM2ڬpapml٧YjL< ok ghyoa)QtZYkPǑ͛6JEc) $kI>tF*ԝW)"Xn`5|:ܜfMq`C; A ~ܰӭ;Ϛ8AH *p %U4ӵ+2K2%KNڎ?QC 2t_,/Д|L38g8p3% h܄3*N#UI̋ΔjTNnXTUT+:zzencܻY?E-]H'xh}i~`7 Ҡå NT+/XDpGCm_y=VCQMTx(õϠ#t:_ y\C1V2ic %o!1P 9<&MKIm3: G[V|ZSje~?GVƸ5ulMjFc;b Ŭ`Xsg *!y:rzOޟ1)p??nx Aۢ$^UVj*k{oXY:tjr(n"H@6&L@qfjG3˶P4Jm\aj $ϧķ$y*Hof| 7g'P`V۬'RPG ?|öϲ6܀߶A ρLhKF&nب~jDyqB`='>d?O,6=8}/0 }mOUVwF=ETfu~(>ӻ*g32y#<>%eYErA޹c#~t shy+@]qMYl)E <_LCF|/W0 yxY*3hz(Dm2PPGB"tvm3}oIr6ku. $Tگs;^F[[eN,IϤ$X"S/oYVk)/1߲KC[h ZyW{KGayW_\*q \˚T&csɘ/JAIB)%''Ũ?ߞ= WZSʓe+R);՗+-(,"%ǶLZ1lE3rc@֤^)oaȳ'y> stream xXy\SW1& *$FAk[gVmq('p1$!L <&̈ V9jGum} kG.3k_e1x֫es 3d͵IcG!,GXSŲKCCG?ڹ*s/]k]|\}>-h3gyyߙ4yBR({j-@&PP)7j5HmPSRj*rQ2]j95ZA͠VRS('j6Cޣ5 %$M8j(5Hj5(1d␺!bfRMpc#"[vpaCm[|` 3:Y#^h&x%G-tmѣcǼ]jda-#*{xKj"øƄ|d@Ĥ A )QhDs_=wnu%!!T]+,Eu%+#*չ" !_` {?>1t0EgC&rq,<;cd~l+Am1xLKw}w":{+fV=-s`c:BFmqs} ͥ>fbE2ĉy/ڛbLK:@FG[–|w rciɐY$tN>X:͝iJ.M-LaZwDB,%-Lb$֖3X]N|M:UXKeO-ݙq!:$m _f2 䔌N(ψ}wC4vzD@d}ofQo/(&IZD(v041ABy5SFFao4rn ""*-0Is#b]B4z:?*B6߾w=ӷr+d 3uEВ/@ M T _EOz=,ڝAnJ"mh62S(u^9̮;5,x5\ǽeسLCki{laf,-FZdW0~mKW(|.{[l@7)өu/c?K-A(5VV&J7f7VTϞwrH:QfAyOwjTryKf\@U(c[_Z؁M=ԉO c$\YaoH̀k"Y՞L}fGoa4lI /;?-ںIkQ˸UH5(EzE$-1P8WϖgZm>Hv3x.IVpHK*3 P6o KU'10x' {@*x xx$ M []9m#AMMLB; l- mqy"Dc 4{zACtדQF0Pb^/0/Gֈ="}Hdnx4qM⹦8+z@iqBǭ:"F1 ˸lvAml(SN^I* PJr&'8;{ O+HT /:-+OXK K˭Mk +؃D{Cv՝֖zaQD69IHbbcv.C_{%*/IGY&MVe%!QFSwykYx/a$kȗz^<#d%\ 'dƚ~##2a+^iD`HnHhR8mB*\^p&f2'|%6+>/5ڬfPחÃTwASGL% A]%$ E(ߣU~pג Jp8BJ;}CKDS:=T p(ShyWR'cVGޟԱ#LTmޢ宗]F7@CH wkziw=d'BuEz"c XGLq aDcݯaЕߟo]A[s 1 =l3R8YsdG! 8_VsQ<}zytX񩆢-_V9"&Hiu"+|̝~5.]fdS'USi0d~sF&3D"Qemuԧv*R@dؚD]w˫b I'+6Rwnͅ`N3!m.%7m؞,a+ h%|+Y"!;9XѬ. ˞HGZr:šLJEJHbbTMHXfU}L-[UTQ &XYQb'̓رiӎS:w1/0'Zc;K::5wbzH:;P\ X8ª(߾@|"=Tt&976 躀rT5L\:5S$->{gx(WmzAנPQQϱh I^V6(Z}Uwo\1aeaAi?dͼ)x2F;('pZi}DuppDDppuD}}uu=3؊9Wv\# `5ڃv(͋^R :*:qKe1Yz}\;qkw #z[xc{cҍ}?hU,/ a֧vWk?Y\xNyѵWfn>"UN)y3މ4R PPl{Q2U+2(O$ǏX$}oðK^=KČR\×ϥpJ@7XUJ77Ѥ)1ujg ;Z Ayn| q#DdLҦwAߺN(3Qh AF!Qk8}-'}~ V fQilsog  6% 1>#b-U,f&͞LZVq7BDIRОqIP+/ފPuxx3c*Yv]}e? |#=I 9m­q1 &D;qQ"9iHQPl<x##;V<~0wպ_S=x '?3BVYq^_{&S=2㫑kD|!h=, A‡o8PP]OHPOSH󡺦fiȓΑ Yh0b,!Gmz@7c7:N4f.*HքDv'̆bfCdʿt-e?^r4qN3s #?[Jv*x>Rٛygm_|Y]Dز(Uʾ})ďد֡:<CNaܴ UDgW$/>ys]DN8endstream endobj 61 0 obj << /Filter /FlateDecode /Length 312 >> stream x]n@D{? fזmE((| }fv҃=nFCu<2ϴØ%]SyNc.6uُq}gtsQ_gN%pids?>].ߩ8`a"߫8պ1*LTd09FC ņˍ/ƨ0Qw WFQQ# MQ(ޱ3 9¯гg/ ¼y#(+#GPWFPAa_Ӌy6ynx[WlܛsiiS%TߢQendstream endobj 62 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2669 >> stream xWyxefڊnvIqxQV\a="GBk6=ҤIs_i&i+imZZ 4 ][}tQY]gu=XG_{GxD4\ZDK-̙\pՕ+!)cw%LFIYX[QX7wb1A ItOv˹yſ]E&Jۈ3JbXC%g D'&v"CaP܋qwŏOȏS$!Q rDCb8Sɶй1d"=; KM*VWe0;^wʸڇQ2ژ#ˣyMPeRzj+h)MmD?cQ4:TP&̯D=tˇ{O=TG+܃{ܨ)S6^Q pc HR:, Ϩ_1\P UPC:V_Q,nUmЇ݇u(㡗ODZ0u4#kOPJ#[3j_&Aͬ ( [>yT[GHu 2u@;h432EGUlVI Q| (~{`v\j^w |<)==ChxH΢l,NF/bmtdG$fhL;zD-;?ynuJa:þЀgԏ(ц Z8l] jVK[u(y7] ~Clrޖv,܎'A;~~ϩWhULJw%o-?Ŧ(Dq92tS!M6U)ʀշ;\ ܏y)dV{2ML811ߏn~oCn7c״gGн<})ҏxrys@G.Z#[W*DAp'"Z8wl.>k&١|k?GwnB $Ҳ PR]7ML.ie/IaZTPPOs]WbNwbfs(w/} @? ӜoJj_Mg3=,Ar^Z:u qE H?q+X,-L< o7<!Ď3x>ܚ.c/`G{5d_]Qp1o ._cz=TZG*8a[|A޿ 0Zt 6G DZV9,~ nsNfJzo{yutM&{ *ڻ:B}uX<>\}tű[8^TMtPst`zMgގ>F&Mra5ԀbX`VJ*nѼ_`ΣNY%E\:ߚLqM2lbiUFZBii5u.o4xzˍԳi۲U .aK1'_тFD館ķkDLPmTU u9y2RO9tYOsD+6s\luBLG'C}n3DUn Z zjZ,FY2 ǿE t=Y#rI2 {nčDsR^C#|QW(}ip3[o+v#^rCt.f-Y Blֆp2?-umh{߿@0|*撩FDջhA$sj`~*e{>mϔ$d n6tT>G`Z揵#DvdOF^Ya m TJ()T**(3f@r} &AO8F|tWoʋ@"ɓ&#Y3V3E2: ȩ'OѼ1/=݇v @C#h B #&h GPUeZ"RRSa$<~:)tZI"PuH旗?&Nh`rqKY37\@@da=Z3}:uIU:XK_M9Zk>p\ԋsgj`<hne~ :W9p/ʝrׂ(B)Sj&%N+WC5瀲rXnMA9A^!Y> stream x}TyPWaو me] I0ĕ<6bx"3rs p @e`A.ZQlv]n:vEjS=GU}OF(<L%2RoI_oBS<y+FQ0o+>SRӳ'\eB^ ~Fl'#v{b& EbBIG"o _lO(oBeM;ysE¢*r5i (}^cj6 =/-.䒍OBդ\HtS=1=y hvM-zGƍ;n1uꍛW} ]0p}"fM| ln7K,Y]Ebb?Ib'kxl2s&``Qkǽ򝭿ci:\wG9~ǟ\ڸV\P銗X@$F`f1-+Zz5òuIH;x(RA-iY hr Izb@TQtx=nfq`$pra3Pk>-w)D&4z V"lp]oStPA/j۸px;/ݲ |O"#!$%njl g9Ӂ$ zQPF̔aȊפ G)Ɛ׿T$sDEmHeךsD!t>_?#5xDa`pteOuV}Q;d<ᵰvB#69igK&$&K22جũht6d[ :O?Z} `saKkcDh<ò!sѷ i[Wf.j=pP'Kif"B`dvb6V` ӈwz$tAa)W>m>U9(Q6iJyIK139+yo! xqh\+2¿V"9f\s&uST2ӯ,`3˪+F(wu;ڷT'!*Kt@ i),<РOJcQ+Q + G ə-ԍQs$j`e,Ô8Iq)I=3,™)Y&"gZ7&a*Mn~IqYn2P[)qPJp3>K&A-yuǰBWDj HLȔOq$e"xc7Qvkt. .=o[[~X0v÷7pןL 2}τ-A[Oߚ7C3fUaO,cl~5]Stù ]XÎn97[w.:x&P+K/DW &9c;[JatOI5L0(5OhgX9l킋'[;жbG9=(zqcx&Lm{:cZ4R`)'0êJQdB|KZN*f#%Jh1~b \aЉ†ϵ. ʐnL8QX_́bWP$nl^4)Xjh2hȒ:1ϑd+ɲٟG_ @٨#m:q5Z"ꘐ }.~p/4DiJR qqfVl6q t\g9"^ʔ\jI?'Jū)j^Ѭv:VOiiFptljrRJdbs 3KPeh:|<%45tkLkKy*MaX-kr6x_= y{!fi>퍼} ߤ4OMendstream endobj 64 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 138 >> stream xcd`ab`ddM,pI-Lu JM/I, 154w!s|nnل&  L,2~(X#Qwbb#&Jendstream endobj 65 0 obj << /Filter /FlateDecode /Length 4584 >> stream xZrܶ10&}n~$.o(u떳Fd4T8٪ڷg #ɶFCh>39/_\~`*f)7SEa3W̊JgʸY>[YU6fZgFeevhڹL*\d=&וSSkoʙqTEVX/^\7ǿ:q3'sSД0JJJS2Ts*Ǣ`Tyv-IJi|IiW~F&Sv f=8_iaJ;Q\?RgG$y8+)3L-3p#`N~S5~Ufh׽\"Q9/YUM;o_V/'7Cs_ :ROY</j|4Nfx|'}_K9D`baώ>ZO'+|7'p|ue\pa%cxaԺ;VbĿ+\f2:[5=;DOGز75[ɬ})Kgyi_6/‰YyU=[5T+7æ_p\.Fɂt{}D*r*R/ 2TZoK/bUYqDq+9 ?pJPt[;rJXחWrV6'M$YxvY[yVڦ]AouEA7*rĬJĢ6kgv S fR F}{ޮw"zv,0Jpevb4mBVgE $mi JyѦB7y)>?7>ʻ% +Fz #1YZ ē[%C&SaJtjѬv*1tq/ES/b7\nO)(!WM7-4: ];KK_-4^KJj QD?c3ADw_63%vr%Fy:H 9̥ 4CI ޳ ^*Z$Lj׃YJ.B͑ج7ryC/vXnNUeVqE"QR`"J;\ÔN0,k[,d,ONOUe*Lo*s[tu{v+!l[i2\rX6ز;VvWb1$E]}S_FkTQfɲ8TX^8nkYqe?U:_? _VC^zNn7MHvu:+5:J'@XI^w!) l8CxG)`7M?dDL]esRIgJgUh;{hUv96>ZC|39'&Lu?D,IF={?rla% 5WA`wp3SD[Rls[I¹9ao~ߴ?+1zSX`a2.2N|^ǯ0Ut=PU&eZOF3J%rp5]SU:_)vᣌ%E6#MuKrk$^rH*xQ躬&C7?~޲ œ;ĈbA'h;/.ʲ9ql [PHU]#Dp u|tb A\5=4wSc}\*6݊ ~mYYWC;zUBO-xhډ2 2wS|x5I$8qM>8iwcy?31Fx޾ٗ'Hc+UÙys j|dIE=qCg4gБHq?_t )/TÑggU h>\ԛ^7b@L) Z'< ;{'btDߥGB~D[KL^-[ ~7є:Ԃa:?r?4bݗuckf< {hv+׉zfki|]x'RnW0Fޫ\[[0EHy3 tEg]B@QYG(ѦDFF]I. 1$ǥBFDwt^swEzz0Wsd8Z7x߄A.8(]}U*Ζ]=n6Q!W,S|K =Hcu#&Hm6X6pu{]d ųi{ޱ:E Cy5yڽ؞nhܚN MqO;QŧG `Ӗ)PKFKS{Qw2ᣪ`Ve-λ?$)Um[cct:`x4ފ`tۀ9$39yL(To]xrfFWU *rljXW|IPTU3 VNꚎ c&5¼LshPIh}-5 Jki:+Zիn"iTLLP*8XPgjz˭RCO|WԯR}'} KhgQ;ˊO!tմj eU,o>/:YV[|.//n(|w \]\]zKUPJcq~eFyke'U LDOyDޗT,󇡙}X,Lf` iWaKaaߥf-PرİaȘ1!}mB]As{{P@nB -Z2R\.PX|"&vD<v]'X0]f\ՆBTe-ތ_(D8^V'^:*lpɬf@%m"t TG̱H(]d:m POo>їMzTi㡽pᢋ%Q2F,=7{ͩM< #8LlNw@*H'sR+h_֡bes!"Yn.'TS/j6Pbx^vŠ_:}N™語iJ.GyMxU|ZO% x(5Y ,MSaLͅ %*tUQAA(CHƀȬMaHaax4L'/@&@[foNY-2: Cћ T^Љ==yż¤mr+k 8L ^30Ķ-,̬xY/K ƻjd9Q!IRÜ\-ξңNȫŠ ;#n&^`".eb1V@t G)ݔdg\P/.vٻs̍3<&rtx9E=gŏs{Re>J tQ$}1BNYv$tԑ^upj&M d]w辂6<txnWId|(F"!JY܋|"_s$RsZԫp8۱Ge"E|nS?"􁺛8=WkIa{nk/8&~sz\?z1óo34)MH_nkEtHעm,0<Ǧ\6XG"ZP}9@›"[nYPG6HH#ݫSI aobbt C0}(Mu( ]VRef[-`iliB1 =xr 50M?NGs*M `PGQ C $VSxb0k&n^74> stream xMViTaU$ E\APvdvQ;(6 l!aE1 BԀKB9bГt}Qj%2K&Aξ32M>h}yEm[j~̵h#  6qu1 su3w8ieO9ZHYPl6ZFQj9eDVRƔ E}CL)3ʜң4/:O&Fu-/ԇiM:. YB#S%v#eܬ5V̳;xUh)ُp+<#kK5o?4QوKdZ\9O6>pB̟.3Q=-Ԋz)j=L8-lů#N39K Y6؊Y#c(e Eis^>ČAgY[+x\ѭ w?׵Lw1z8[R#T3O,<"=J|\#Mv ~*Rh^ݫp [K q>W#;zh7V, u+?CU^rY8`o+0QfR.#hcG,:b r3]x,vشlR;,vMk 7𢮻Q+樥/.4EȀtrj*`ംCO Bڂ6d7~DKVmvZ:!  YA[gڷ_#qO\%<[(K,ϸey1[pjPʸi1]R#t!L+:["U&KbN%EgXohm˫`*_^ ̋y r-T4-ϩV1hŋhC&Ҙg6N3I1+!HNƟ"?Gf&R%#`f`;y+$L"S;ւڳ,L!ALGe=Jӑ?-iȕ;ǒ*~̤.*i֕I3)Hs /ºαv~6pYu匜jx.eG[2!,,0lj`-}+ *%9[u^֘C0M!Etz17}>kӿ3hrxޅ9q>r'IP>7!* !z10"u_Dztap02|e cv:)-kmj80 ~qΎ!ģ?g9 ^N_pz(e-:'2 V5 qJ-=G7 Z+,,ʰK}/XJw1r0p%{Iy~VNv@gq.¡k-~7c;/s`:)u^|wrlQTYO̯b`WJ/qtfz~3[UdQ*Q13A8l s/Cs ى9tRbdR V[CWa|x imqHCi.tGBNhmT> stream xe{LWgea)bjb QEd)T"WDvQ, ]WAVʨBb)4ZӜ1"h7'Q 3J&MS1jB챇kJ2Og6өqSwsvqcEQT KPK͠fRP,ʁSRP>Tl,QvL'_*-AҌ2d&8kj@0qOfhGG*UkU=#zzt l/ dǦzghI_L+@XQ|YH\ ͋ /p",'ʑjUmb8`OCVx  B[Al,@-\B'Jh|͇Wh2Ni%SNK֙'Vph&:JS__UU?AID aԥxÁj.sB#ė;0/_#6s00<}H,P& C*\WڈG2E!ڨ3Sh~|u%GW7 h]uÂmVh><q5gpUX>ADCvt:Z XOl.\湄gxL'gkSe M13:0?'{#'2p}D!6(6mk15B$k9ݽ؆1݄&SA⎯98;؞-HY9Չ1qn˓'oEji %brϖ˨P6@ j2_lwDZz8O*,pQ[T獃oYzg;RckNk[t .ez00'$ċtSZ$ 2@'t̄aM""kpe<_E>$Ia z5VGp;( œ||y3 aMP*=v 9ȧû ̠tӖX=ZIXq,g 3GF~Gp XWP˭oڿkבK*w:M>RnT [! (zK4"vqtXtvZu .*WN j7 w Yx燷yA2rܕ]]+T{> /W [ 1 2 1 ] /Info 3 0 R /Root 2 0 R /Size 69 /ID [<3c5e46efcbe2a67bb409f42146a7b9a2>] >> stream xcb&F~ cIބ L l{>* $@b1@Ī"@Hp!Hi v# endstream endobj startxref 51505 %%EOF RcppAnnoy/R/0000755000176200001440000000000014105564652012374 5ustar liggesusersRcppAnnoy/R/version.R0000644000176200001440000000107113766143727014213 0ustar liggesusers#' Get the Annoy library version #' #' Get the version of the Annoy C++ library that RcppAnnoy was compiled with. #' #' @param compact Logical scalar indicating whether a compact #' \code{\link{package_version}} should be returned. #' #' @return An integer vector containing the major, minor and patch version numbers; #' or if \code{compact=TRUE}, a \code{\link{package_version}} object. #' #' @author Aaron Lun getAnnoyVersion <- function(compact=FALSE) { v <- .annoy_version() if (compact) as.package_version(paste(unname(v), collapse = ".")) else v } RcppAnnoy/R/RcppExports.R0000644000176200001440000000106413766143621015012 0ustar liggesusers# Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 #' Report CPU Architecture and Compiler #' #' @return A constant direct created at compile-time describing #' the extent of AVX instructions (512 bit, 128 bit, or none) #' and compiler use where currently recognised are MSC (unlikely #' for R), GCC, Clang, or \sQuote{other}. getArchictectureStatus <- function() { .Call(`_RcppAnnoy_getArchictectureStatus`) } .annoy_version <- function() { .Call(`_RcppAnnoy_annoy_version`) } RcppAnnoy/R/annoy.R0000644000176200001440000001347613562654026013657 0ustar liggesusers#' @name AnnoyIndex #' #' @aliases #' AnnoyEuclidean Rcpp_AnnoyEuclidean-class Rcpp_AnnoyEuclidean #' AnnoyAngular Rcpp_AnnoyAngular-class Rcpp_AnnoyAngular #' AnnoyManhattan Rcpp_AnnoyManhattan-class Rcpp_AnnoyManhattan #' AnnoyHamming Rcpp_AnnoyHamming-class Rcpp_AnnoyHamming #' #' @title Approximate Nearest Neighbors with Annoy #' #' @description #' Annoy is a small library written to provide fast and memory-efficient #' nearest neighbor lookup from a possibly static index which can be #' shared across processes. #' #' @section Usage: #' \preformatted{ #' a <- new(AnnoyEuclidean, vectorsz) #' #' a$setSeed(0) #' a$setVerbose(0) #' #' a$addItem(i, dv) #' #' a$getNItems() #' #' a$getItemsVector(i) #' a$getDistance(i, j) #' #' a$build(n_trees) #' #' a$getNNsByItem(i, n) #' a$getNNsByItemList(i, n, search_k, include_distances) #' #' a$getNNsByVector(v, n) #' a$getNNsByVectorList(v, n, search_k, include_distances) #' #' a$save(fn) #' a$load(fn) #' a$unload() #' } #' #' @section Details: #' #' \code{new(Class, vectorsz)} #' Create a new Annoy instance of type \code{Class} where \code{Class} #' is on of the following: #' \code{AnnoyEuclidean}, #' \code{AnnoyAngular}, #' \code{AnnoyManhattan}, #' \code{AnnoyHamming}. #' \code{vectorsz} denotes the length of the vectors that the Annoy instance #' will be indexing. #' #' \code{$addItem(i, v)} #' Adds item \code{i} (any nonnegative integer) with vector \code{v}. #' Note that it will allocate memory for \code{max(i) + 1} items. #' #' \code{$build(n_trees)} #' Builds a forest of \code{n_trees} trees. #' More trees gives higher precision when querying. #' After calling \code{build}, no more items can be added. #' #' \code{$save(fn)} #' Saves the index to disk as filename \code{fn}. #' After saving, no more items can be added. #' #' \code{$load(fn)} #' Loads (mmaps) an index from filename \code{fn} on disk. #' #' \code{$unload()} #' Unloads index. #' #' \code{$getDistance(i, j)} #' Returns the distance between items \code{i} and \code{j} #' #' \code{$getNNsByItem(i, n)} #' Returns the \code{n} closest items as an integer vector of indices. #' #' \code{$getNNsByVector(v, n)} #' Same as \code{$getNNsByItem}, but queries by vector \code{v} rather than #' index \code{i}. #' #' \code{$getNNsByItemList(i, n, search_k = -1, include_distances = FALSE)} #' Returns the n closest items to item \code{i} as a list. #' During the query it will inspect up to \code{search_k} nodes which #' defaults to \code{n_trees * n} if not provided. #' \code{search_k} gives you a run-time tradeoff between better accuracy and #' speed. #' If you set \code{include_distances} to \code{TRUE}, #' it will return a length 2 list with elements \code{"item"} & #' \code{"distance"}. #' The \code{"item"} element contains the \code{n} closest items as an integer #' vector of indices. #' The optional \code{"distance"} element contains the corresponding distances #' to \code{"item"} as a numeric vector. #' #' \code{$getNNsByVectorList(i, n, search_k = -1, include_distances = FALSE)} #' Same as \code{$getNNsByItemList}, but queries by vector \code{v} rather than #' index \code{i} #' #' \code{$getItemsVector(i)} #' Returns the vector for item \code{i} that was previously added. #' #' \code{$getNItems()} #' Returns the number of items in the index. #' #' \code{$setVerbose()} #' If \code{1} then messages will be printed during processing. #' If \code{0} then messages will be suppressed during processing. #' #' \code{$setSeed()} #' Set random seed for annoy (integer). #' #' @examples #' library(RcppAnnoy) #' #' # BUILDING ANNOY INDEX --------------------------------------------------------- #' vector_size <- 10 #' a <- new(AnnoyEuclidean, vector_size) #' #' a$setSeed(42) #' #' # Turn on verbose status messages (0 to turn off) #' a$setVerbose(1) #' #' # Load 100 random vectors into index #' for (i in 1:100) a$addItem(i - 1, runif(vector_size)) # Annoy uses zero indexing #' #' # Display number of items in index #' a$getNItems() #' #' # Retrieve item at postition 0 in index #' a$getItemsVector(0) #' #' # Calculate distance between items at postitions 0 & 1 in index #' a$getDistance(0, 1) #' #' # Build forest with 50 trees #' a$build(50) #' #' #' # PERFORMING ANNOY SEARCH ------------------------------------------------------ #' #' # Retrieve 5 nearest neighbors to item 0 #' # Returned as integer vector of indices #' a$getNNsByItem(0, 5) #' #' # Retrieve 5 nearest neighbors to item 0 #' # search_k = -1 will invoke default search_k value of n_trees * n #' # Return results as list with an element for distance #' a$getNNsByItemList(0, 5, -1, TRUE) #' #' # Retrieve 5 nearest neighbors to item 0 #' # search_k = -1 will invoke default search_k value of n_trees * n #' # Return results as list without an element for distance #' a$getNNsByItemList(0, 5, -1, FALSE) #' #' #' v <- runif(vector_size) #' # Retrieve 5 nearest neighbors to vector v #' # Returned as integer vector of indices #' a$getNNsByVector(v, 5) #' #' # Retrieve 5 nearest neighbors to vector v #' # search_k = -1 will invoke default search_k value of n_trees * n #' # Return results as list with an element for distance #' a$getNNsByVectorList(v, 5, -1, TRUE) #' #' # Retrieve 5 nearest neighbors to vector v #' # search_k = -1 will invoke default search_k value of n_trees * n #' # Return results as list with an element for distance #' a$getNNsByVectorList(v, 5, -1, TRUE) #' #' #' # SAVING/LOADING ANNOY INDEX --------------------------------------------------- #' #' # Create a tempfile, replace with a local file to keep #' treefile <- tempfile(pattern="annoy", fileext="tree") #' #' # Save annoy tree to disk #' a$save(treefile) #' #' # Load annoy tree from disk #' a$load(treefile) #' #' # Unload index from memory #' a$unload() NULL ## ensure module gets loaded loadModule("AnnoyAngular", TRUE) loadModule("AnnoyEuclidean", TRUE) loadModule("AnnoyManhattan", TRUE) loadModule("AnnoyHamming", TRUE) RcppAnnoy/MD50000644000176200001440000000442614553747041012513 0ustar liggesusers562d31d6b7afed7b18f4e0f6fc787601 *ChangeLog 348dee3cdb5be7cd1131518ed5ec9b8e *DESCRIPTION dae4f8ca1beeb667ee6121de3c975d2c *NAMESPACE 7ae968c5de1e6252a2c1ab5a6568517d *R/RcppExports.R 93628a741e3dac462131c3053319c589 *R/annoy.R 4d86ce7f605efd09238d1259c3edf71b *R/version.R 4b05c33b6f9ddb26a37eae6d3c825c49 *README.md d775f6fe3437484978ff0bd03585d7ec *build/vignette.rds febc42ec3b6fd6c342a9fd8d38f20cd0 *cleanup f6f2db8ee77cb1083ce50ea2ce613ca8 *demo/00Index 626d1ee412f1f366f860e2fa1b7e15a1 *demo/simpleExample.R dd203af48e7b8ed052a482301f921ba2 *inst/NEWS.Rd 568dcf938bfd545c06324d487888e301 *inst/doc/UsingAnnoyInCppWrapper.Rnw d44f9640a57cb8e901ceec573b9abfdd *inst/doc/UsingAnnoyInCppWrapper.pdf 69a50a3206497e6cd55e1571e39e4925 *inst/include/RcppAnnoy.h 1fc7d61f9386cf81b7e7be80ab27dd4a *inst/include/annoylib.h d71f69b770dcc346f36da24381e45814 *inst/include/kissrandom.h bb5e4ec24ecaed6c71be0d76836eedba *inst/include/mman.h 816cc1ac0aef382762f8a536d8037756 *inst/rmd/UsingAnnoyInCpp.Rmd e77d053b7f11b37333a71c8da8bdaf4c *inst/rmd/rcppannoy.bib 14c740fb1a1c4d78afc7d3b76641d9e6 *inst/tinytest/data/test.tree 4bb99f63e5ba7c7ae5b730625cf8e2eb *inst/tinytest/testAngular.R 56f9fece1ea637c58c269f6b530712b5 *inst/tinytest/testEuclidean.R 1ec108d7dc0af03ced95ccf131c6daf0 *inst/tinytest/testHamming.R 7d8dae4a58700885f9f424d9f38c63aa *inst/tinytest/testIndex.R bfc5aa0efdfe1fde02cc8fdb51e6b447 *inst/tinytest/testManhattan.R 15e6bfe848de489a6e6e0b972980c159 *inst/tinytest/testOnDiskBuild.R c31e274a819e1b945f2fcef39c3e9d51 *inst/tinytest/testSeeds.R ebb89d9c7e2a0af6a3ca60edfd328a54 *inst/tinytest/testVignette.R f44f93b08b6248788fc2f6c52b36c90c *man/AnnoyIndex.Rd cbe66b243d9b4737c44ce13d427c2554 *man/RcppAnnoy-package.Rd 5ac2065ddceaf546aa75a251678ac58e *man/getAnnoyVersion.Rd eb1a07c50cc3ab66aad1f84abf7cd18c *man/getArchictectureStatus.Rd 17901f6a75ae9de82d24efabc4dab9dc *src/Makevars 946690d41f51e14187ae75f2895c2c68 *src/RcppExports.cpp 3eec41105eeb3e919c13a85a2c63bf17 *src/annoy.cpp f61d5764f4ba6cf6e90127398a30e7be *src/arch.cpp cbdf0205d2d47c8249c7ff1cd7d1e7dc *src/init.c 95527d46e099ce463e3654a399b64b6f *src/version.cpp c473b8f4e7d47b1b87cd6fa570f096c3 *tests/tinytest.R 80a81a5fefb7724c2e830238a80dfa18 *vignettes/UsingAnnoyInCpp.pdf 568dcf938bfd545c06324d487888e301 *vignettes/UsingAnnoyInCppWrapper.Rnw RcppAnnoy/inst/0000755000176200001440000000000014553606145013151 5ustar liggesusersRcppAnnoy/inst/doc/0000755000176200001440000000000014553606145013716 5ustar liggesusersRcppAnnoy/inst/doc/UsingAnnoyInCppWrapper.Rnw0000644000176200001440000000042514442705672020776 0ustar liggesusers\documentclass{article} \usepackage{pdfpages} %\VignetteIndexEntry{Using Annoy in C++} %\VignetteKeywords{Rcpp, Annoy, R, Cpp, Approximate Nearest Neighbours} %\VignettePackage{RcppAnnoy} \begin{document} \includepdf[pages=-, fitpaper=true]{UsingAnnoyInCpp.pdf} \end{document}RcppAnnoy/inst/doc/UsingAnnoyInCppWrapper.pdf0000644000176200001440000014372014553606145021005 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 2696 /Filter /FlateDecode /N 39 /First 299 >> stream xZr8}߯d*F5*Jxf*˜DG2~v$EL9~bQ[8Ѡ H8!AOdI@ᓐD!܄+!gP*DxaD*h{DF<+I|> ^ Q 0`DpKx.@ tB$ G9G:"8 qI@=1PH@y[䣐DdBS hEpy0fo:y)VPj-a3Ǐe52'0.U:9I/N@Coe*E:3mjw'xqwΧrN/r%'*Ҋp\V(r} P^cL{Pf2]~RzrBρJa0(*ψZ+g\އw:ݗ0!@>=4:hBK0_g4?8Ԟ'x! ͼ1A̓d%.NB0,/gs (2Xf,eAME-9)ʅvAmrVNQU Dvb_Xi߬x߁FNfؚӔK~u,X8i7b*ė9UtP=s|05n; =9Kz\L"6i;z;Б@{C9]*Ktҫ$ZVW4Jk5N^ !-"IᛴڴcVԗCo'"xGGgqbs:xY'^iD*N] c A~ BKD|ϼB"2T~( 6p ͿD ,4xR^^?.T!SM$<ȃPҁ.;m&= :,HVcczJG^xEo INUl`=0EgrZo4۹)P>2&-|.ݥCwɍUj]G|^2+:|?0M]͌l=ԓc.eBuЈH㠕_Lk27)Kq[/@?f V-cC̖5L&]W@]1CSS~-k1+iwf.NGx?.d T/W&kQ3%x1m%9!C=T1^Sp)[ **".|n;/OhBe6C!hlܼ 2箞(2Z5^Z-uYwWݰAnP=km#!fG"mmP}W{Ӛq!\.+0wV%x(F<*_Mr*e= ބG6p.T"uʺmkr_x sԵ*iEvѝ=31e4J",:/VުuTj^N*+m+,6$k9U0Ѡ 7(1[a _xġ꺐3xP6sᵉ!^zLY'^*vQj/f'T}cNL F Xse ̌)Cz\3n_l`Sփ&eE}8h6f<~WttvL'ݸvOi!za禧զM߻PMT,^N*hMjd'LQ(*L[ o /T`TQͼ="l}{\sD؇kE㋓ף8:wػ{.ұ03`}aM}YxX_a2/CFs4dR*UR1ֱDX]Wm/Ll.ʴTt@_#>Ŧ?e]0BiU14\R.E*gXV~3ߏ8mv Sv~6ssFݿloڡ'OAuV~~27O9P~"WNSaCUNw^ O$_}:.l@];^>Œwެ|Wfk[m(nL`OW쬭o+T =Z(Kq9sX:ܾ~9A.fN&f6Z,[e8[{ih į͇|U\㐰InN_;%3endstream endobj 41 0 obj << /Subtype /XML /Type /Metadata /Length 1168 >> stream 2024-01-22T18:46:29-06:00 2024-01-22T18:46:29-06:00 TeX Untitled endstream endobj 42 0 obj << /Filter /FlateDecode /Length 7289 >> stream x=kqUҏ`9FG NdI>mrݥTX _ZIgܽ% ~w(K(?H. ?+eBJ|\|`.F_]^|8K /vF0j3j!Gɿ'0\IBkr MJnhfKccƋ7Ȳ_*-X0l'_.5uZ2YS޼$M/(x%'_%7 q$Y$f?*a^~?\|}y #52XiS9>B~Y6c@ɋ:XDzuy̌T*@rm?T[H cv, 恄 x9kBdFD h0a)nAqA2!u969Y XzAf<yl۬^6 +U@iXkM&u<7/|XN =vח`$$vQ 3M,x԰>o^+#Qd_ewI!R@wΦ/[/߃̽\O%T`쳍sO %ך{‚ccPyto |6G-`侞H̫_IyWj~ta :K=Q/ )I; z,IK!ԩ5:zҡ c1f/3.R)Ğ3时p,K{1jIHp:~DjX˕WR,)gzX,Iq -`1[B&`^{mVm|ǚ-I!Yj$DauzޘϳN#=&og}x@Ɛ<~1u4z ƿWV (EzX|Ux(vlIA1~bF;CctQpΜ1K+2` )<[k1F1L*;u$ ˥ (q)(} iAs] n(ͪu.A[Oj+z܌ iKP 'uN#luNu5?zݖHuELWpxaIl$ܽC1I4ևBtȁ&w2hl݀9 b&}۬7k Hɛ__,C.rBlWs[zzC|+ghb&V~:Ȝxg4ya[B3(fSOq;; R4Pj;.YJehEX}D5-7J2L=]إy >jKԇ~,) c7* ً2C52f:?8Ղ); `cr)LKohikc8E\dz ˾ZV4WpHd9 eF\J̈aSS:Z"9` qq ]Lɧ&Xj=;*=U&~~ tt2(U.) 47yMZJƣq..nٙ/`" ڙ~Ḗ<,X_)QDH,}Y96 ,B.R _!}U?wamp%*pp\^Gܦ9n7Y}}]5 &chPPd.όm.*Evgu),MSOmB_ h*B/~M^nVM D- #sġ(B^i]9d-wmemctDB7֖Sˮe"&oW5M1ƫjs_Uf Ta qJ][l_!XN'KINoګ YX<5&^Oz^O:h_%ɫkdaxɝCI MkӪd\"-׵mn;pN0XDBAk8kfG,h#SNzuV]`8O ب{o{ #6H8+GƲ,t|OG Ĥp-phe]<4hWUMu.P:;Lhpgp)mR#@L]1}kv$ xAavsf8_ Ǻm|cAJZh3(Ul6y]-=d<~T6Gcغ?=M'FO4گǮf ɸ<Wп޹UxiS,7LAŔNZj!T6=osK3^8 LX.o^!Uvmpt=N⒏ EQmF :zqbsQ!|)৸Vv֢W&ys4Nk 3Ⴇ-Pz+$ :;ּD |>.a%VM}S Fܮ|L 4‚.r.dC9ǺZG vY c#?̂.L%^=NStuSk#N}G$mC958 HP I)H9Ww]N8%w>^zALc܆?RGKF8URKn| 2+օek* |Ƙܢ*eӹ w*i1f+mfGތ1UH'K޼]kzoպ+>]hd݀w껂f;kYpWMw`vG ˢ`ǃTu;:O 5 u3;<5Q~x=?K4z`?-g|WR֛9Z#7bK`Q:ЛxudhXY<Du/LVF\]|C];>Y`ŋ;~(ft^r9xv)4X*LcouC;xf&39$VA9XNT,7\MLG V\Nhhp4чwN7ti=0t`(l`xC.M`,)7J+\aQLtOu#<\t-g,ǃ&m8dvN{ΧAx]VQA~=xS,S S:QA ^oC0[9j^B nY5@ uѕwyQW~әkfْA = Ru2{=;x?w۔p̰7?՟ 27W0<ʸ60ypuxru?t硟֟\ON >O` -ɩzxAd%}eFq;L {8Ch/}I̖Ae&sO Ʃ<*#%n<ޅ_I/W hu =Zzʻńz&x>THtH~*d<|'_0G<8v6ZƢ/]þ45fs8F=#mv14j蝐?}SoC޲A bSLxs~pЧLxR7R~tܼMYrFe]'|56zäBآ7 YG wt_ o|<$Y> stream xeUiPgau)0F ha,ɮ1ZH%7#1 3s\FYfƍ2UVb Fwm8ck_]~易(Bv݆$MAwWI~$yktPBO(*u<]kv+H*IIݙ1Q1zjKQ+**VSk-ʨak~)(CϥER~6R1bDڮUF`KO3ւI}` \7}:T*}2.á= !VhI!$`F_{!m+y#Og0tzd: LKS>0 d2[[r 쾪vÅJlKJݱ6`3ՠseMc3%].f`.`g< E?Nĥ^A4r=2[oܵ+4@UXaPm3Ȗ(/-7ԔPeF3 î/y/d=>H9(HwҰV-}rl[Pe&oXІs?$x`ݐo,c__lҙ!Y ! thL*ۣE#Ⓓ p/ R{Yʪ7GӸs5\ p.y:ʡh-mc,Q?xOyuU:aq䆱qԨ(SbА3兊]MhN CpCV+(OE^̖KNzݽ퍻F 7b^zC=*m@k/qRna=8Պ"8CkK`dr0.~=Q554665DAps40gƏ*KQ48ӡl"G>*](Q9P.p'%Ak%*}"$%ţ8 V> stream xWiTYDq3JTPPâ (0(JD1 *@!%n>}$c0IMr^5c| ϩwނ (D]7g:6\7%~,؇?cgƹgrWIX+14iQWƪF9h7n{GRC)_j5NQ#(j"ʅZL͢R+F))wʃ)/ʁH͡)ʌRQ(5՛RKTʎ2fP@Ϥ5 c ^2|f4(d$A%yf2a!9!cxBc}` <*SӅfb̼;i@R -|-!;VIXFx>TJ@L4`\uZ:n;T3[?Y0lŬKહarV Ob#dZ<[8poO:+gg%5t;ZN&>_r@t!~yEvQ4 b)L6nˆ8;2XjNeϊvgЧ,2<'`a[Lpz4̄#Xw\P p1}Qw+/}l !7o;r)x3'ꂩ lä.#?_=LG0t&9D?);#0q\^1}@Msrnq`##/("/zB((.z.&jQJ[P۷m =|%T2`ڋA A`f^[`{[[,Ă3Da. B ɴEP|VW?<| cghBU.l{GEPW}@!i6Hm2'Hu> Z?!C-𻀱o 0`l:EAR^ڥ05 OIo<^loopBܪcP=j:Z.Iݏp嚺fI{x~L1? c+<\i׆3΅(+ڳHݴ+=#qikPќ2z%UߔJgb[ީ;T%͚CtifnmSC;K3CY!=U1{♯X}˙!PZXYخ|S '5C_8^t-\z$܌]9.v$-]6N5GlOKvM  1$;Nloh,SSl+ /)\Xn Tȉ?2Cs*Tg?"q|ud 2~eĨE.-9mc_n!!-GsgK͕$݄8ڈ⥇"%Z@;R_JTU=ʃ<`nنR36+2P2JA{Dq08p(0*+wzX^݈kQ1'sɱuzʐ0ɞA;7o̎G(*U~MCSNE$?}́VHȼ0#0Pha¯^l<Y05ydl%WaZKIZ51n3IS~>d_0| #ׄ+0sĪ0\wzE`P"[I$VUc(BG0^1noipbbxs D홏ZZ= {}.5+&3O?٩OM-*jN c] kuLk|'dQغ`H3UCJ)M.kB)xaSELȋh0z^uck'J:C2l`c';Y*w V+9xK-z`~뚇 '!F\om IePHqqw?y ]4K&|GۊG5mjм@冧їC[Z''Q:j4bӧ7PRT~Bw8{X(i&^TvZGlNx"Vd`au2[43G4އW4ɹ>ţvJLw7WN㰡Muރ6*hPvƱm5K{R;;3&[vzG SVߪ>~@0OqWQn X{ T#JyH'`0p4|o,LO&#lZ> stream xWgXTW>pQxXbX% R V "M4[4*M@z`AE[LH41}{s?f6kze J& sc@[l|7џ׳54Җ#mz_4~>\om͂o޸cnV֞6^ޫ}:|=6xfϝ7RdGYR)+ʚ&Rjj2eG}HSS(ʑZD9Q_PӨ5bʙZB͠R2j&eF͢S)sj2VRQ) j.5RjJFR j-ST0e@FQ)S Hܔp\f" =0V#Ѣ>*F;]1L7kΝl08jp!{;޻]7t䡷t|Өǰþ><] ]?zݟr:.wOᯏ=jDň(Yf*5 cIo3gcw`΃rI,hj:HWyQ-vgEнlh] =.?9y! ZpOS;R}B :iX7r'ڷSт*lo Wm†ۃߦ+Yu(C)QS&  &ãT~gټw@ ]X]ġ%AW=ݐXDV0+1]x0o0 |҃ګ?=}>LOLЉa4΅2ˤ|A7Vfעυ$#4_}&nse 4~|7f| fI_ʪؚ2bqw$#A(fӃyK/`!aD׊ͮΊjx&z ^')bV:6y⋮V8xxY3hgǔ﬏9M qʈmUG=8~QunaCі؈#IFGc5pEQ;mh q$n&Ϝ4Xϯ`Zueth*=$*Ø$j6yJ<{`B1:Ixu J?Hװ:hiqpncfvW5hRVq{KvVALmS_/W[Xv5pZF`~1]NCW> $%U8dM ^ amɱʎDNnx|X<'*fԒw|?8'߲U*eib})ȿ|iҀjF'BâCPHWݤ1Uo tq;ֆP(U> g؍~"_~ rì̸ 'lƮ -m6c{˓I0٬s$0OFE׫%=Q&1|#Q8 Їbq,}&6+b^}q=,!IWT<4B:oђcǐ0i ;לSsZůqJk!|]Wo選7`0~sEA]U:F?+/290-aEޫ5} ݕBzGkl/<$ō)dzK8+J^HO]-YjaPsX=5M-#f˞hrss>%`UHA? VI,0 )Lpy_~J'USW?}쟆g@M&>2)Af+`?7L8 >>GJK!$RA+Aj)mlR\#`JfˢK9Bcp[MB9tÐJujm]c.fT9^7uAyqlD2#4c*}f0Vm&B7n)ܙ w si ki: rgV$I|4c঒HLX]ƢaS.DE@AOaPUsw9q4I)ލ\ʄRG!byQy̟9y&O?ǦA6&$L/5K !CKLgӧ`:yTO~n `4Q؞D0][6lC< /wAn( mjÚwIJU.'v~B'ϣ[H!G; < VŸlB3Tr_czHngϸZ,s="h jȍ@V־[4߽J] 륉R\# nkF}f^}1˟̫L-uw^^Tl4Rm!TlsSW :el9]g`X_30[|s=^LC{\^`\,ӯ$@2DqZl /l6V<X#-H 9(%!80K8FG}iůCsnjt,Tȕm;kC%S< u_>}v1$Usoz+7bнç8~ tEEEվAAjOᘬT*";Db}+C#R#&-r_(~f [v&LO^a8~vz_1\!%"՛z]A&8*AuV [堂!ãhkyc~e;YWRJO]a:&#G SVSDNn~kw7_1$ d%Jyh!_..p}*\<D&DܩA(l]cowߚ݌'"nnHR:41Oio<þfKyHC\C}:EZ*tvLǭf~^2Y.E}Z{25~xR;;k.O+BAN׷ Su_W$4(B%*&OEE꣞*o-O?Bc^E^j^pS*"鼬?FI.`[h߸W$5k>Ț-h((<}HٛdxdEf5+}f64h6B_b#X[A$V2_eA,)LQ 9kendstream endobj 46 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3837 >> stream xmW X׶23*'"(`} y"AAUdV+JߠUA- P*"JV+ុ'}Me2c^Z׏26D"ѠֆƤNXSt;ud"F&h ArzOkfeZ"8!$qʤ’c9HL&&& 6g,լN꜐ JZC:иW!nZ\LĔCJ~~sҢ%찒~g_B#m筦׏be_ wk[#J&^armZhj|%FtЅ*V!H[XJG?2kƟ8X\Kkcr7:Ţ̴M L2:ZZnbR@魼C:phg[=50Fw}YڃwsoocKl8`q[VnVN*ƢaAsIF[!O׼C0肈)n$Niwof>%?v y_*NQoJ]SpV batFX.~DWm s?7Lx@ riKH;ٝvj-?L+~c gi 21pC9>b`s{g#}eݩY-JFJ(=w3Pᄈ}H+604 -_؍6cLy M΁jc*)5S\G;x ɮ Uq0H!We;##<Ɨɐ?Jօޅ> I6|A]mw\>#j'+RLtz3oDC {I0b ކPΛ,N Z`Xի~jܣXOt R|N -D|3ث`k'^}>=2)?$P^놐\ZZok%z^C'C[ bXϡWs/|=Xr,<0L:} I$V_=|0PNmH3}:뉘zUG/DJ+e55 ܸ,#e]E(,N6@7[N_{ǴRV]z3cpVU7[a.-RC}C6?@^j!7ٷk22l o[숳p+xp]'W R.*Y̤hdF>=N={O sA,b7q\XNqZ͑ϋ>vZޘ={DwTN_G(ArNy)^oeYn!x'4 nT쿼c%6sP3Җ7=.G{^Epμ 1+R|+7BQKYi3k]9/ZȽ`"g VZj Dvn.ؖJjAq? JBű^@{D=]C6\g]~-aB0/'LmCi:GԡA%RɗImŤQG7V${޿i=Euyi^zjzVrZ2 yM<"PaS(Jxs`_JP JCƲIq~o& ?J%.1"8_"2* a+c)8AيkeD܌Ռ#1*jX%B8׼{b׈a?_4&2s֟ԯD}=g7l'N.1_oFڛ1c/MD>7DojWw?zʉ:Ķ7̟?A̧OZ-xy.++H!6v_yAӸ%W?n_8xE n2G!]׾(K_=:qڏCtZ3fqdzGc(/\:vYي/k}IZpf/#ۢ/qdFhHʨSN"~:IR=[Jyg;28` $!ū^ {N{` ^\^*XsQV\Kv[yWgvo7SO+/< y[d +>=*..($_VҏP'nt2wqbc Oʤ N ػS/0 ȃ-WFFϞyK!tЉnwt4w4P! ac# nIDdNg#BzR{?xSLegb3A[(vYB HsV;?~ n.` 3"p7 m7endstream endobj 47 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1786 >> stream xMTiPTW}Mϭin"H*3a* fc# ͒qhe  J 6(,f@3j4P*^{qjS=(K J$ن3?/&-;}m4gt4h-4j6O.7'!WO۳3\;㳬u.@ER(*Sq@ST LmBpj!%2Rc"'QEqq^*&ƚcƭ99A pnF \ v}՜Ec_fWYrn#Xs87%`/OFiy>īؒ5QP$HL!1#9`8SiOJpKm42 6×,p==^U`܆s"xD ?:%K}1?6bZ!eȯEFzVsa裥[ 7.MlFG[*ς]yW EiI~Ծip':X .zt-#}لm T;;T9(\4N:;ZxL"s6K g/$ydv &93TѪ^pf8jh9fhkCݨsﱜJ̭Za6qxZ㞄mb?Q`KoG ,ۿ=ؖ{~{ÎEB@X&Į ѣ3O+z뀵\FsGvDh*n[tl\Ylqkv1t!)~H&ML?٩!a#URaO~8 7ko{?ϼ2K=Ev<%G$pn&2dt {Go]km j=hkLNX8G&NG|0ٞRrɛI֙e NmrkSڌեU% _/"Y+u <3pgm,~`}vMt\w]'4!$9mN0[$条{=8!_5%33vn3^;4SɑKῢq'G8v`^>gRa!'Y/=U=c={b%6>FeBpZDQrendstream endobj 48 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1699 >> stream xu{TT8{nezAACc1D ȣnQAZp8R"NlW)- g C>2pW谸 j4WNBiiy'#a l~2J8"*? qQ)+%PmQMQ wmX4;eT#q=yq:k VT**9DLR@V;;wrxLM C~bO6y~9 i6XXlh!:-,E<{ւǓ%mH$RveT[T؏2"KwdǤzy*hH6lL#SI8agOMmRA?T` ̭H'2MSeR)}9JsMnX,Fa"5o=VV^XP).A s}gG}ۄq$+hC QaكqI#o[J1~>͂;8\^ 4Ӡg7"2,6F7jiE))9{7oia`/2auWHJ(]|T;2\ʃwrz"OÊV;Hwt̛48:@_A}5iP,~6`r>#JqҕiRo,"}<_ܵ;%ũz^iv_x"r }Ofħv(ӳ'0/ =+1 kߎ7Kna; 萨ktg[Xa7XN,u8!zM _tu%tER^ K(#nbD̮uF4#iRj-|X 9 /k@endstream endobj 49 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2074 >> stream xMyTSg%Vb w7sEkǪjm]-(IXD@0, la [BB\,e2ue8g6.szfz>|{qq|71c;W{"dQ+*TXKkWyp鲙w .>!QHL=v"&V&xcb,ۏbA,;`^^a`NrVsNcwp1^sXEYOxIr3gsl:fx@3lE`^LP F"7sW98mnꔰjM(S@Քlk. -ݶ #tԠX>YbEc]{="8PdY?|6*:_:.SKwyYçaƩ<Á)aG;7~!5ğU4 i2Nf^TTdTRCwyaUahًVr!-!{qkf9dJv1P`c=$r;2_]PޡmPћ,`zO9*TR7߀`sبR!gs> { *!M4Zw筀uE55s%)p> E\A0ںRVs_4rf̠ ֓I@A bs[J!qҬ93$ SPixyOoXb|xPo:)<#$=ʒT`hLTV?HXaij jR[J}nM?BmU# BR)5L&19NCJ(xOQ]= WZSʓe)sS);/)(c|ؒm[Xgc&[{髌LߜhN6)mWʚFؿȳ9'y"P-75\ ÿYfTpfLC_إ6XI' F&n:|UT䏮W V@Yg:bwS&%(d5t~4\n'ÛVXCrrs(8 e[kq3{BMf8\xѿ g dxĠI_I ֜p]4zsMv0_@ I>lͅq=\̙\D fAo$$kMp0Vkwپ`߄Q1eXк!(*q][: [=MF.۬ %$d th]f%N_ U$endstream endobj 50 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4877 >> stream xXw\纞uQ,: 3cgl&QOX"h6d {o hHc_5գǓhr;~߽߲'.WyyGDY D"gg\1ozo_eЮPHQ;Ip1nqqm ,GXQϼ%rŖe!C•EDZfs.>~?SM1c9s{k$zr\=rS Lm6SKj5J9R)wj9.AfRٔ5ZMͥPQZjeI FRŔ5eC(Cxj(5),cȤ!CG(+veږ1LPMÆ f)chFL1⧑G"!֗m6ۜ_Ywtv:1[con= #j{"E XHla[CKaBybS|?Q|Bb[n Fu]RZZȏz*t4֣<^ XlMׁgetzx6[u.:zpՏQ "韶-:]mH+dmqG7'5v[WWq+d\aqTōƍuٴ%$dO(=T.x+U^=_U` >3EaTS/-A%ũ+׻"b^W7Ƀ>3Cu0US% Y}-Ós[Q4Ia _Tu)_Ǣ-LoZ\beJ1$ i n))i>;* >>_u0*6s X-Ui\1KPw-Q0[:\<>hp},@ /ܻ8~{W{\:._'/گ1-zaBA#2iCg5ur{2+QۃfHƔ,o&W)A):Q, o0:A'3z iB }jP@P!?6% + j%ͶGVކIz M1 _ZH e-pL#Ts^w5I]'/V[-&ʓ(sVdvrTr{ HTci= XPj؛*&Dq++Nr`ёFBb~/0!s}LhnX LLG;ԫ5] őrN' [9LdJRTqOUU'G<'6F ޓXvLvzQVN*aHLVDEj |oW[mjf,"1r\Sa1Q^;^^#PJM/A̠ 'bDlUL2vRjĘ]ފ4ei(Lզi5񥈩v9oA1 AJ++j6OyY"p2P':"qm+\|Mn&x?PW55A0 ;2SfTҧ`P]j]}Rf/ӯ X2'C| GSmX: FøkE`|⻋G@PǶ̀!}2Rm~pc ;GN|*aMu=h%Z1=L9Eqg7]D7 Oi, AqEnې#rlR`8V'Gy(fr[9h&i0d~Г &.#JU(: 4dpa! ؚH]wOr*/g+7R%aӗ`%Kg»B0W6o ߑ$~dl0^A!hW"=uN( U}Y#-;bQB PDYy1͚fC s㇇,0mO{ dF21wT;7_N<>b4-edѴ2+e*-vk1# ɂUeIUW &NLY/8SVE>߼ց%XH S[i<-Db{f6ô-MI@6b6 NtC1U l>4Ոk6mܸ/Mz{6&+ʒ q_D-p%{S *r#>(t:|y> y Wy>qI OlPuK0h ]M^"db"{8>'8(Ч9p}s["Kr!c+AfuK&qD־c$/`8qK X~3 {pW&c~u0!̵峄B@ $.hW4e*DնzߝeB1 0m>foA~ljqĀ夯'.X/j/dO*ʚr~6wWGBbb"3 ?Ц7P7y {2taT%>PXĢT3@kb&NL;8@x*ґq? }xhgr'k@mn<.ʾD!mYY\ӡ]?|6v*y6'_^hu!Q89 6Bq;l> nd 9 [lɕ݃@jRʊx7 c5.axV_6Յ/8s盳N poCpmEոgpE#=4/*,2|꾱,`4kaGBhld4odQi|&nWO8՜Mz+&?28us>6~=US1k.H]ϏT -YlP z4_Kr-K>endstream endobj 51 0 obj << /Filter /FlateDecode /Length 312 >> stream x]n@D{? fזmE((| }fv҃=nFCu<2ϴØ%]SyNc.6uُq}gtsQ_gN%pVds?>].ߩ8`a"߫8պ1*LTd09FC ņˍ/ƨ0Qw WFQQ# MQ(ޱ3 9¯гg/ ¼y#(+#GPWFPAa_Ӌy6ynx[WlܛsiiS%TޢQendstream endobj 52 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2661 >> stream xVitSeR*J;!UG2n8¸@Y"KBkwtI&i4k$MtMZnhDY*: (stP,Xϑ_'yyߗG xmٲ{f "}.X}F6oU3/4]cms0MP!u&M y0":DtzՅ F*ʖ`sx hx+C `k; zCBB7ׂ*6CG37%tX0Vb8\+ eRPA:Z^?(DQ~>yAqQC/c׃_it$#kOP #[3j_"@Ŭ$( [>YL[G{KIU)"eΓpwЌhNdMK7Y)6Fjfڍ[3wM)uDzލ6@X Y\F"9K@2сV6ZmLmhX_I)a :[=~D6L&ђ$_b`P?\(H 6 mY`d9xtEtN۽-) X'Lis9v`(S/髙Ų)C: %:T*JZp5p.]U* xRuL811ߋl~oՃn7cWg}<1L=hEO)[ :$3̶`m$4b}q^5Nf-p):{lk~#x6Zo(;&Ǖy"zbopC8N#Ot pӜk8O3P5Sr7MITٺ PRS7MTV$38Ֆÿ.&5:B֞΁co֜޽p2OqysVIÃfIT]'9BJ2IW,&JsV3x.>/ӱb0s#`G./gq87b/Ʊ~pa{Tkwii}v3Ts-,w`l+4S=ny4sDݴ;抝D?vߨ=se כL&#Bwu`' \$pJcNsLlg%瘙D}MyjrՄ*U{7| #hziA0_E'/ΒĎ oaeMlbiUFZBY1iu.o4xzK͔3i۲+r0+nK1']頇FD飯ķdƨN-8 < &s9@mrKVpW+Q 0% <{`ۂ-xVT봻t#PAF5irmT 0Rp1K'ߕ>$n*W"`Sh.^Dh/ cc/ mqҫ7N:r(7=4-z67Tju`641hikC3 -aEqV3Su1*j6HhA$sz`~*eɻ*#o0Z -jZFNaj2;'#6CHJsgU`ksN[VDX>7Qm"&%#^3Gw=̢yFdԓeowO4QrC֓[hw~Dڐ&^e?E2(k F*jfyntҬsNMBV zZx =*DZht:9 =-2"rwfpbi^5/b!^> stream x} Pg{5m3me] I0ĕ<6DdFqc`QF9dzTvoruE♯ѷze3*%葍A\H=t}C0g<~ hvY ts՛o}>~7ɊX8LhQU3&dr Q+ai:B w[9rG_\\y/UAck0iZ)w6֮iy$/OhWBdO"jHXEΚ-gχD%EG9ڜ.,nT.ls2Y~B#֠d@ VC|Fͧ)ME>dЭ{F~Śzc-&tS'ˌbj@. ֓HdDVgc%#03^nB֪JtS\zɨݻgyU,\3/E1$*:O3:k6(^֙P(Ӿ~~XkK7T ̾M6}^g:,r]~̎?td$s2ZQXQf,JEkКYw)8I63\_쏧s[ \B6\B#%ԋ1<Jl:ڛYo^YN%tDt4NLD( lhHj[e7@-h>Sr2`I޿aũYJ9QB!83KJPUP8(G$O5Q^ʸ\"ZkHf Vv4[5nu΂ A[* \o]Iq'Rz++ٕ_P_f,Fi)Xʀqٯٮ>W3䎤}4S'OJ*o{]8{] (Uֲ]JHp[M8Lg/9(Ogge+:PKtq-ҊX R֘?@q;?\bzluAUY ķ:]m몒)~Aћ[uHGad>Rxz<[A?78+P}=}?HI1DLI &B׭tġY+.*)D&<|:JIQ3Ŏ~Š a3A|>Z&Kc)-@(6ؙ JdCT. Lo{PtsJjzp֪j-">i%>}}JDv?> stream xcd`ab`ddM,pI-Lu JM/I, 154w!sk7s7KǤB7_`F}&FF_A|?z~J,gs|XOq1d`@"endstream endobj 55 0 obj << /Filter /FlateDecode /Length 4683 >> stream x[rF}gGz-B;J3[e9&& ɶ &ň=UKyH@QUgE.f.~?0VlidnLjrgګ\lS6[w~vzjv2KiLD0̵s}]5b{ p{BJP+?93SN`A'un??ŋz5_^RF;LBxmn!fȍbҗ {Fnw[B\*1\w1{B }B,gG*%ԄJBIzRz|?߿~d݈ЃźPzm9^R9 ES zѯ˱ysNeW?2c?gQ 7E9YpD>"1t|w̲6vB˄"CK7Ut{r C#Mv8>>PtϵT{/}|6Rpń' %62=`B"zy1{{Ak^@Q¥ 6` W pr3K2Oz~ )Mm7kK/ ug5+@%P%Y GĀ't^fWՊRQuV8J ΘC-ˡt%b߽z{~ToZоɚʻ` 3 %u޲sr9 jSCzIm䴴K˼Ο<?߮R("x`<]UxKr2qDL0ǓH%)Bgm٦7-yZVwON% S4QJ[&IH H"ɕ+zH#Xg]>묮g鋌GgA4m=Bs@m%JmwVu/W(" _S""O6%|b`g(>oRd$Ȫ7zJE{x$9Z<+q nup P42Il*u_ } 9]`ukIˌ)S>.+|HV]mjuM?b=]R\M 6^$RT])/ˮW'sdͅpK6[b=k#Q`Oxza^s-A ǤEn:*:^iX/yhz3gJ-vup\'uG T곸f[u ^N/X /n͒؄@# ( SIUm`MW`}ćS좡[c üEle2BYdg`׻0Hh=35:Mv1EySh}GH28A\$wUchB|LoX_ a9k! NN87_LaҨ`ͶvD/ E'yƨBYsp֣5?ysAfgj=Ş`W=  \9 D;b\"jpp*0vWڥO*7yinMYd͚FJJ9uu5b(nw1?Ҁ|ЎD&;uOA`Ş[?|[L9 &Ύ|~(FJ/BN?dj>* |< ۮCP5 \Za#Lɵbt<ڒfϚ+(c/\]LYȇ_ ԘQ[Ez8En #+84rZxVmnyYE B|ZYq!${1eQ]rziQbd(bRǹ8H2Ѳ !,_{;~c"/ZUB)ʠ~!K@< en`qyo*]:݊PQ>y U"ci2ɰIk2His^IDi!)(Y ,ѕ*¯~( ?ȻTsXr:ObH{Ngʼn FjH^<8ಫ:G`9.nO`Oc`4;Y5U78~La'!rJwE@.QG0n6 3Y&~Tf2`UOc듍Ih"([/}[> XuW#Ez1Ԇ2 ٸ䊰1?1{I [h4FZuD6^oʟQ+cA.Gc2y}46T[O㵟4"}؋z}F'shM,5uboV9*Fz'&VkikYUs.WMjyᡚ|3J9i ݌C=Hz8bWTZZ-g&d":r}2/(ù{5coK-Ǚ^\yKVC"F:uCF nmꋦ]"\?pSqL1>c S,ux#ukEQx*;#}@eʴ,~6=6!rJ0O8.1e!!ŸhKmlݮ#")#' bN0S b;-tL!|Ww$xѦ!2WKij!;E/. spuz _rEu@){ZD[\\7p""rR0Agast1|t( JPnLTI|sDew=;u\ Ѻƶ. igĵ>2$CVLy*V|fE|CX$}3q:#uj^.AAS;F_6YuY-WQW&Sq?`.ϫ.wJ.wgoU.J/cɆ|5ﯻ&^)Qq5遦j:AFd p"F`8}g(fsɭ/icKgwo:IZ Q9:1g]wѾxbMb7{^сG)(Sռ'D"CT61džzu4Oۺjj@Y˝oSw-nUҵ*H!=}Kj8q@ʀܧEv%tuM=4n,+z o`T Pdq]m.QL'd4h7 ^?#اk#Qv1%,Fav۽V,M^p~̾,; 5Xo`6oZ.bV@60UPGap l(O< OF)I(S^JҘ31 g#ONq,- y#o=4+Kï/GΗ6;$xL!({}|QEDUb2ï;V .jn/5O@ zNn cOmJ'µPy|͜NiWmB$Ka/WjJ AU*ujas\>wC s{P`D[\.pk S+R gmR W.qp x=p->&;)pK$pS* cwP>?" QR9 &ʆ/Qrv;Z3Tb1Wh/Iy@j45twmdRؘuIҰ~ܤXGK'bc{ ^;BxO3`*[нCBCuCOC` C  }B*qah^%,NI+R|sH#A,brV@Ӟ㈹I懃Q}endstream endobj 56 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2922 >> stream xMViTaU$ E\APvd_dvP;( PaŠl Q. Igj=}~_Z}a#9a]|gh;rիƻ``c7  -vx"1;),[%QzrI|e6”"j\ 7,Yσmrz{:& hohxf9l% qm&@r` x 3RrQ ;6?[j uW;߭~gϜbľGbc 2w~*5.}vѭkE5.&ZQDO-K@`ȱѣƶlǵ[!C##.K}n2rzJ(!?&!ӿ#:_to#'dl,` e =SԕԽoَD0es:SŲLaL[[y؁#XL EU'͌':R?ipXg`MLYds,45>Ģ~Fsn\\Y"6*ֹ2}=_XPz2؎PdHNM蠪nq﷧|NZT/SY?͜HH} yUZz8/(,&;?MvJ! ?sG>F|f2޶D6^W2OfIrZdiԧNJ_s}:rGqMr^+Khw/ug|0q8lp\<di.t=D&>ǒՖ!~dV-)ik 㩪D&FoIa8{?;[îtNbv^ulq-׊-iq^|RA.SDkJ`|K+ %ygZOsF֜G8M!Š,z!+^kY8 9>Î`(6>2G$ g Fr2cEe?D7CW]ߌb/Ec|~Dzϰ\8Hc3ANΊw {+Z$ wjo)Hcgg4(*$*L/:-3 \ JdYPt^aEWk8M{ j-PGlHAu~]`9zؚ8Zxc,| K]0.\^V_ήauJT:UCQy/ډ4PZ5ne †C³zl[0'/Bj78WPՖR ;O ʯJrkͨil$ǯ``WJϟtqtrz~3SUd: t[(VVrE7k\M=1`snogw& mB)>)eI e/F)!5TVgփ>q *&^ D!rOӋLIa#XnXM>f~O82I/7GE0p%R]oo`1^?q(FHWO9bg8` Eü![Ԇܰ|Qpo7 h.[3LR^wv)#66vK 3kRcS(mҦKbEKr$xÉ]vEnXXzEVAׅk,Zp|^pjQ4zj8A-x+k6ه[osArL&@LӨG`caC,>-E4s\٤"(ٓŤVͱŎU %م`;ox}sx( ʒsb΄BxF;rR&Xx(d~ nj- jW;"e]t|AFҖ;+̨8y~kmX6֮.~ư̛m{"} vXG,m!pk?ۊo+ueѥarUO0$DެyU[KEB$&!%DDZc<.AIFyqM1Qkit꾚n(`U 95LOItјbp R=:ʡSyJm:w 1{VƧƦJ63k#n ʅhDoV YyJNlU9VuvUݽ Á#;w3#K"qT"nL3r1Nؙ&[iF܉AHySBR&fmx$yMQ<)CsGDs i 3P&'㧄U$A{?jIendstream endobj 57 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1386 >> stream xe{LWgey#EL+ƪ T_@-"KR **\D(.By肂(T E-RV4Rb i9Cn;D&?nro=܀ IGPF)]C>6}g\D픷!2!ņZ06'U;8~vAބaNXC'Bba&A9Et+I_24vɞo0< :W.@@vR/sLcn6@51ܦ^볚{WnHQz+&IX]4JTcjQJFaaH˷TЕhDcr;l: :Ws~H2: n^¯c0pN`  !a @߉:k4^B%EIT;oRe l:2RV54TW7"v"^ = =xYtrL"v|)OٰqR94FC؂c\/5V;^e!_~.7LN9ꑆ(]qaF#8˶I=}T-!&'"654uk\#'«N^䤸ru:|"Q{ȡ$>2# sQvv5Srrk⫢b'u gf+ $~Ҥ"Cg_8)F:)Q}E1}ai<0J@1Mܢ"L{iC[|6o@`yK<[X4%yI:4 y>Jblߖ Ad1hQC*oTͨ< 3߄?C؏NA!W\d-c]`:4sl3CY1I`cnv$#Ò[a9=nM a,l`^7ѹ/x (]8^5<ܷË7$5yG: LT,ayrlhò1v/F{{F(VCRmɪب֝f0vNOX_-n~tGa.zӬw=ߖ ŢG1jr(X?3(M4fI+;/"Ą ԯOendstream endobj 58 0 obj << /Type /XRef /Length 90 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Info 3 0 R /Root 2 0 R /Size 59 /ID [<0098d33ec911351d398764bb818539d8>] >> stream xcb&F~ cX!{Hp\<2@B  V I @{?HL Ľ$lGW endstream endobj startxref 50791 %%EOF RcppAnnoy/inst/include/0000755000176200001440000000000014553605723014575 5ustar liggesusersRcppAnnoy/inst/include/mman.h0000644000176200001440000001323713743110346015674 0ustar liggesusers // This is from https://code.google.com/p/mman-win32/ // // Licensed under MIT #ifndef _MMAN_WIN32_H #define _MMAN_WIN32_H #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #include #include #include #include #define PROT_NONE 0 #define PROT_READ 1 #define PROT_WRITE 2 #define PROT_EXEC 4 #define MAP_FILE 0 #define MAP_SHARED 1 #define MAP_PRIVATE 2 #define MAP_TYPE 0xf #define MAP_FIXED 0x10 #define MAP_ANONYMOUS 0x20 #define MAP_ANON MAP_ANONYMOUS #define MAP_FAILED ((void *)-1) /* Flags for msync. */ #define MS_ASYNC 1 #define MS_SYNC 2 #define MS_INVALIDATE 4 #ifndef FILE_MAP_EXECUTE #define FILE_MAP_EXECUTE 0x0020 #endif static int __map_mman_error(const DWORD err, const int deferr) { if (err == 0) return 0; //TODO: implement return err; } static DWORD __map_mmap_prot_page(const int prot) { DWORD protect = 0; if (prot == PROT_NONE) return protect; if ((prot & PROT_EXEC) != 0) { protect = ((prot & PROT_WRITE) != 0) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; } else { protect = ((prot & PROT_WRITE) != 0) ? PAGE_READWRITE : PAGE_READONLY; } return protect; } static DWORD __map_mmap_prot_file(const int prot) { DWORD desiredAccess = 0; if (prot == PROT_NONE) return desiredAccess; if ((prot & PROT_READ) != 0) desiredAccess |= FILE_MAP_READ; if ((prot & PROT_WRITE) != 0) desiredAccess |= FILE_MAP_WRITE; if ((prot & PROT_EXEC) != 0) desiredAccess |= FILE_MAP_EXECUTE; return desiredAccess; } inline void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) { HANDLE fm, h; void * map = MAP_FAILED; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4293) #endif const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ? (DWORD)off : (DWORD)(off & 0xFFFFFFFFL); const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ? (DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL); const DWORD protect = __map_mmap_prot_page(prot); const DWORD desiredAccess = __map_mmap_prot_file(prot); const off_t maxSize = off + (off_t)len; const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) ? (DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL); const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) ? (DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL); #ifdef _MSC_VER #pragma warning(pop) #endif errno = 0; if (len == 0 /* Unsupported flag combinations */ || (flags & MAP_FIXED) != 0 /* Usupported protection combinations */ || prot == PROT_EXEC) { errno = EINVAL; return MAP_FAILED; } h = ((flags & MAP_ANONYMOUS) == 0) ? (HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE; if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE) { errno = EBADF; return MAP_FAILED; } fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL); if (fm == NULL) { errno = __map_mman_error(GetLastError(), EPERM); return MAP_FAILED; } map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len); CloseHandle(fm); if (map == NULL) { errno = __map_mman_error(GetLastError(), EPERM); return MAP_FAILED; } return map; } inline int munmap(void *addr, size_t len) { if (UnmapViewOfFile(addr)) return 0; errno = __map_mman_error(GetLastError(), EPERM); return -1; } inline int mprotect(void *addr, size_t len, int prot) { DWORD newProtect = __map_mmap_prot_page(prot); DWORD oldProtect = 0; if (VirtualProtect(addr, len, newProtect, &oldProtect)) return 0; errno = __map_mman_error(GetLastError(), EPERM); return -1; } inline int msync(void *addr, size_t len, int flags) { if (FlushViewOfFile(addr, len)) return 0; errno = __map_mman_error(GetLastError(), EPERM); return -1; } inline int mlock(const void *addr, size_t len) { if (VirtualLock((LPVOID)addr, len)) return 0; errno = __map_mman_error(GetLastError(), EPERM); return -1; } inline int munlock(const void *addr, size_t len) { if (VirtualUnlock((LPVOID)addr, len)) return 0; errno = __map_mman_error(GetLastError(), EPERM); return -1; } #if !defined(__MINGW32__) inline int ftruncate(const int fd, const int64_t size) { if (fd < 0) { errno = EBADF; return -1; } HANDLE h = reinterpret_cast(_get_osfhandle(fd)); LARGE_INTEGER li_start, li_size; li_start.QuadPart = static_cast(0); li_size.QuadPart = size; if (SetFilePointerEx(h, li_start, NULL, FILE_CURRENT) == ~0 || SetFilePointerEx(h, li_size, NULL, FILE_BEGIN) == ~0 || !SetEndOfFile(h)) { unsigned long error = GetLastError(); fprintf(stderr, "I/O error while truncating: %lu\n", error); switch (error) { case ERROR_INVALID_HANDLE: errno = EBADF; break; default: errno = EIO; break; } return -1; } return 0; } #endif #endif RcppAnnoy/inst/include/kissrandom.h0000644000176200001440000000504713763170231017117 0ustar liggesusers#ifndef KISSRANDOM_H #define KISSRANDOM_H #if defined(_MSC_VER) && _MSC_VER == 1500 typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #else #include #endif // KISS = "keep it simple, stupid", but high quality random number generator // http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf -> "Use a good RNG and build it into your code" // http://mathforum.org/kb/message.jspa?messageID=6627731 // https://de.wikipedia.org/wiki/KISS_(Zufallszahlengenerator) // 32 bit KISS struct Kiss32Random { uint32_t x; uint32_t y; uint32_t z; uint32_t c; static const uint32_t default_seed = 123456789; #if __cplusplus < 201103L typedef uint32_t seed_type; #endif // seed must be != 0 Kiss32Random(uint32_t seed = default_seed) { x = seed; y = 362436000; z = 521288629; c = 7654321; } uint32_t kiss() { // Linear congruence generator x = 69069 * x + 12345; // Xor shift y ^= y << 13; y ^= y >> 17; y ^= y << 5; // Multiply-with-carry uint64_t t = 698769069ULL * z + c; c = t >> 32; z = (uint32_t) t; return x + y + z; } inline int flip() { // Draw random 0 or 1 return kiss() & 1; } inline size_t index(size_t n) { // Draw random integer between 0 and n-1 where n is at most the number of data points you have return kiss() % n; } inline void set_seed(uint32_t seed) { x = seed; } }; // 64 bit KISS. Use this if you have more than about 2^24 data points ("big data" ;) ) struct Kiss64Random { uint64_t x; uint64_t y; uint64_t z; uint64_t c; static const uint64_t default_seed = 1234567890987654321ULL; #if __cplusplus < 201103L typedef uint64_t seed_type; #endif // seed must be != 0 Kiss64Random(uint64_t seed = default_seed) { x = seed; y = 362436362436362436ULL; z = 1066149217761810ULL; c = 123456123456123456ULL; } uint64_t kiss() { // Linear congruence generator z = 6906969069LL*z+1234567; // Xor shift y ^= (y<<13); y ^= (y>>17); y ^= (y<<43); // Multiply-with-carry (uint128_t t = (2^58 + 1) * x + c; c = t >> 64; x = (uint64_t) t) uint64_t t = (x<<58)+c; c = (x>>6); x += t; c += (x #include #ifndef _MSC_VER #include #endif #include #include #include #include #include #if defined(_MSC_VER) && _MSC_VER == 1500 typedef unsigned char uint8_t; typedef signed __int32 int32_t; typedef unsigned __int64 uint64_t; typedef signed __int64 int64_t; #else #include #endif #if defined(_MSC_VER) || defined(__MINGW32__) // a bit hacky, but override some definitions to support 64 bit #define off_t int64_t #define lseek_getsize(fd) _lseeki64(fd, 0, SEEK_END) #ifndef NOMINMAX #define NOMINMAX #endif #include "mman.h" #include #else #include #define lseek_getsize(fd) lseek(fd, 0, SEEK_END) #endif #include #include #include #include #include #include #include #if __cplusplus >= 201103L #include #endif #ifdef ANNOYLIB_MULTITHREADED_BUILD #include #include #include #endif #ifdef _MSC_VER // Needed for Visual Studio to disable runtime checks for mempcy #pragma runtime_checks("s", off) #endif // This allows others to supply their own logger / error printer without // requiring Annoy to import their headers. See RcppAnnoy for a use case. #ifndef __ERROR_PRINTER_OVERRIDE__ #define annoylib_showUpdate(...) { fprintf(stderr, __VA_ARGS__ ); } #else #define annoylib_showUpdate(...) { __ERROR_PRINTER_OVERRIDE__( __VA_ARGS__ ); } #endif // Portable alloc definition, cf Writing R Extensions, Section 1.6.4 #ifdef __GNUC__ // Includes GCC, clang and Intel compilers # undef alloca # define alloca(x) __builtin_alloca((x)) #elif defined(__sun) || defined(_AIX) // this is necessary (and sufficient) for Solaris 10 and AIX 6: # include #endif // We let the v array in the Node struct take whatever space is needed, so this is a mostly insignificant number. // Compilers need *some* size defined for the v array, and some memory checking tools will flag for buffer overruns if this is set too low. #define ANNOYLIB_V_ARRAY_SIZE 65536 #ifndef _MSC_VER #define annoylib_popcount __builtin_popcountll #else // See #293, #358 #define annoylib_popcount cole_popcount #endif #if !defined(NO_MANUAL_VECTORIZATION) && defined(__GNUC__) && (__GNUC__ >6) && defined(__AVX512F__) // See #402 #define ANNOYLIB_USE_AVX512 #elif !defined(NO_MANUAL_VECTORIZATION) && defined(__AVX__) && defined (__SSE__) && defined(__SSE2__) && defined(__SSE3__) #define ANNOYLIB_USE_AVX #else #endif #if defined(ANNOYLIB_USE_AVX) || defined(ANNOYLIB_USE_AVX512) #if defined(_MSC_VER) #include #elif defined(__GNUC__) #include #endif #endif #if !defined(__MINGW32__) #define ANNOYLIB_FTRUNCATE_SIZE(x) static_cast(x) #else #define ANNOYLIB_FTRUNCATE_SIZE(x) (x) #endif namespace Annoy { inline void set_error_from_errno(char **error, const char* msg) { annoylib_showUpdate("%s: %s (%d)\n", msg, strerror(errno), errno); if (error) { *error = (char *)malloc(256); // TODO: win doesn't support snprintf snprintf(*error, 255, "%s: %s (%d)", msg, strerror(errno), errno); } } inline void set_error_from_string(char **error, const char* msg) { annoylib_showUpdate("%s\n", msg); if (error) { *error = (char *)malloc(strlen(msg) + 1); strcpy(*error, msg); } } using std::vector; using std::pair; using std::numeric_limits; using std::make_pair; inline bool remap_memory_and_truncate(void** _ptr, int _fd, size_t old_size, size_t new_size) { #ifdef __linux__ *_ptr = mremap(*_ptr, old_size, new_size, MREMAP_MAYMOVE); bool ok = ftruncate(_fd, new_size) != -1; #else munmap(*_ptr, old_size); bool ok = ftruncate(_fd, ANNOYLIB_FTRUNCATE_SIZE(new_size)) != -1; #ifdef MAP_POPULATE *_ptr = mmap(*_ptr, new_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, _fd, 0); #else *_ptr = mmap(*_ptr, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); #endif #endif return ok; } namespace { template inline Node* get_node_ptr(const void* _nodes, const size_t _s, const S i) { return (Node*)((uint8_t *)_nodes + (_s * i)); } template inline T dot(const T* x, const T* y, int f) { T s = 0; for (int z = 0; z < f; z++) { s += (*x) * (*y); x++; y++; } return s; } template inline T manhattan_distance(const T* x, const T* y, int f) { T d = 0.0; for (int i = 0; i < f; i++) d += fabs(x[i] - y[i]); return d; } template inline T euclidean_distance(const T* x, const T* y, int f) { // Don't use dot-product: avoid catastrophic cancellation in #314. T d = 0.0; for (int i = 0; i < f; ++i) { const T tmp=*x - *y; d += tmp * tmp; ++x; ++y; } return d; } #ifdef ANNOYLIB_USE_AVX // Horizontal single sum of 256bit vector. inline float hsum256_ps_avx(__m256 v) { const __m128 x128 = _mm_add_ps(_mm256_extractf128_ps(v, 1), _mm256_castps256_ps128(v)); const __m128 x64 = _mm_add_ps(x128, _mm_movehl_ps(x128, x128)); const __m128 x32 = _mm_add_ss(x64, _mm_shuffle_ps(x64, x64, 0x55)); return _mm_cvtss_f32(x32); } template<> inline float dot(const float* x, const float *y, int f) { float result = 0; if (f > 7) { __m256 d = _mm256_setzero_ps(); for (; f > 7; f -= 8) { d = _mm256_add_ps(d, _mm256_mul_ps(_mm256_loadu_ps(x), _mm256_loadu_ps(y))); x += 8; y += 8; } // Sum all floats in dot register. result += hsum256_ps_avx(d); } // Don't forget the remaining values. for (; f > 0; f--) { result += *x * *y; x++; y++; } return result; } template<> inline float manhattan_distance(const float* x, const float* y, int f) { float result = 0; int i = f; if (f > 7) { __m256 manhattan = _mm256_setzero_ps(); __m256 minus_zero = _mm256_set1_ps(-0.0f); for (; i > 7; i -= 8) { const __m256 x_minus_y = _mm256_sub_ps(_mm256_loadu_ps(x), _mm256_loadu_ps(y)); const __m256 distance = _mm256_andnot_ps(minus_zero, x_minus_y); // Absolute value of x_minus_y (forces sign bit to zero) manhattan = _mm256_add_ps(manhattan, distance); x += 8; y += 8; } // Sum all floats in manhattan register. result = hsum256_ps_avx(manhattan); } // Don't forget the remaining values. for (; i > 0; i--) { result += fabsf(*x - *y); x++; y++; } return result; } template<> inline float euclidean_distance(const float* x, const float* y, int f) { float result=0; if (f > 7) { __m256 d = _mm256_setzero_ps(); for (; f > 7; f -= 8) { const __m256 diff = _mm256_sub_ps(_mm256_loadu_ps(x), _mm256_loadu_ps(y)); d = _mm256_add_ps(d, _mm256_mul_ps(diff, diff)); // no support for fmadd in AVX... x += 8; y += 8; } // Sum all floats in dot register. result = hsum256_ps_avx(d); } // Don't forget the remaining values. for (; f > 0; f--) { float tmp = *x - *y; result += tmp * tmp; x++; y++; } return result; } #endif #ifdef ANNOYLIB_USE_AVX512 template<> inline float dot(const float* x, const float *y, int f) { float result = 0; if (f > 15) { __m512 d = _mm512_setzero_ps(); for (; f > 15; f -= 16) { //AVX512F includes FMA d = _mm512_fmadd_ps(_mm512_loadu_ps(x), _mm512_loadu_ps(y), d); x += 16; y += 16; } // Sum all floats in dot register. result += _mm512_reduce_add_ps(d); } // Don't forget the remaining values. for (; f > 0; f--) { result += *x * *y; x++; y++; } return result; } template<> inline float manhattan_distance(const float* x, const float* y, int f) { float result = 0; int i = f; if (f > 15) { __m512 manhattan = _mm512_setzero_ps(); for (; i > 15; i -= 16) { const __m512 x_minus_y = _mm512_sub_ps(_mm512_loadu_ps(x), _mm512_loadu_ps(y)); manhattan = _mm512_add_ps(manhattan, _mm512_abs_ps(x_minus_y)); x += 16; y += 16; } // Sum all floats in manhattan register. result = _mm512_reduce_add_ps(manhattan); } // Don't forget the remaining values. for (; i > 0; i--) { result += fabsf(*x - *y); x++; y++; } return result; } template<> inline float euclidean_distance(const float* x, const float* y, int f) { float result=0; if (f > 15) { __m512 d = _mm512_setzero_ps(); for (; f > 15; f -= 16) { const __m512 diff = _mm512_sub_ps(_mm512_loadu_ps(x), _mm512_loadu_ps(y)); d = _mm512_fmadd_ps(diff, diff, d); x += 16; y += 16; } // Sum all floats in dot register. result = _mm512_reduce_add_ps(d); } // Don't forget the remaining values. for (; f > 0; f--) { float tmp = *x - *y; result += tmp * tmp; x++; y++; } return result; } #endif template inline T get_norm(T* v, int f) { return sqrt(dot(v, v, f)); } template inline void two_means(const vector& nodes, int f, Random& random, bool cosine, Node* p, Node* q) { /* This algorithm is a huge heuristic. Empirically it works really well, but I can't motivate it well. The basic idea is to keep two centroids and assign points to either one of them. We weight each centroid by the number of points assigned to it, so to balance it. */ static int iteration_steps = 200; size_t count = nodes.size(); size_t i = random.index(count); size_t j = random.index(count-1); j += (j >= i); // ensure that i != j Distance::template copy_node(p, nodes[i], f); Distance::template copy_node(q, nodes[j], f); if (cosine) { Distance::template normalize(p, f); Distance::template normalize(q, f); } Distance::init_node(p, f); Distance::init_node(q, f); int ic = 1, jc = 1; for (int l = 0; l < iteration_steps; l++) { size_t k = random.index(count); T di = ic * Distance::distance(p, nodes[k], f), dj = jc * Distance::distance(q, nodes[k], f); T norm = cosine ? get_norm(nodes[k]->v, f) : 1; if (!(norm > T(0))) { continue; } if (di < dj) { for (int z = 0; z < f; z++) p->v[z] = (p->v[z] * ic + nodes[k]->v[z] / norm) / (ic + 1); Distance::init_node(p, f); ic++; } else if (dj < di) { for (int z = 0; z < f; z++) q->v[z] = (q->v[z] * jc + nodes[k]->v[z] / norm) / (jc + 1); Distance::init_node(q, f); jc++; } } } } // namespace struct Base { template static inline void preprocess(void* nodes, size_t _s, const S node_count, const int f) { // Override this in specific metric structs below if you need to do any pre-processing // on the entire set of nodes passed into this index. } template static inline void zero_value(Node* dest) { // Initialize any fields that require sane defaults within this node. } template static inline void copy_node(Node* dest, const Node* source, const int f) { memcpy(dest->v, source->v, f * sizeof(T)); } template static inline void normalize(Node* node, int f) { T norm = get_norm(node->v, f); if (norm > 0) { for (int z = 0; z < f; z++) node->v[z] /= norm; } } }; struct Angular : Base { template struct Node { /* * We store a binary tree where each node has two things * - A vector associated with it * - Two children * All nodes occupy the same amount of memory * All nodes with n_descendants == 1 are leaf nodes. * A memory optimization is that for nodes with 2 <= n_descendants <= K, * we skip the vector. Instead we store a list of all descendants. K is * determined by the number of items that fits in the space of the vector. * For nodes with n_descendants == 1 the vector is a data point. * For nodes with n_descendants > K the vector is the normal of the split plane. * Note that we can't really do sizeof(node) because we cheat and allocate * more memory to be able to fit the vector outside */ S n_descendants; union { S children[2]; // Will possibly store more than 2 T norm; }; T v[ANNOYLIB_V_ARRAY_SIZE]; }; template static inline T distance(const Node* x, const Node* y, int f) { // want to calculate (a/|a| - b/|b|)^2 // = a^2 / a^2 + b^2 / b^2 - 2ab/|a||b| // = 2 - 2cos T pp = x->norm ? x->norm : dot(x->v, x->v, f); // For backwards compatibility reasons, we need to fall back and compute the norm here T qq = y->norm ? y->norm : dot(y->v, y->v, f); T pq = dot(x->v, y->v, f); T ppqq = pp * qq; if (ppqq > 0) return 2.0 - 2.0 * pq / sqrt(ppqq); else return 2.0; // cos is 0 } template static inline T margin(const Node* n, const T* y, int f) { return dot(n->v, y, f); } template static inline bool side(const Node* n, const T* y, int f, Random& random) { T dot = margin(n, y, f); if (dot != 0) return (dot > 0); else return (bool)random.flip(); } template static inline void create_split(const vector*>& nodes, int f, size_t s, Random& random, Node* n) { Node* p = (Node*)alloca(s); Node* q = (Node*)alloca(s); two_means >(nodes, f, random, true, p, q); for (int z = 0; z < f; z++) n->v[z] = p->v[z] - q->v[z]; Base::normalize >(n, f); } template static inline T normalized_distance(T distance) { // Used when requesting distances from Python layer // Turns out sometimes the squared distance is -0.0 // so we have to make sure it's a positive number. return sqrt(std::max(distance, T(0))); } template static inline T pq_distance(T distance, T margin, int child_nr) { if (child_nr == 0) margin = -margin; return std::min(distance, margin); } template static inline T pq_initial_value() { return numeric_limits::infinity(); } template static inline void init_node(Node* n, int f) { n->norm = dot(n->v, n->v, f); } static const char* name() { return "angular"; } }; struct DotProduct : Angular { template struct Node { /* * This is an extension of the Angular node with an extra attribute for the scaled norm. */ S n_descendants; S children[2]; // Will possibly store more than 2 T dot_factor; T v[ANNOYLIB_V_ARRAY_SIZE]; }; static const char* name() { return "dot"; } template static inline T distance(const Node* x, const Node* y, int f) { return -dot(x->v, y->v, f); } template static inline void zero_value(Node* dest) { dest->dot_factor = 0; } template static inline void init_node(Node* n, int f) { } template static inline void copy_node(Node* dest, const Node* source, const int f) { memcpy(dest->v, source->v, f * sizeof(T)); dest->dot_factor = source->dot_factor; } template static inline void create_split(const vector*>& nodes, int f, size_t s, Random& random, Node* n) { Node* p = (Node*)alloca(s); Node* q = (Node*)alloca(s); DotProduct::zero_value(p); DotProduct::zero_value(q); two_means >(nodes, f, random, true, p, q); for (int z = 0; z < f; z++) n->v[z] = p->v[z] - q->v[z]; n->dot_factor = p->dot_factor - q->dot_factor; DotProduct::normalize >(n, f); } template static inline void normalize(Node* node, int f) { T norm = sqrt(dot(node->v, node->v, f) + pow(node->dot_factor, 2)); if (norm > 0) { for (int z = 0; z < f; z++) node->v[z] /= norm; node->dot_factor /= norm; } } template static inline T margin(const Node* n, const T* y, int f) { return dot(n->v, y, f) + (n->dot_factor * n->dot_factor); } template static inline bool side(const Node* n, const T* y, int f, Random& random) { T dot = margin(n, y, f); if (dot != 0) return (dot > 0); else return (bool)random.flip(); } template static inline T normalized_distance(T distance) { return -distance; } template static inline void preprocess(void* nodes, size_t _s, const S node_count, const int f) { // This uses a method from Microsoft Research for transforming inner product spaces to cosine/angular-compatible spaces. // (Bachrach et al., 2014, see https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/XboxInnerProduct.pdf) // Step one: compute the norm of each vector and store that in its extra dimension (f-1) for (S i = 0; i < node_count; i++) { Node* node = get_node_ptr(nodes, _s, i); T d = dot(node->v, node->v, f); T norm = d < 0 ? 0 : sqrt(d); node->dot_factor = norm; } // Step two: find the maximum norm T max_norm = 0; for (S i = 0; i < node_count; i++) { Node* node = get_node_ptr(nodes, _s, i); if (node->dot_factor > max_norm) { max_norm = node->dot_factor; } } // Step three: set each vector's extra dimension to sqrt(max_norm^2 - norm^2) for (S i = 0; i < node_count; i++) { Node* node = get_node_ptr(nodes, _s, i); T node_norm = node->dot_factor; T squared_norm_diff = pow(max_norm, static_cast(2.0)) - pow(node_norm, static_cast(2.0)); T dot_factor = squared_norm_diff < 0 ? 0 : sqrt(squared_norm_diff); node->dot_factor = dot_factor; } } }; struct Hamming : Base { template struct Node { S n_descendants; S children[2]; T v[ANNOYLIB_V_ARRAY_SIZE]; }; static const size_t max_iterations = 20; template static inline T pq_distance(T distance, T margin, int child_nr) { return distance - (margin != (unsigned int) child_nr); } template static inline T pq_initial_value() { return numeric_limits::max(); } template static inline int cole_popcount(T v) { // Note: Only used with MSVC 9, which lacks intrinsics and fails to // calculate std::bitset::count for v > 32bit. Uses the generalized // approach by Eric Cole. // See https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64 v = v - ((v >> 1) & (T)~(T)0/3); v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); v = (v + (v >> 4)) & (T)~(T)0/255*15; return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; } template static inline T distance(const Node* x, const Node* y, int f) { size_t dist = 0; for (int i = 0; i < f; i++) { dist += annoylib_popcount(x->v[i] ^ y->v[i]); } return dist; } template static inline bool margin(const Node* n, const T* y, int f) { static const size_t n_bits = sizeof(T) * 8; T chunk = n->v[0] / n_bits; return (y[chunk] & (static_cast(1) << (n_bits - 1 - (n->v[0] % n_bits)))) != 0; } template static inline bool side(const Node* n, const T* y, int f, Random& random) { return margin(n, y, f); } template static inline void create_split(const vector*>& nodes, int f, size_t s, Random& random, Node* n) { size_t cur_size = 0; size_t i = 0; int dim = f * 8 * sizeof(T); for (; i < max_iterations; i++) { // choose random position to split at n->v[0] = random.index(dim); cur_size = 0; for (typename vector*>::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { if (margin(n, (*it)->v, f)) { cur_size++; } } if (cur_size > 0 && cur_size < nodes.size()) { break; } } // brute-force search for splitting coordinate if (i == max_iterations) { int j = 0; for (; j < dim; j++) { n->v[0] = j; cur_size = 0; for (typename vector*>::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { if (margin(n, (*it)->v, f)) { cur_size++; } } if (cur_size > 0 && cur_size < nodes.size()) { break; } } } } template static inline T normalized_distance(T distance) { return distance; } template static inline void init_node(Node* n, int f) { } static const char* name() { return "hamming"; } }; struct Minkowski : Base { template struct Node { S n_descendants; T a; // need an extra constant term to determine the offset of the plane S children[2]; T v[ANNOYLIB_V_ARRAY_SIZE]; }; template static inline T margin(const Node* n, const T* y, int f) { return n->a + dot(n->v, y, f); } template static inline bool side(const Node* n, const T* y, int f, Random& random) { T dot = margin(n, y, f); if (dot != 0) return (dot > 0); else return (bool)random.flip(); } template static inline T pq_distance(T distance, T margin, int child_nr) { if (child_nr == 0) margin = -margin; return std::min(distance, margin); } template static inline T pq_initial_value() { return numeric_limits::infinity(); } }; struct Euclidean : Minkowski { template static inline T distance(const Node* x, const Node* y, int f) { return euclidean_distance(x->v, y->v, f); } template static inline void create_split(const vector*>& nodes, int f, size_t s, Random& random, Node* n) { Node* p = (Node*)alloca(s); Node* q = (Node*)alloca(s); two_means >(nodes, f, random, false, p, q); for (int z = 0; z < f; z++) n->v[z] = p->v[z] - q->v[z]; Base::normalize >(n, f); n->a = 0.0; for (int z = 0; z < f; z++) n->a += -n->v[z] * (p->v[z] + q->v[z]) / 2; } template static inline T normalized_distance(T distance) { return sqrt(std::max(distance, T(0))); } template static inline void init_node(Node* n, int f) { } static const char* name() { return "euclidean"; } }; struct Manhattan : Minkowski { template static inline T distance(const Node* x, const Node* y, int f) { return manhattan_distance(x->v, y->v, f); } template static inline void create_split(const vector*>& nodes, int f, size_t s, Random& random, Node* n) { Node* p = (Node*)alloca(s); Node* q = (Node*)alloca(s); two_means >(nodes, f, random, false, p, q); for (int z = 0; z < f; z++) n->v[z] = p->v[z] - q->v[z]; Base::normalize >(n, f); n->a = 0.0; for (int z = 0; z < f; z++) n->a += -n->v[z] * (p->v[z] + q->v[z]) / 2; } template static inline T normalized_distance(T distance) { return std::max(distance, T(0)); } template static inline void init_node(Node* n, int f) { } static const char* name() { return "manhattan"; } }; template class AnnoyIndexInterface { public: // Note that the methods with an **error argument will allocate memory and write the pointer to that string if error is non-NULL virtual ~AnnoyIndexInterface() {}; virtual bool add_item(S item, const T* w, char** error=NULL) = 0; virtual bool build(int q, int n_threads=-1, char** error=NULL) = 0; virtual bool unbuild(char** error=NULL) = 0; virtual bool save(const char* filename, bool prefault=false, char** error=NULL) = 0; virtual void unload() = 0; virtual bool load(const char* filename, bool prefault=false, char** error=NULL) = 0; virtual T get_distance(S i, S j) const = 0; virtual void get_nns_by_item(S item, size_t n, int search_k, vector* result, vector* distances) const = 0; virtual void get_nns_by_vector(const T* w, size_t n, int search_k, vector* result, vector* distances) const = 0; virtual S get_n_items() const = 0; virtual S get_n_trees() const = 0; virtual void verbose(bool v) = 0; virtual void get_item(S item, T* v) const = 0; virtual void set_seed(R q) = 0; virtual bool on_disk_build(const char* filename, char** error=NULL) = 0; }; template class AnnoyIndex : public AnnoyIndexInterface= 201103L typename std::remove_const::type #else typename Random::seed_type #endif > { /* * We use random projection to build a forest of binary trees of all items. * Basically just split the hyperspace into two sides by a hyperplane, * then recursively split each of those subtrees etc. * We create a tree like this q times. The default q is determined automatically * in such a way that we at most use 2x as much memory as the vectors take. */ public: typedef Distance D; typedef typename D::template Node Node; #if __cplusplus >= 201103L typedef typename std::remove_const::type R; #else typedef typename Random::seed_type R; #endif protected: const int _f; size_t _s; S _n_items; void* _nodes; // Could either be mmapped, or point to a memory buffer that we reallocate S _n_nodes; S _nodes_size; vector _roots; S _K; R _seed; bool _loaded; bool _verbose; int _fd; bool _on_disk; bool _built; public: AnnoyIndex(int f) : _f(f), _seed(Random::default_seed) { _s = offsetof(Node, v) + _f * sizeof(T); // Size of each node _verbose = false; _built = false; _K = (S) (((size_t) (_s - offsetof(Node, children))) / sizeof(S)); // Max number of descendants to fit into node reinitialize(); // Reset everything } ~AnnoyIndex() { unload(); } int get_f() const { return _f; } bool add_item(S item, const T* w, char** error=NULL) { return add_item_impl(item, w, error); } template bool add_item_impl(S item, const W& w, char** error=NULL) { if (_loaded) { set_error_from_string(error, "You can't add an item to a loaded index"); return false; } _allocate_size(item + 1); Node* n = _get(item); D::zero_value(n); n->children[0] = 0; n->children[1] = 0; n->n_descendants = 1; for (int z = 0; z < _f; z++) n->v[z] = w[z]; D::init_node(n, _f); if (item >= _n_items) _n_items = item + 1; return true; } bool on_disk_build(const char* file, char** error=NULL) { _on_disk = true; #ifndef _MSC_VER _fd = open(file, O_RDWR | O_CREAT | O_TRUNC, (int) 0600); #else _fd = _open(file, _O_RDWR | _O_CREAT | _O_TRUNC, (int) 0600); #endif if (_fd == -1) { set_error_from_errno(error, "Unable to open"); _fd = 0; return false; } _nodes_size = 1; if (ftruncate(_fd, ANNOYLIB_FTRUNCATE_SIZE(_s) * ANNOYLIB_FTRUNCATE_SIZE(_nodes_size)) == -1) { set_error_from_errno(error, "Unable to truncate"); return false; } #ifdef MAP_POPULATE _nodes = (Node*) mmap(0, _s * _nodes_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, _fd, 0); #else _nodes = (Node*) mmap(0, _s * _nodes_size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); #endif return true; } bool build(int q, int n_threads=-1, char** error=NULL) { if (_loaded) { set_error_from_string(error, "You can't build a loaded index"); return false; } if (_built) { set_error_from_string(error, "You can't build a built index"); return false; } D::template preprocess(_nodes, _s, _n_items, _f); _n_nodes = _n_items; ThreadedBuildPolicy::template build(this, q, n_threads); // Also, copy the roots into the last segment of the array // This way we can load them faster without reading the whole file _allocate_size(_n_nodes + (S)_roots.size()); for (size_t i = 0; i < _roots.size(); i++) memcpy(_get(_n_nodes + (S)i), _get(_roots[i]), _s); _n_nodes += _roots.size(); if (_verbose) annoylib_showUpdate("has %d nodes\n", _n_nodes); if (_on_disk) { if (!remap_memory_and_truncate(&_nodes, _fd, static_cast(_s) * static_cast(_nodes_size), static_cast(_s) * static_cast(_n_nodes))) { // TODO: this probably creates an index in a corrupt state... not sure what to do set_error_from_errno(error, "Unable to truncate"); return false; } _nodes_size = _n_nodes; } _built = true; return true; } bool unbuild(char** error=NULL) { if (_loaded) { set_error_from_string(error, "You can't unbuild a loaded index"); return false; } _roots.clear(); _n_nodes = _n_items; _built = false; return true; } bool save(const char* filename, bool prefault=false, char** error=NULL) { if (!_built) { set_error_from_string(error, "You can't save an index that hasn't been built"); return false; } if (_on_disk) { return true; } else { // Delete file if it already exists (See issue #335) #ifndef _MSC_VER unlink(filename); #else _unlink(filename); #endif FILE *f = fopen(filename, "wb"); if (f == NULL) { set_error_from_errno(error, "Unable to open"); return false; } if (fwrite(_nodes, _s, _n_nodes, f) != (size_t) _n_nodes) { set_error_from_errno(error, "Unable to write"); return false; } if (fclose(f) == EOF) { set_error_from_errno(error, "Unable to close"); return false; } unload(); return load(filename, prefault, error); } } void reinitialize() { _fd = 0; _nodes = NULL; _loaded = false; _n_items = 0; _n_nodes = 0; _nodes_size = 0; _on_disk = false; _seed = Random::default_seed; _roots.clear(); } void unload() { if (_on_disk && _fd) { #ifndef _MSC_VER close(_fd); #else _close(_fd); #endif munmap(_nodes, _s * _nodes_size); } else { if (_fd) { // we have mmapped data #ifndef _MSC_VER close(_fd); #else _close(_fd); #endif munmap(_nodes, _n_nodes * _s); } else if (_nodes) { // We have heap allocated data free(_nodes); } } reinitialize(); if (_verbose) annoylib_showUpdate("unloaded\n"); } bool load(const char* filename, bool prefault=false, char** error=NULL) { #ifndef _MSC_VER _fd = open(filename, O_RDONLY, (int)0400); #else _fd = _open(filename, _O_RDONLY, (int)0400); #endif if (_fd == -1) { set_error_from_errno(error, "Unable to open"); _fd = 0; return false; } off_t size = lseek_getsize(_fd); if (size == -1) { set_error_from_errno(error, "Unable to get size"); return false; } else if (size == 0) { set_error_from_errno(error, "Size of file is zero"); return false; } else if (size % _s) { // Something is fishy with this index! set_error_from_errno(error, "Index size is not a multiple of vector size. Ensure you are opening using the same metric you used to create the index."); return false; } int flags = MAP_SHARED; if (prefault) { #ifdef MAP_POPULATE flags |= MAP_POPULATE; #else annoylib_showUpdate("prefault is set to true, but MAP_POPULATE is not defined on this platform"); #endif } _nodes = (Node*)mmap(0, size, PROT_READ, flags, _fd, 0); _n_nodes = (S)(size / _s); // Find the roots by scanning the end of the file and taking the nodes with most descendants _roots.clear(); S m = -1; for (S i = _n_nodes - 1; i >= 0; i--) { S k = _get(i)->n_descendants; if (m == -1 || k == m) { _roots.push_back(i); m = k; } else { break; } } // hacky fix: since the last root precedes the copy of all roots, delete it if (_roots.size() > 1 && _get(_roots.front())->children[0] == _get(_roots.back())->children[0]) _roots.pop_back(); _loaded = true; _built = true; _n_items = m; if (_verbose) annoylib_showUpdate("found %zu roots with degree %d\n", _roots.size(), m); return true; } T get_distance(S i, S j) const { return D::normalized_distance(D::distance(_get(i), _get(j), _f)); } void get_nns_by_item(S item, size_t n, int search_k, vector* result, vector* distances) const { // TODO: handle OOB const Node* m = _get(item); _get_all_nns(m->v, n, search_k, result, distances); } void get_nns_by_vector(const T* w, size_t n, int search_k, vector* result, vector* distances) const { _get_all_nns(w, n, search_k, result, distances); } S get_n_items() const { return _n_items; } S get_n_trees() const { return (S)_roots.size(); } void verbose(bool v) { _verbose = v; } void get_item(S item, T* v) const { // TODO: handle OOB Node* m = _get(item); memcpy(v, m->v, (_f) * sizeof(T)); } void set_seed(R seed) { _seed = seed; } void thread_build(int q, int thread_idx, ThreadedBuildPolicy& threaded_build_policy) { // Each thread needs its own seed, otherwise each thread would be building the same tree(s) Random _random(_seed + thread_idx); vector thread_roots; while (1) { if (q == -1) { threaded_build_policy.lock_n_nodes(); if (_n_nodes >= 2 * _n_items) { threaded_build_policy.unlock_n_nodes(); break; } threaded_build_policy.unlock_n_nodes(); } else { if (thread_roots.size() >= (size_t)q) { break; } } if (_verbose) annoylib_showUpdate("pass %zd...\n", thread_roots.size()); vector indices; threaded_build_policy.lock_shared_nodes(); for (S i = 0; i < _n_items; i++) { if (_get(i)->n_descendants >= 1) { // Issue #223 indices.push_back(i); } } threaded_build_policy.unlock_shared_nodes(); thread_roots.push_back(_make_tree(indices, true, _random, threaded_build_policy)); } threaded_build_policy.lock_roots(); _roots.insert(_roots.end(), thread_roots.begin(), thread_roots.end()); threaded_build_policy.unlock_roots(); } protected: void _reallocate_nodes(S n) { const double reallocation_factor = 1.3; S new_nodes_size = std::max(n, (S) ((_nodes_size + 1) * reallocation_factor)); void *old = _nodes; if (_on_disk) { if (!remap_memory_and_truncate(&_nodes, _fd, static_cast(_s) * static_cast(_nodes_size), static_cast(_s) * static_cast(new_nodes_size)) && _verbose) annoylib_showUpdate("File truncation error\n"); } else { _nodes = realloc(_nodes, _s * new_nodes_size); memset((char *) _nodes + (_nodes_size * _s) / sizeof(char), 0, (new_nodes_size - _nodes_size) * _s); } _nodes_size = new_nodes_size; if (_verbose) annoylib_showUpdate("Reallocating to %d nodes: old_address=%p, new_address=%p\n", new_nodes_size, old, _nodes); } void _allocate_size(S n, ThreadedBuildPolicy& threaded_build_policy) { if (n > _nodes_size) { threaded_build_policy.lock_nodes(); _reallocate_nodes(n); threaded_build_policy.unlock_nodes(); } } void _allocate_size(S n) { if (n > _nodes_size) { _reallocate_nodes(n); } } Node* _get(const S i) const { return get_node_ptr(_nodes, _s, i); } double _split_imbalance(const vector& left_indices, const vector& right_indices) { double ls = (float)left_indices.size(); double rs = (float)right_indices.size(); float f = ls / (ls + rs + 1e-9); // Avoid 0/0 return std::max(f, 1-f); } S _make_tree(const vector& indices, bool is_root, Random& _random, ThreadedBuildPolicy& threaded_build_policy) { // The basic rule is that if we have <= _K items, then it's a leaf node, otherwise it's a split node. // There's some regrettable complications caused by the problem that root nodes have to be "special": // 1. We identify root nodes by the arguable logic that _n_items == n->n_descendants, regardless of how many descendants they actually have // 2. Root nodes with only 1 child need to be a "dummy" parent // 3. Due to the _n_items "hack", we need to be careful with the cases where _n_items <= _K or _n_items > _K if (indices.size() == 1 && !is_root) return indices[0]; if (indices.size() <= (size_t)_K && (!is_root || (size_t)_n_items <= (size_t)_K || indices.size() == 1)) { threaded_build_policy.lock_n_nodes(); _allocate_size(_n_nodes + 1, threaded_build_policy); S item = _n_nodes++; threaded_build_policy.unlock_n_nodes(); threaded_build_policy.lock_shared_nodes(); Node* m = _get(item); m->n_descendants = is_root ? _n_items : (S)indices.size(); // Using std::copy instead of a loop seems to resolve issues #3 and #13, // probably because gcc 4.8 goes overboard with optimizations. // Using memcpy instead of std::copy for MSVC compatibility. #235 // Only copy when necessary to avoid crash in MSVC 9. #293 if (!indices.empty()) memcpy(m->children, &indices[0], indices.size() * sizeof(S)); threaded_build_policy.unlock_shared_nodes(); return item; } threaded_build_policy.lock_shared_nodes(); vector children; for (size_t i = 0; i < indices.size(); i++) { S j = indices[i]; Node* n = _get(j); if (n) children.push_back(n); } vector children_indices[2]; Node* m = (Node*)alloca(_s); for (int attempt = 0; attempt < 3; attempt++) { children_indices[0].clear(); children_indices[1].clear(); D::create_split(children, _f, _s, _random, m); for (size_t i = 0; i < indices.size(); i++) { S j = indices[i]; Node* n = _get(j); if (n) { bool side = D::side(m, n->v, _f, _random); children_indices[side].push_back(j); } else { annoylib_showUpdate("No node for index %d?\n", j); } } if (_split_imbalance(children_indices[0], children_indices[1]) < 0.95) break; } threaded_build_policy.unlock_shared_nodes(); // If we didn't find a hyperplane, just randomize sides as a last option while (_split_imbalance(children_indices[0], children_indices[1]) > 0.99) { if (_verbose) annoylib_showUpdate("\tNo hyperplane found (left has %zu children, right has %zu children)\n", children_indices[0].size(), children_indices[1].size()); children_indices[0].clear(); children_indices[1].clear(); // Set the vector to 0.0 for (int z = 0; z < _f; z++) m->v[z] = 0; for (size_t i = 0; i < indices.size(); i++) { S j = indices[i]; // Just randomize... children_indices[_random.flip()].push_back(j); } } int flip = (children_indices[0].size() > children_indices[1].size()); m->n_descendants = is_root ? _n_items : (S)indices.size(); for (int side = 0; side < 2; side++) { // run _make_tree for the smallest child first (for cache locality) m->children[side^flip] = _make_tree(children_indices[side^flip], false, _random, threaded_build_policy); } threaded_build_policy.lock_n_nodes(); _allocate_size(_n_nodes + 1, threaded_build_policy); S item = _n_nodes++; threaded_build_policy.unlock_n_nodes(); threaded_build_policy.lock_shared_nodes(); memcpy(_get(item), m, _s); threaded_build_policy.unlock_shared_nodes(); return item; } void _get_all_nns(const T* v, size_t n, int search_k, vector* result, vector* distances) const { Node* v_node = (Node *)alloca(_s); D::template zero_value(v_node); memcpy(v_node->v, v, sizeof(T) * _f); D::init_node(v_node, _f); std::priority_queue > q; if (search_k == -1) { search_k = n * _roots.size(); } for (size_t i = 0; i < _roots.size(); i++) { q.push(make_pair(Distance::template pq_initial_value(), _roots[i])); } std::vector nns; while (nns.size() < (size_t)search_k && !q.empty()) { const pair& top = q.top(); T d = top.first; S i = top.second; Node* nd = _get(i); q.pop(); if (nd->n_descendants == 1 && i < _n_items) { nns.push_back(i); } else if (nd->n_descendants <= _K) { const S* dst = nd->children; nns.insert(nns.end(), dst, &dst[nd->n_descendants]); } else { T margin = D::margin(nd, v, _f); q.push(make_pair(D::pq_distance(d, margin, 1), static_cast(nd->children[1]))); q.push(make_pair(D::pq_distance(d, margin, 0), static_cast(nd->children[0]))); } } // Get distances for all items // To avoid calculating distance multiple times for any items, sort by id std::sort(nns.begin(), nns.end()); vector > nns_dist; S last = -1; for (size_t i = 0; i < nns.size(); i++) { S j = nns[i]; if (j == last) continue; last = j; if (_get(j)->n_descendants == 1) // This is only to guard a really obscure case, #284 nns_dist.push_back(make_pair(D::distance(v_node, _get(j), _f), j)); } size_t m = nns_dist.size(); size_t p = n < m ? n : m; // Return this many items std::partial_sort(nns_dist.begin(), nns_dist.begin() + p, nns_dist.end()); for (size_t i = 0; i < p; i++) { if (distances) distances->push_back(D::normalized_distance(nns_dist[i].first)); result->push_back(nns_dist[i].second); } } }; class AnnoyIndexSingleThreadedBuildPolicy { public: template static void build(AnnoyIndex* annoy, int q, int n_threads) { AnnoyIndexSingleThreadedBuildPolicy threaded_build_policy; annoy->thread_build(q, 0, threaded_build_policy); } void lock_n_nodes() {} void unlock_n_nodes() {} void lock_nodes() {} void unlock_nodes() {} void lock_shared_nodes() {} void unlock_shared_nodes() {} void lock_roots() {} void unlock_roots() {} }; #ifdef ANNOYLIB_MULTITHREADED_BUILD class AnnoyIndexMultiThreadedBuildPolicy { private: std::shared_timed_mutex nodes_mutex; std::mutex n_nodes_mutex; std::mutex roots_mutex; public: template static void build(AnnoyIndex* annoy, int q, int n_threads) { AnnoyIndexMultiThreadedBuildPolicy threaded_build_policy; if (n_threads == -1) { // If the hardware_concurrency() value is not well defined or not computable, it returns 0. // We guard against this by using at least 1 thread. n_threads = std::max(1, (int)std::thread::hardware_concurrency()); } vector threads(n_threads); for (int thread_idx = 0; thread_idx < n_threads; thread_idx++) { int trees_per_thread = q == -1 ? -1 : (int)floor((q + thread_idx) / n_threads); threads[thread_idx] = std::thread( &AnnoyIndex::thread_build, annoy, trees_per_thread, thread_idx, std::ref(threaded_build_policy) ); } for (auto& thread : threads) { thread.join(); } } void lock_n_nodes() { n_nodes_mutex.lock(); } void unlock_n_nodes() { n_nodes_mutex.unlock(); } void lock_nodes() { nodes_mutex.lock(); } void unlock_nodes() { nodes_mutex.unlock(); } void lock_shared_nodes() { nodes_mutex.lock_shared(); } void unlock_shared_nodes() { nodes_mutex.unlock_shared(); } void lock_roots() { roots_mutex.lock(); } void unlock_roots() { roots_mutex.unlock(); } }; #endif } #endif // vim: tabstop=2 shiftwidth=2 RcppAnnoy/inst/include/RcppAnnoy.h0000644000176200001440000000336414553605723016665 0ustar liggesusers// Emacs make this -*- mode: C++; -*- // RcppAnnoy // // R bindings for the 'Annoy' Approximate Nearest Neighbor Library #ifndef RCPPANNOY_H #define RCPPANNOY_H // -- include Rcpp headers #define R_NO_REMAP #define STRICT_R_HEADERS #include // -- define a few things needed for Annoy #if defined(__MINGW32__) #undef Realloc #undef Free #endif // define R's REprintf as the 'local' error print method for Annoy #define __ERROR_PRINTER_OVERRIDE__ REprintf #include "annoylib.h" #include "kissrandom.h" // -- some version housekeeping not provided by Annoy #define ANNOY_VERSION_MAJOR 1 #define ANNOY_VERSION_MINOR 17 #define ANNOY_VERSION_PATCH 3 // create a single 'comparable' number out of version, minor and patch #define Annoy_Version(v,m,p) (((v) * 65536) + ((m) * 256) + (p)) // current build is encoded in ANNOY_VERSION #define ANNOY_VERSION Annoy_Version(ANNOY_VERSION_MAJOR,ANNOY_VERSION_MINOR,ANNOY_VERSION_PATCH) // -- same for RcppAnnoy #define RCPPANNOY_VERSION_MAJOR 0 #define RCPPANNOY_VERSION_MINOR 0 #define RCPPANNOY_VERSION_PATCH 22 #define RCPPANNOY_VERSION_MICRO 0 #define RcppAnnoyVersion(maj, min, rev, dev) (((maj)*1000000) + ((min)*10000) + ((rev)*100) + (dev)) #define RCPPANNOY_VERSION RcppAnnoyVersion(RCPPANNOY_VERSION_MAJOR,RCPPANNOY_VERSION_MINOR,RCPPANNOY_VERSION_PATCH,RCPP_ANNOY_VERSION_MICRO) // -- convenience typedefs // prefixed with Rcpp to ensure we are most unlikely to clash with upstream defines // usage of these is entire optional #ifdef ANNOYLIB_MULTITHREADED_BUILD typedef Annoy::AnnoyIndexMultiThreadedBuildPolicy RcppAnnoyIndexThreadPolicy; #else typedef Annoy::AnnoyIndexSingleThreadedBuildPolicy RcppAnnoyIndexThreadPolicy; #endif #endif RcppAnnoy/inst/tinytest/0000755000176200001440000000000013756552014015033 5ustar liggesusersRcppAnnoy/inst/tinytest/data/0000755000176200001440000000000013465550702015743 5ustar liggesusersRcppAnnoy/inst/tinytest/data/test.tree0000644000176200001440000004461013465550702017610 0ustar liggesusers>?O>a8վ+x2;w? r[?vVz?| sT7>^C>3>L8?ɺUE!=?]=A>o?׿1UD A>V>i.<\;┿pњ}Ҋj鿫v^ j>?2T?M?'OV45@\?@Q e?5?<= &#?Q?{?iҾI?{Z忏??⼟]?-'?8%>Ԛ:o>\??bZ~ؾ>B` Pgmc?֤>6x??ޒ??z2 ?vUp?s? $>:?&$) >:=>>QN?ۿh}>0B?qLp>BI?k^>q(u?ޜ%>P%-K?@)B=5@Ym>yn>̔1>+-T+N? ?K{=kE>)=ntq?= N>#>e?ܻTu?e"=ܺ>< >EV{R{?#>?v>z{,=(?=E=D?ˎc~?D?a%濨4?-S tо~5(9)?)m>f>=␾$$̜پ?\?yCc=߉*ג>T>[@X> ?2/SKo->> =6?h,%?1ܿC(>IzffuBo-Կ I?(ҿ g>蝎?@]?s.?HBK>9?Kd- ??q[`?A{F?W @q>Mtal(W=n?R,?UqT͗ -R?⳿C7@phh?t>1>V?>8\?͓@褁=?t??:"T>@Y<,ǿ>??x6xþ>@gO>G?sm d==?7U"RB?x @LL *C?=T?#Y??iT >Zt? UjB?$""Of@!?-9oC`{?5=#? Yf>>jO @Ŀ>+p)VF>/|?E˽bz\?iɿ1}f>}aٿ*/o=$?bvɽҬ,?W=jLU?~qv? "r?>?e ?Ǔ@?ah^81?!s?J_)?-ξ݌?I+>G ¿:毲>̍?40?ж\jݮ:>W?3?l?>@ھ>B~0>)S= ?k?5K =v?J=*2ۿ`B?>d^UܿS[?v>Htk2h_@ɠ~Y=[\i:??n?{?bò>㳿biyqs?$)Ć?>`=c<0?sojg?*J?rfxT?'4>8M >y<q|.i?F79>wܾmKg> +?7r> 6>[ >ɪTU5?'?}}IokZ?@yKt?a?=?"U>: >jd?܈>Np??Mv;Ay*>f%AK?q+]?ϔ?V?^S[a*ayUa??>R>;NP?mƿMe,s>Z6þ{?8,)oUL4?!3>wzx?">=%??F2MM\?V_ƀO?Dd? ?)U uDZ~naF?f:?mDb?fkֿ\R?mB?Ͼ42 @(&>X-hSC? FQChj!"@ݬMh?>>ɑL0ռ(?x(?e@v=Ȣ?Yg=s?ܿ8ÞR}M?ys~ó?Ad˶6w??>lۂ>\sx[#!&ן=2#-?M?j>_+?4̽*doK>zȥb?νSQ?ty?w9>a4@r@T@4Xؾ8?x~d?ȗCK/>Ͽ ?K?پ?XF? =>?R?^ο`?;S^??g?@yn? `?oi?L!?3q惿2?{ ?=F=Av?h]?#=(?٭>bb?,> ȿQ?6=~!=/R&>.{>?>?޿A>X?7>/§?>s}?e=V!P{ƾ}B*>O=i:7?A<?a:^ _!/?: ϗyI<̿I1f[>j9.6.-?# A?\L?>{>_zXMk۾Y)<Ƿ?IV<{v>Ma$@ʰ?Yw"99>KAžO?5=&Z?.?Ů>? l?&3k>r񿧘,S?ڳ&ڎܼ}rcmǾƽA4=nZ3?)xH?f.?yJU>4?S" >ȆS?6Y?/?Kw>T0?򒗿u_vĿ"@?z<>Gb$?L n?@?stތ m4#W?X ?aZ>C:|]/%>{`#4+>쿺>P?8!?>1>?=.@[K:^a=m?b?#??cϾh=,S hB?U%>h@o߾ ` ި?lKWlտc?8=Z?yd/ ?Y?>5myo]?n>W?5?8b~a>࿁?{??E'X>yJ|\=c̍?͟k ?%?҇?߷?-\>ߚ>`!0o=<?y@Yu? rGVդ?RZ۾D?Ntֽj~17S$L><Ҿ֠)T?t@Ĉ|X̛N?ed?*m#!=܌6der8{=e *>q? ?92>׽+p* :5fi_@>F>Z=ʌ *Z?S%>8ֽgh!k>ܳ>%9?;k Ż=6 ;+x/==eU  #'+283@AOV%jk?< <=>kC>pa4t>Cٽ &146T[lo!Yk>w=>BL>\^Y᥾mn=Q(@km>+jR/%>> */;EU\b-57BLpq'罓˾J>i$=g)>>/=?>?MPQa !%KRXY`/sxc> ba{_:Q>=±>S>=twSo >J>(<]k^=>k> g,?uv:Jcy~ ?7¼5>/>Ĉ>>z{:A;8N>(N>BS(}< [= $9CFS|}q|;}>logڽw~ႾMY>1 ()G  ".:=^ZdN>r@AxlV>>>fI>Q]?5O>}{B}A>(=p;K=VC> ~>q= g>W>Հ_0f^= &*?MPUXbg=^>s\- O>?v"2;_ ,.BDQ[c0z}?%OyپrEB'>1>տ1̾=W)?9K=ϤY> -4:ENRTY\%9K`'/CHOVZa/>= ?=~Xq?žwpo=='oZY2̜Lo>7"^¾ lD4ᾝ$> ?>9=ݮ>> D iJ>+ď>  <JL  +F]^ !$1W'>蟢Ⱦ#Ž߲>, (?W>DѾΝ> `>NJ1>p4%?NK!&=:W=F%涽=R #6=>AI(57 )038@GSd5R>Cޅ>>l>bʻ= >,0߾M>>,l>??ol7> >G>>X> >xg=wٽ8fyW3dh(&>Ã>  <CDPVa^'>d&}FKAd]>;þcҊ> */?OU38@AM$?:>ö;=H@><>(> >^%=#?  '2W]c OK/>>u=#>;F>h \=y*WE<#)+>GI&(5J_4m=-о9)?v> MK!BE=.>D> >[@d;JQ'>~V|>_>s>.9QZ.xY>im>N!?Ru> L۽Ͼ yT>~= $6=KLT ,07:HS,=8>=LJ>p? >| =h ;?TO>  "1;FN[^>?d7 1zj4¼tRSj = (W!+τ>z 뾆6f>?nS !B %-4ERX`bY\dM >H>^8\o>MF=Ho>t(>.;ۚ>3`v)=)})[a=ꤾA >ˇ*> KS >eᘾ傼L7X'==>$=+qԀ½=@v=_cz۾2? >F]_ '2<GJNW^",9V>J-[=gX>Ǿ23Vd;y #+11=>SYb=!# =0< I>>X  $()DI0:=H6>GO>9=`> >FB>D =91?ˎоT2>)*b.^ >j>chܬ߾Q> 8>{>#J>.J>}BrTg>>F>yE\s>CF8f= %-CMY`c !57;?@L\7 XD= ̊NQOj=J$?Zx>hb> ?%>?>g9п *.KQRSX4BU[b TR#7?d8>Uy)>L>F7ؾO>q3=-5>ӵ &/368AEOPad" X/2P=*1D0\2.+QYt'>B\",>9-?Q?h=*>پxm*=μ$n=YJo'>c>2;?NW5Y^_c|Zݼ9"> ߽:B<>|W?<?zY{l?z>tֽz;.3=?Q(.GR ,7>KMUZ` "*BCQX !/9:S1֩>j>=x(L?V)C:">3>>E=}ü4]$?>9ؾF[=5>=kT=})gD>= )&  $'DJP]a >Nї><P>cK>?[*=f׾<%4OV[\b 038<AE>QB)?tZ>4뼬`CV%J>u?=  #+-1=IL )6@FHTd?5 R>)肾_>Oc=N>rk>᪾;<c5>gk>a=&3>#?3>A>}>aB4>I:ꮽ:.>$(#=&+IT쓹= |v#=C>>p*?2>0== #=BN > ?f׾~>&g=\b!>=c^>3= '1DJR["4PQX\b K美>Oz6lս&H>`ʽ(rL{'-?Гb>?pv=\ݎ>H=¾7> %(6:YZ^`*5OUck >UC>_$)>se>)?q{<C>-.2KM ,7;(͎>P>?d:>.5?-۾}g>Eb?>ؾdv>>aP$9a/?CEV]>ʽU>rbj2j}z[!"L̽a0k=zw>x>>7>+0x>3o>'>K\=s <q>]=>1B?W_ !)<>FGS038@AHdڟľB>=>Q\gL>㇙>D?>4}u/4?Q>">->R?h>(7T= >I> ,n}҂= >\~C=b t>6ͼr=4T@S?u > . -.5KMSY`c %36U!79Z4T?倽gkJ$Ͻq*>,35P>'> ;Nm?:BY>;M=7)>ey#(Gt=1Ћ<} >c.>n>m=>=3>> 0:@HTW^ )IL5+b=>:Hv>h ȾFо:= 𽷇 UXs &L;4U$Q?=>l> )K>BE  >4r\⾄L%>z$>)>p1P6 FJ   |>+ykxt>x>`>kܽ=Ƹ2?C "$+18<=>]=3> >k=ʉ%>Y>ϙ>]>'%>ga†=F8a>+`DV_ *,OQX[43Oa>P 5$hS>J$潉<>/4A\ab &'PRd! *婾pۼn=YC˾o !%?EZ>(ƴCd?3=?lV߽DA>¾>Խ>d=ܒQt;IF> H]> ?˲>'%;#i=U'i~<[_\='<D $)0:@IL i=ATYܽ`>*1=FGBZ=?UW=H>>þ!3=d>>(p?"QW_  8AFTaE<"%֐X*A-' >T>%+&[?Wp#$?H;\y\z>eH?Ƚ>=V=  .17Sc#(,5;G*&+uHo,IK-lj8>;u'(]i߾3Ymﵾnо>=ż= \>!/B)*VV{۾#<->Ze=B=(yɽ,IX> &?U 3Y^`,-M=r!=D7=n c46NZ./ _>WE=d5#=EԮ: ?Mžc%-KMRX\ *+2CJOPV[bd1>$.- 8A>ۛ6ৼTa>%>229 >L>!> dW{`⾿Q3=sdɾRS38'w'ML X;נ/ +Hi'Ͼ45i#?μ =g>>XI>a>6q9>A[>=(67$v>>32>< pw !7FS5=>B"KL:==NJ>2$o>Su% >c_>r>8 ?;<~/%dDq7>>=ns&{μ>bv/0;@ ,9:EQTXZ\ 6HUY_2?B*Nm=2l>wt/(i?Ʀ޾a@Ais>OJc>i>0JT(Q]+?\S>|r=).<G^%*34IOV$CFM<ȫ/ ;[>}:==s rP<0>DE(O4[jWT>-wcCřLk>&]b 28?ACJP[aGH7>;<Ҿ=?ʾ&P>vͼF8H>$=Ժ= DMNWc   #$'+-1R`dJQs> (\>z>„U쾤>$K=2Ӿ)KNf>VH=$>LM1>=+!f>7ARý%8>ϋ(86 z^>  "5BXZ )79;STW^OP=z5=$c>?0I>m>J姼 &*+?QUY_ (.28GMc;R]\ݼ>ᖾ彘?>iu>)r>i:?-SZ:- >S9J=ǧĽ4>=9fl?TW>F>z&4>P>o9>U>,OUV]4.<݅>x((?ᖾ<2;>y>M>Β=!%/0KL-E\`aXYNh>:`${.ɽҜ=.*ДƊE[a% =FHPVb 1:N[\Q>;> ?2ӭ)>>:>0B $'@A[,<>C]^_M;h~>ԨndE c{o=p>='4 #36I 4DJORder8{=e *>q? ?92>׽+p* :dN>r@AxlV>>>fI>Q]?d5R>Cޅ>>l>bʻ= >,dM >H>^8\o>MF=Ho>t(>d" X/2)肾_>Oc=N>rk>᪾;dڟľB>=>Q\gL>㇙>D?>4}ud! *婾pۼn=YC˾o !%?EZ>d1>$.- 8A>ۛ6ৼTa>%>dJQs> (\>z>„U쾤>$K=2ӾRcppAnnoy/inst/tinytest/testIndex.R0000644000176200001440000000215113541674477017136 0ustar liggesusers ## if this is set (eg .travis.yml) then run the test if (Sys.getenv("RunAllRcppAnnoyTests") != "yes") exit_file("Skip this test") suppressMessages(library(RcppAnnoy)) a <- new(AnnoyAngular, 10) a$load(system.file("tinytest", "data", "test.tree", package="RcppAnnoy")) ## This might change in the future if we change the search ## algorithm, but in that case let's update the test checkEqual(a$getNNsByItem(0, 10), c(0, 85, 42, 11, 54, 38, 53, 66, 19, 31), msg="check loaded index") a <- new(AnnoyEuclidean, 10) v <- rnorm(10) expect_error(a$addItem(-2, v))#, msg="check negative index", silent=TRUE) expect_error(a$addItem(NA, v))#, msg="check NA index", silent=TRUE) ## modeled after annoy_test.py() and its t i <- new(AnnoyAngular, 10) i$load(system.file("tinytest", "data", "test.tree", package="RcppAnnoy")) u <- i$getItemsVector(99) i$save(tempfile()) v <- i$getItemsVector(99) checkEqual(u, v, msg="getItemVector comparison") j <- new(AnnoyAngular, 10) j$load(system.file("tinytest", "data", "test.tree", package="RcppAnnoy")) w <- i$getItemsVector(99) checkEqual(u, w, msg="getItemVector comparison") RcppAnnoy/inst/tinytest/testVignette.R0000644000176200001440000000130613756552014017643 0ustar liggesusers ## See #66 for the idea and discussion vigfile <- system.file("rmd", "UsingAnnoyInCpp.Rmd", package="RcppAnnoy") if (!file.exists(vigfile)) exit_file("No vignette source found. What's up with that?") lines <- readLines(vigfile) starts <- which(lines == "```{Rcpp, eval=FALSE}") ends <- which(lines=="```") ends <- ends[findInterval(starts, ends)+1] code <- lines[unlist(mapply(seq, starts+1, ends-1))] res <- Rcpp::sourceCpp(code=paste(code, collapse="\n")) # checks everything is compileable. expect_equal(res$functions, "thingy") # check we got a function compiled set.seed(42) mat <- matrix(runif(1000), 100) Q <- matrix(runif(100), 10) res <- thingy(mat, 1, 10, Q, tempfile()) expect_equal(res, 1) RcppAnnoy/inst/tinytest/testOnDiskBuild.R0000644000176200001440000000211213541674477020233 0ustar liggesusers suppressMessages(library(RcppAnnoy)) f <- 2 # arbitrary a <- new(AnnoyEuclidean, f) diskfile <- tempfile(pattern="annoy", fileext="bin") expect_true(a$onDiskBuild(diskfile)) a$addItem(0, c(2, 2)) a$addItem(1, c(3, 2)) a$addItem(2, c(3, 3)) a$build(10) expect_equal(a$getNNsByVector(c(4,4), 3), c(2,1,0)) #, msg="getNNsByVector check 1") expect_equal(a$getNNsByVector(c(1,1), 3), c(0,1,2)) #, msg="getNNsByVector check 2") expect_equal(a$getNNsByVector(c(5,3), 3), c(2,1,0)) #, msg="getNNsByVector check 3") a$unload() a$load(diskfile) expect_equal(a$getNNsByVector(c(4,4), 3), c(2,1,0)) #, msg="getNNsByVector check 1") expect_equal(a$getNNsByVector(c(1,1), 3), c(0,1,2)) #, msg="getNNsByVector check 2") expect_equal(a$getNNsByVector(c(5,3), 3), c(2,1,0)) #, msg="getNNsByVector check 3") b <- new(AnnoyEuclidean, f) b$load(diskfile) expect_equal(b$getNNsByVector(c(4,4), 3), c(2,1,0)) #, msg="getNNsByVector check 1") expect_equal(b$getNNsByVector(c(1,1), 3), c(0,1,2)) #, msg="getNNsByVector check 2") expect_equal(b$getNNsByVector(c(5,3), 3), c(2,1,0)) #, msg="getNNsByVector check 3") RcppAnnoy/inst/tinytest/testSeeds.R0000644000176200001440000000152313743414424017120 0ustar liggesusers ## if this is set (eg .travis.yml) then run the test if (Sys.getenv("RunAllRcppAnnoyTests") != "yes") exit_file("Skip this test") suppressMessages(library(RcppAnnoy)) f <- 2 set.seed(123456) # R Seed for next two vectors n <- 100 x <- rnorm(n) y <- rnorm(n) v1 <- new(AnnoyHamming, f) v1$setSeed(123) for (i in 1:n) v1$addItem(i-1, c(x[i], y[i])) v1$build(f) v2 <- new(AnnoyHamming, f) v2$setSeed(456) # different for (i in 1:n) v2$addItem(i-1, c(x[i], y[i])) v2$build(f) v3 <- new(AnnoyHamming, f) v3$setSeed(123) # as first for (i in 1:n) v3$addItem(i-1, c(x[i], y[i])) v3$build(f) checkEqual(v1$getNNsByVector(c(0.5,0.5), 20), v3$getNNsByVector(c(0.5,0.5), 20)) # msg="v1 and v3 are equal") checkTrue(any(v1$getNNsByVector(c(0.5,0.5), 20) != v2$getNNsByVector(c(0.5,0.5), 20))) # msg="v1 and v2 are not equal") RcppAnnoy/inst/tinytest/testAngular.R0000644000176200001440000000374213465550702017454 0ustar liggesusers suppressMessages(library(RcppAnnoy)) f <- 3 a <- new(AnnoyAngular, f) a$addItem(0, c(0,0,1)) a$addItem(1, c(0,1,0)) a$addItem(2, c(1,0,0)) a$build(10) checkEqual(a$getNNsByVector(c(3,2,1), 3), c(2,1,0), msg="getNNsByVector check 1") checkEqual(a$getNNsByVector(c(1,2,3), 3), c(0,1,2), msg="getNNsByVector check 1") checkEqual(a$getNNsByVector(c(2,0,1), 3), c(2,0,1), msg="getNNsByVector check 1") f <- 3 a <- new(AnnoyAngular, f) a$addItem(0, c(2,1,0)) a$addItem(1, c(1,2,0)) a$addItem(2, c(0,0,1)) a$build(10) checkEqual(a$getNNsByItem(0, 3), c(0,1,2), msg="getNNsByItem check1") checkEqual(a$getNNsByItem(1, 3), c(1,0,2), msg="getNNsByItem check2") f <- 2 a <- new(AnnoyAngular, f) a$addItem(0, c(0, 1)) a$addItem(1, c(1, 1)) checkEqual(a$getDistance(0, 1), (2.0 * (1.0 - 2^(-0.5)))^0.5, msg="distance 1", tolerance=1e-6) f <- 2 a <- new(AnnoyAngular, f) a$addItem(0, c(1000, 0)) a$addItem(1, c(10, 0)) checkEqual(a$getDistance(0, 1), 0, msg="distance 2") f <- 2 a <- new(AnnoyAngular, f) a$addItem(0, c(97, 0)) a$addItem(1, c(42, 42)) d <- ((1 - 2^(-0.5))^2 + (2^(-0.5))^2)^0.5 checkEqual(a$getDistance(0, 1), d, msg="distance 3", tolerance=1.0e-6) f <- 2 a <- new(AnnoyAngular, f) a$addItem(0, c(1, 0)) a$addItem(1, c(0, 0)) checkEqual(a$getDistance(0, 1), 2.0^0.5, msg="distance 4", tolerance=1.0e-6) ## Generate pairs of random points where the pair is super close f <- 10 a <- new(AnnoyAngular, f) set.seed(123) for (j in seq(0, 10000, by=2)) { p <- rnorm(f) f1 <- runif(1) + 1 f2 <- runif(1) + 1 x <- f1 * p + rnorm(f, 0, 1.0e-2) y <- f2 * p + rnorm(f, 0, 1.0e-2) a$addItem(j, x) a$addItem(j+1, y) } a$build(10) res <- TRUE for (j in seq(0, 10000, by=2)) { #expect_equal(a$getNNsByItem(j, 2), c(j, j+1), msg="getNNsByItem check1") #expect_equal(a$getNNsByItem(j+1, 2), c(j+1, j), msg="getNNsByItem check1") res <- res && all.equal(a$getNNsByItem(j, 2), c(j, j+1)) && all.equal(a$getNNsByItem(j+1, 2), c(j+1, j)) } checkTrue(res) RcppAnnoy/inst/tinytest/testEuclidean.R0000644000176200001440000000506113465550702017750 0ustar liggesusers suppressMessages(library(RcppAnnoy)) ## getNNsByVector f <- 2 a <- new(AnnoyEuclidean, f) a$addItem(0, c(2, 2)) a$addItem(1, c(3, 2)) a$addItem(2, c(3, 3)) a$build(10) checkEqual(a$getNNsByVector(c(4,4), 3), c(2,1,0), msg="getNNsByVector check 1") checkEqual(a$getNNsByVector(c(1,1), 3), c(0,1,2), msg="getNNsByVector check 1") checkEqual(a$getNNsByVector(c(4,2), 3), c(1,2,0), msg="getNNsByVector check 1") ## getNNsByItem f <- 2 a <- new(AnnoyEuclidean, f) a$addItem(0, c(2, 2)) a$addItem(1, c(3, 2)) a$addItem(2, c(3, 3)) a$build(10) checkEqual(a$getNNsByItem(0, 3), c(0, 1, 2), msg="getNNsByItem check 1") checkEqual(a$getNNsByItem(2, 3), c(2, 1, 0), msg="getNNsByItem check 2") ### test03dist f <- 2 a <- new(AnnoyEuclidean, f) a$addItem(0, c(0, 1)) a$addItem(1, c(1, 1)) a$addItem(2, c(0, 0)) checkEqual(a$getDistance(0, 1), 1.0^0.5, msg="distance 1") checkEqual(a$getDistance(1, 2), 2.0^0.5, msg="distance 2", tolerance=1e-6) ## test04largeIndex ## Generate pairs of random points where the pair is super close f <- 10 #q <- rnorm(f, 0, 10) a <- new(AnnoyEuclidean, f) set.seed(123) for (j in seq(0, 10000, by=2)) { p <- rnorm(f) x <- 1 + p + rnorm(f, 0, 1.0e-2) y <- 1 + p + rnorm(f, 0, 1.0e-2) a$addItem(j, x) a$addItem(j+1, y) } a$build(10) res <- TRUE for (j in seq(0, 10000, by=2)) { #expect_equal(a$getNNsByItem(j, 2), c(j, j+1), msg="getNNsByItem check1") #expect_equal(a$getNNsByItem(j+1, 2), c(j+1, j), msg="getNNsByItem check1") res <- res && all.equal(a$getNNsByItem(j, 2), c(j, j+1)) && all.equal(a$getNNsByItem(j+1, 2), c(j+1, j)) } expect_true(res) ## test05precision precision <- function(n, nTrees=10, nPoints=10000, nRounds=3) { found <- 0 for (r in 1:nRounds) { ## create random points at distance x f <- 10 a <- new(AnnoyEuclidean, f) for (j in seq(nPoints)) { p <- rnorm(f, 0, 1) nrm <- sqrt(sum(p^2)) x <- p / nrm * j a$addItem(j, x) } a$build(nTrees) nns <- a$getNNsByVector(rep(0, f), n) checkEqual(nns, nns[order(nns)], msg="checking precision order") # should be in order ## The number of gaps should be equal to the last item minus n-1 found <- found + length(nns[ nns <= n]) } return(1.0 * found / (n * nRounds)) } checkTrue(precision(1) >= 0.98)#, msg="precision at 1") checkTrue(precision(10) >= 0.98)#, msg="precision at 10") checkTrue(precision(100) >= 0.98)#, msg="precision at 100") checkTrue(precision(1000) >= 0.98)#, msg="precision at 1000") RcppAnnoy/inst/tinytest/testHamming.R0000644000176200001440000000527113465550702017442 0ustar liggesusers suppressMessages(library(RcppAnnoy)) # test01getNNsByVector f <- 2 a <- new(AnnoyHamming, f) a$addItem(0, c(2, 2)) a$addItem(1, c(3, 2)) a$addItem(2, c(3, 3)) a$build(10) checkEqual(a$getNNsByVector(c(4,4), 3), c(0,1,2), msg="getNNsByVector check 1") checkEqual(a$getNNsByVector(c(1,1), 3), c(2,1,0), msg="getNNsByVector check 2") checkEqual(a$getNNsByVector(c(5,3), 3), c(2,1,0), msg="getNNsByVector check 3") # test02getNNsByItem f <- 2 a <- new(AnnoyHamming, f) a$addItem(0, c(2, 2)) a$addItem(1, c(3, 2)) a$addItem(2, c(3, 3)) a$build(10) checkEqual(a$getNNsByItem(0, 3), c(0, 1, 2), msg="getNNsByItem check 1") checkEqual(a$getNNsByItem(2, 3), c(2, 1, 0), msg="getNNsByItem check 2") # test03dist f <- 2 a <- new(AnnoyHamming, f) a$addItem(0, c(0, 1)) a$addItem(1, c(1, 1)) a$addItem(2, c(0, 0)) checkEqual(a$getDistance(0, 1), 1.0, msg="distance 1")# checkEqual(a$getDistance(1, 2), 2.0, msg="distance 2")# ## test04largeIndex <- function() { ## ## Generate pairs of random points where the pair is super close ## f <- 10 ## #q <- rnorm(f, 0, 10) ## a <- new(AnnoyHamming, f) ## set.seed(123) ## for (j in seq(0, 10000, by=2)) { ## p <- rnorm(f) ## x <- 1 + p + rnorm(f, 0, 1.0e-2) ## y <- 1 + p + rnorm(f, 0, 1.0e-2) ## a$addItem(j, x) ## a$addItem(j+1, y) ## } ## a$build(10) ## for (j in seq(0, 10000, by=2)) { ## checkEquals(a$getNNsByItem(j, 2), c(j, j+1), msg="getNNsByItem check 1") ## checkEquals(a$getNNsByItem(j+1, 2), c(j+1, j), msg="getNNsByItem check 2") ## } ## } ## test05precision <- function() { ## precision <- function(n, nTrees=10, nPoints=10000, nRounds=3) { ## found <- 0 ## for (r in 1:nRounds) { ## ## create random points at distance x ## f <- 10 ## a <- new(AnnoyHamming, f) ## for (j in seq(nPoints)) { ## p <- rnorm(f, 0, 1) ## nrm <- sqrt(sum(p^2)) ## x <- p / nrm + j ## a$addItem(j, x) ## } ## a$build(nTrees) ## nns <- a$getNNsByVector(rep(0, f), n) ## checkEquals(nns, nns[order(nns)], msg="checking precision order") # should be in order ## ## The number of gaps should be equal to the last item minus n-1 ## found <- found + length(nns[nns <= n]) ## } ## return(1.0 * found / (n * nRounds)) ## } ## checkTrue(precision(1) >= 0.98, msg="precision at 1") ## checkTrue(precision(10) >= 0.98, msg="precision at 10") ## checkTrue(precision(100) >= 0.98, msg="precision at 100") ## checkTrue(precision(1000) >= 0.98, msg="precision at 1000") ## } RcppAnnoy/inst/tinytest/testManhattan.R0000644000176200001440000000460113465550702017771 0ustar liggesusers suppressMessages(library(RcppAnnoy)) ## test01getNNsByVector f <- 2 a <- new(AnnoyManhattan, f) a$addItem(0, c(2, 2)) a$addItem(1, c(3, 2)) a$addItem(2, c(3, 3)) a$build(10) checkEqual(a$getNNsByVector(c(4,4), 3), c(2,1,0), msg="getNNsByVector check 1") checkEqual(a$getNNsByVector(c(1,1), 3), c(0,1,2), msg="getNNsByVector check 2") checkEqual(a$getNNsByVector(c(5,3), 3), c(2,1,0), msg="getNNsByVector check 3") ## test02getNNsByItem f <- 2 a <- new(AnnoyManhattan, f) a$addItem(0, c(2, 2)) a$addItem(1, c(3, 2)) a$addItem(2, c(3, 3)) a$build(10) checkEqual(a$getNNsByItem(0, 3), c(0, 1, 2), msg="getNNsByItem check 1") checkEqual(a$getNNsByItem(2, 3), c(2, 1, 0), msg="getNNsByItem check 2") ## test03dist f <- 2 a <- new(AnnoyManhattan, f) a$addItem(0, c(0, 1)) a$addItem(1, c(1, 1)) a$addItem(2, c(0, 0)) checkEqual(a$getDistance(0, 1), 1.0, msg="distance 1")# checkEqual(a$getDistance(1, 2), 2.0, msg="distance 2")# ## test04largeIndex ## Generate pairs of random points where the pair is super close f <- 10 ##q <- rnorm(f, 0, 10) a <- new(AnnoyManhattan, f) set.seed(123) for (j in seq(0, 10000, by=2)) { p <- rnorm(f) x <- 1 + p + rnorm(f, 0, 1.0e-2) y <- 1 + p + rnorm(f, 0, 1.0e-2) a$addItem(j, x) a$addItem(j+1, y) } a$build(10) res <- TRUE for (j in seq(0, 10000, by=2)) { res <- res && all.equal(a$getNNsByItem(j, 2), c(j, j+1)) && all.equal(a$getNNsByItem(j+1, 2), c(j+1, j)) } checkTrue(res) ## test05precision precision <- function(n, nTrees=10, nPoints=10000, nRounds=3) { found <- 0 for (r in 1:nRounds) { ## create random points at distance x f <- 10 a <- new(AnnoyManhattan, f) for (j in seq(nPoints)) { p <- rnorm(f, 0, 1) nrm <- sqrt(sum(p^2)) x <- p / nrm + j a$addItem(j, x) } a$build(nTrees) nns <- a$getNNsByVector(rep(0, f), n) checkEqual(nns, nns[order(nns)], msg="checking precision order") # should be in order ## The number of gaps should be equal to the last item minus n-1 found <- found + length(nns[nns <= n]) } return(1.0 * found / (n * nRounds)) } checkTrue(precision(1) >= 0.98) #, msg="precision at 1") checkTrue(precision(10) >= 0.98) #, msg="precision at 10") checkTrue(precision(100) >= 0.98) #, msg="precision at 100") checkTrue(precision(1000) >= 0.98) #, msg="precision at 1000") RcppAnnoy/inst/NEWS.Rd0000644000176200001440000001544314553605365014226 0ustar liggesusers\name{NEWS} \title{News for Package \pkg{RcppAnnoy}} \newcommand{\ghpr}{\href{https://github.com/eddelbuettel/rcppannoy/pull/#1}{##1}} \newcommand{\ghit}{\href{https://github.com/eddelbuettel/rcppannoy/issues/#1}{##1}} \section{Changes in version 0.0.22 (2024-01-23)}{ \itemize{ \item Replace empty examples macros to satisfy CRAN request. } } \section{Changes in version 0.0.21 (2023-07-02)}{ \itemize{ \item The build setup switched from C++11 to C++17 which offers threading support (which remains off by default to ensure consistent results) \item Upstream code was update to Annoy 1.17.3, the switch to an explicit C++ namespace has been accomodated (Dirk in \ghpr{75}) } } \section{Changes in version 0.0.20 (2022-10-27)}{ \itemize{ \item Minor tweaks appease \code{clang-15} and \code{Xcode 14} } } \section{Changes in version 0.0.19 (2021-07-30)}{ \itemize{ \item Minor tweaks to default CI setup and DESCRIPTION file } } \section{Changes in version 0.0.18 (2020-12-15)}{ \itemize{ \item Small tweaks to threading policy header defines (Dirk closing \ghit{65}) \item Vignette code is again compiled during testing (Aaron Lum and Dirk in \ghpr{66} addressing \ghit{64}) \item Upstream code (with Aaron's PR) was synchronized once more (Dirk in \ghpr{67}) \item A new helper function was added to report the Annoy version (Aaron in \ghpr{68}) } } \section{Changes in version 0.0.17 (2020-11-15)}{ \itemize{ \item Upgrade to Annoy 1.17, but default to serial use. \item Add new header file to regroup includes and defines. \item Upgrade CI script to use R with bspm on focal. } } \section{Changes in version 0.0.16 (2020-03-06)}{ \itemize{ \item Use \code{int} in two interfaces (Dirk in \ghpr{59} for upstream PR 460 and closing \ghit{56}). \item Use \code{inline} for two helper functions (Dirk in \ghpr{59} for upstream PR 461 and closing \ghit{57}; also Aaron in \ghpr{58} after earlier discussion). \item Removed a noisy \code{pragma} (Dirk in \ghpr{60} for upstream PR 462). \item Add a simple helper function displaying compiler status. } } \section{Changes in version 0.0.15 (2020-02-25)}{ \itemize{ \item RcppAnnoy synchronized with upstream PR 455 (Dirk in \ghpr{55}). \item The help page has a small correction thanks to Bill1 Venables. \item The \code{alloca()} function is now declared portably thanks to a working example in \emph{Writing R Extensions}. } } \section{Changes in version 0.0.14 (2019-11-11)}{ \itemize{ \item RcppAnnoy again synchronized with upstream to ensure builds with older compilers without AVX512 instructions (Dirk \ghpr{53}). \item The \code{cleanup} script only uses \code{/bin/sh}. } } \section{Changes in version 0.0.13 (2019-09-23)}{ \itemize{ \item In example(), the saved and loaded filename is now obtained via tempfile() to not touch user directories per CRAN Policy (Dirk). \item RcppAnnoy was again synchronized with Annoy upstream leading to enhanced performance and more features (Dirk \ghpr{48}). \item Minor changes made (and send as PRs upstream) to adapt both \code{annoylib.h} and \code{mman.h} changes (Dirk). \item A spurious command was removed from one vignette (Peter Hickey in \ghpr{49}). \item Two new user-facing functions onDiskBuild() and unbuild() were added (Dirk in \ghpr{50}). \item Minor tweaks were made to two tinytest-using test files (Dirk). } } \section{Changes in version 0.0.12 (2019-05-12)}{ \itemize{ \item Allow setting of seed (Dirk in \ghpr{41} fixing \ghit{40}). \item Document \code{setSeed} (James Melville in \ghpr{42} documenting \ghit{41}). \item Added documentation (Adam Spannbauer in \ghpr{44} closing \ghit{43}). \item Switched unit testing to the new \pkg{tinytest} package (Dirk in \ghpr{45}). \item The vignette is now pre-made in included as-is in Sweave document reducing the number of suggested packages. } } \section{Changes in version 0.0.11 (2018-10-30)}{ \itemize{ \item Synchronized with Annoy upstream (\ghpr{26}, \ghpr{30}, \ghpr{36}). \item Added new Hamming distance measure functionality; should be considered experimental as the functionality depends on integer values. \item Travis CI use was updated to the R 3.5 PPA (\ghpr{28}) \item New vignette about Annoy use from C++ via Rcpp (Aaron Lun in \ghpr{29} addressing \ghit{19}; also \ghpr{32}, \ghpr{33}) \item The vignette was rewritten using \pkg{pinp} (\ghpr{34}, \ghpr{35}). } } \section{Changes in version 0.0.10 (2017-09-25)}{ \itemize{ \item The \code{getItemsVector()} function no longer crashes (\ghit{24}) } } \section{Changes in version 0.0.9 (2017-08-31)}{ \itemize{ \item Synchronized with Annoy upstream version 1.9.1 \item Minor updates in calls and tests as required by annoy 1.9.1 \item New Manhattan distance modules along with unit test code \item Additional unit tests from upstream test code carried over \item Binary mode is used for \code{save} (as suggested by @khoran in \ghit{21}) \item A new file \code{init.c} was added with calls to \code{R_registerRoutines()} and \code{R_useDynamicSymbols()} \item Symbol registration is enabled in \code{useDynLib} } } \section{Changes in version 0.0.8 (2016-10-01)}{ \itemize{ \item New functions \code{getNNsByItemList} and \code{getNNsByVectorList}, from by Michael Phan-Ba in \ghit{12} \item Added destructor (PR \ghpr{14} by Michael Phan-Ba) \item Extended templatization (PR \ghpr{11} by Dan Dillon) \item Switched to \code{run.sh} for Travis (PR \ghpr{17}) \item Added test for admissible value to \code{addItem} (PR \ghpr{18} closing issue \ghit{13}) } } \section{Changes in version 0.0.7 (2015-11-15)}{ \itemize{ \item Synchronized with Annoy upstream changes \item Minor internal changes required by Annoy changes } } \section{Changes in version 0.0.6 (2015-05-03)}{ \itemize{ \item Synchronized with Annoy upstream changes \item Permit supplying our own RNG \item Minor internal changes } } \section{Changes in version 0.0.5 (2015-01-22)}{ \itemize{ \item Synchronized with Annoy upstream changes } } \section{Changes in version 0.0.4 (2015-01-22)}{ \itemize{ \item Synchronized with Annoy upstream changes \item Depends on R (>= 3.1) to permit C++11 builds } } \section{Changes in version 0.0.3 (2014-11-17)}{ \itemize{ \item Synchronized with Annoy upstream changes \item Windows support added (Qiang Kou in \ghpr{2}) } } \section{Changes in version 0.0.2 (2014-11-13)}{ \itemize{ \item Added verbosity toggle \item Added regression tests } } \section{Changes in version 0.0.1 (2014-11-08)}{ \itemize{ \item Initial release } } RcppAnnoy/inst/rmd/0000755000176200001440000000000014442705672013735 5ustar liggesusersRcppAnnoy/inst/rmd/rcppannoy.bib0000644000176200001440000000535713756552014016433 0ustar liggesusers@String{CRAN = "http://CRAN.R-Project.org/" } @Manual{Bioc:BiocNeighbors, title = {BiocNeighbors: Nearest Neighbor Detection for Bioconductor Packages}, author = {Aaron Lun}, year = 2020, note = {R package version 1.8.1}, } @Manual{CRAN:Rcpp, title = {{Rcpp}: Seamless {R} and {C++} Integration}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois and JJ Allaire and Kevin Ushey and Qiang Kou and Nathan Russel and John Chambers and Douglas Bates}, year = 2020, note = {R package version 1.0.5}, url = CRAN # "package=Rcpp" } @Manual{CRAN:RcppAnnoy, title = {RcppAnnoy: {Rcpp} Bindings for {Annoy}, a Library for Approximate Nearest Neighbors}, author = {Dirk Eddelbuettel}, year = 2020, note = {R package version 0.0.17}, url = CRAN # "package=RcppAnnoy" } @Book{Eddelbuettel:2013:Rcpp, author = {Dirk Eddelbuettel}, title = {Seamless R and C++ Integration with Rcpp}, publisher = {Springer}, series = {Use R!}, year = 2013, address = {New York}, isbn = {978-1-4614-6867-7} } @Manual{Github:annoy, author = {Erik Bernhardsson}, title = {Annoy: Approximate Nearest Neighbors in C++/Python}, year = 2020, note = {Python package version 1.17.0}, url = {https://pypi.org/project/annoy/}, } @Article{JSS:Rcpp, title = {{Rcpp}: Seamless {R} and {C++} Integration}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, journal = {Journal of Statistical Software}, year = 2011, volume = 40, number = 8, pages = {1--18}, url = {http://www.jstatsoft.org/v40/i08/}, } @Article{Lun+Richard+Marioni:2017, author = {Aaron T. L. Lun and Arianne C. Richard and John C. Marioni}, title = {Testing for differential abundance in mass cytometry data}, journal = {Nat. Methods}, year = 2017, volume = 14, number = 7, pages = {707--709}, month = {Jul}, } @Article{TAS:Rcpp, author = {Dirk Eddelbuettel and James Joseph Balamuta}, title = {Extending R with C++: A Brief Introduction to Rcpp}, journal = {The American Statistician}, volume = 72, number = 1, year = 2018, month = {August}, doi = {10.1080/00031305.2017.1375990} } @Article{Wang:2012, author = {Xueyi Wang}, title = {A fast exact k-nearest neighbors algorithm for high dimensional search using k-means clustering and triangle inequality}, journal = {Proc Int Jt Conf Neural Netw}, year = 2012, volume = 43, number = 6, pages = {2351--2358}, month = {Feb}, } RcppAnnoy/inst/rmd/UsingAnnoyInCpp.Rmd0000644000176200001440000002024514442705672017430 0ustar liggesusers--- title: Using Annoy in package C++ code author: - name: Aaron Lun affiliation: a address: - code: a address: \url{https://github.com/LTLA} lead_author_surname: Lun doi: "https://cran.r-project.org/package=RcppAnnoy" keywords: - Rcpp - Annoy - Approximate Nearest Neighbours footer_contents: "RcppAnnoy Vignette" date: \today output: pinp::pinp: collapse: true keep_tex: false bibliography: rcppannoy.bib skip_final_break: true abstract: | This note shows how to use the Annoy library for _Approximate Nearest Neighbours (Oh Yeah)_ from C++ code using the headers provided by the RcppAnnoy package. header-includes: > \newcommand{\proglang}[1]{\textsf{#1}} \newcommand{\pkg}[1]{\textbf{#1}} vignette: > %\VignetteIndexEntry{Using Annoy in C++} %\VignetteEngine{knitr::rmarkdown} %\VignetteKeywords{Rcpp, Annoy, R, Cpp, Approximate Nearest Neighbours} %\VignettePackage{Rcpp} %\usepackage[utf8]{inputenc} --- ```{r, echo=FALSE, results="hide"} knitr::opts_chunk$set(error=FALSE, warning=FALSE, message=FALSE, eval=FALSE) ``` # Setting up your package The [\pkg{Annoy}](https://github.com/spotify/annoy) \proglang{C++} library \citep{Github:annoy} implements a quick and simple method for _approximate nearest neighbor (oh yeah)_ searching. The \pkg{RcppAnnoy} package \citep{CRAN:RcppAnnoy} provides a centralized resource for developers to use this code in their own \proglang{R} packages by relying on \pkg{Rcpp} \citep{TAS:Rcpp,CRAN:Rcpp}. To use \pkg{Annoy} in \proglang{C++} code, simply put in your `DESCRIPTION` the line ``` LinkingTo: RcppAnnoy ``` and the header files will be available for inclusion into your package's source files. Note that \pkg{Annoy} is a header-only library so no additional commands are necessary for the linker. # Including the header files Obviously, the header files need to be `include`d in any \proglang{C++} source file that uses \pkg{Annoy}. A few macros also need to be added to handle Windows-specific behaviour and to ensure that error messages are printed through R. Version number comparison macros help in conditioning changes on a particular version. Since release 0.0.17 all this is now expressed centrally in a header in the package so users can just use this one-liner: ```{Rcpp, eval=FALSE} #include "RcppAnnoy.h" ``` # Defining the search type The `AnnoyIndex` template class can accommodate different data types, distance metrics, random number generators, and threading policies (where the latter are a choice between sequential or multithreaded). Here, we will consider the most common application of a nearest-neighbor search on floating-point data with Euclidean distance. We `typedef` the type and realized template for convenience: ```{Rcpp, eval=FALSE} typedef float ANNOYTYPE; typedef Annoy::AnnoyIndex MyAnnoyIndex; ``` Note that we use `float` by default, rather than the more conventional `double`. This is chosen for speed and to be consistent with the original Python implementation. The \pkg{Annoy} library uses random number generation during index creation (via the `Kiss64Random` class), with a seed that is separate from R's RNG seed. By default, the seed is fixed and results will be "deterministic" in the sense that repeated runs on the same data will yield the same result. They will also be unresponsive to the state of R's RNG seed. The seed used by `AnnoyIndex` can be specified by the `set_seed` method, which should be called before adding items to the index. # Building an index Let's say we have an `Rcpp::NumericMatrix` named `mat`, where each row corresponds to a sample and each column corresponds to a dimension/variable. ```{Rcpp, eval=FALSE} const size_t nsamples=mat.nrow(); const size_t ndims=mat.ncol(); ``` It is simple to build a `MyAnnoyIndex` containing the data in this matrix. Note the copy from the double-precision matrix into a `float` vector before calling `add_item()`. ```{Rcpp, eval=FALSE} MyAnnoyIndex obj(ndims); // from std::vector tmp(ndims); for (size_t i=0; i std::copy(cr.begin(), cr.end(), tmp.begin()); obj.add_item(i, tmp.data()); } obj.build(50); ``` The `build()` method accepts an integer argument specifying the number of trees to use to construct the index. Indices with more trees are larger (in memory and on file) but yield greater search accuracy. The index can also be saved to file via ```{Rcpp, eval=FALSE} obj.save(indexfile.c_str()); ``` and reloaded in some other context: ```{Rcpp, eval=FALSE} MyAnnoyIndex obj2(ndims); obj2.load(indexfile.c_str()); // same as 'obj'. ``` This is helpful for parallelization across workers running in different \proglang{R} sessions. It also allows us to avoid rebuilding the index in applications where the same data set is to be queried multiple times. # Searching for nearest neighbors Let's say that we want to find the `K` (approximate) nearest neighbors of sample `c` in the original data set used to construct `obj`. To do this, we write: ```{Rcpp, eval=FALSE} std::vector neighbor_index; std::vector neighbor_dist; obj.get_nns_by_item(c, K + 1, -1, &neighbor_index, &neighbor_dist); ``` Upon return, the `neighbor_index` vector will be filled with the sample numbers of the `K` nearest neighbors (i.e., rows of the original `mat`, in this case). The `neighbor_dist` vector will be filled with the distances to each of those neighbors. Note that: - We ask for the `K+1` nearest neighbors, as the set returned in `neighbor_index` will usually include `c` itself. This should be taken into consideration when the results are used in downstream calculations. - The returned neighbors are sorted by increasing distance from `c`. However, note that `c` itself may not necessarily be at the start if there is another point with the same coordinates. - `get_nns_by_item()` requires pointers to the vectors rather than the vectors themselves. If the pointer to the output vector for distances is `NULL`, distances will not be returned. This provides a slight performance boost when only the identities of the neighbors are of interest. - The `-1` is the default value for a tuning parameter that specifies how many samples should be collected from the trees for exhaustive distance calculations. This defaults to the number of trees multiplied by the number of requested neighbors; larger values will increase accuracy at the cost of speed. Another application is to query the index for the neighbors of a new sample given its coordinates. Assuming we have a `float*` to an array of coordinates of length `ndims`, we do: ```{Rcpp, eval=FALSE} obj.get_nns_by_vector(query, K+1, -1, &neighbor_index, &neighbor_dist); ``` # Further information The [Annoy repository](https://github.com/spotify/Annoy) is the canonical source of all things Annoying. Questions or issues related to the \pkg{Annoy} \proglang{C++} library itself should be posted there. Any issues specific to the \pkg{RcppAnnoy} interface should be posted at its separate [Github](https://github.com/eddelbuettel/rcppannoy) repository. An example of using the Annoy library via \pkg{RcppAnnoy} is available in the [\pkg{BiocNeighbors}](https://bioconductor.org/packages/BiocNeighbors) package \citep{Bioc:BiocNeighbors}. RcppAnnoy/cleanup0000755000176200001440000000024514553606145013552 0ustar liggesusers#!/bin/sh rm -rf *~ */*~ src/*.o src/*.so src/*.dll src/*.dylib src/symbols.rds \ vignettes/jss.bst vignettes/pinp.cls vignettes/auto \ vignettes/annoy.index