Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
branches: [main, master]
branches: # prevents running on tag push
- '**'
pull_request:

name: R-CMD-check.yaml
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/linux_build_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
with:
user: __token__
password: ${{ secrets.TEST_PYPI_APIKEY }}
repository_url: https://test.pypi.org/legacy/
repository-url: https://test.pypi.org/legacy/

- name: Upload to PyPI on published release
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/linux_run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
run: |
# The flags are necessary to ignore the pyproject.toml
# See https://github.com/pypa/pip/issues/9738
python -m pip install --no-use-pep517 --no-build-isolation -vvv -e .
python -m pip install --no-use-pep517 --no-build-isolation -v -e .
env:
# The default compiler on the Github Ubuntu runners is gcc
# Would need to make a respective include change for clang
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/mac_arm64_run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:

# On the MacOS machine, when installing from source,
# we use LLVM Clang
# Note: we need to include armadillo here even though we install armadillo from source
# to create the correct folders
- name: Install MacOS dependencies
run: |
brew install llvm libomp armadillo
Expand All @@ -45,6 +47,7 @@ jobs:
cd ~
git clone https://gitlab.com/conradsnicta/armadillo-code.git
cd armadillo-code
git checkout tags/14.6.3
sudo cmake .
sudo make install

Expand All @@ -63,7 +66,7 @@ jobs:
run: |
# The flags are necessary to ignore the pyproject.toml
# See https://github.com/pypa/pip/issues/9738
python -m pip install --no-use-pep517 --no-build-isolation -vvv -e .
python -m pip install --no-use-pep517 --no-build-isolation -v -e .
env:
# The default compiler on the Github Ubuntu runners is gcc
# Would need to make a respective include change for clang
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/mac_build_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Build wheels
uses: pypa/cibuildwheel@v2.23.3
env:
MACOSX_DEPLOYMENT_TARGET: "14"
MACOSX_DEPLOYMENT_TARGET: "15"
CIBW_ARCHS_MACOS: "x86_64 arm64 universal2"

CIBW_BUILD: "cp310* cp311* cp312* cp313*"
Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:
with:
user: __token__
password: ${{ secrets.TEST_PYPI_APIKEY }}
repository_url: https://test.pypi.org/legacy/
repository-url: https://test.pypi.org/legacy/

- name: Upload to PyPI on published release
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/mac_intel_run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ jobs:

# On the MacOS machine, when installing from source,
# we use LLVM Clang
# Note: we need to include armadillo here even though we install armadillo from source
# to create the correct folders
- name: Install MacOS dependencies
run: |
brew install llvm libomp armadillo
Expand All @@ -44,6 +46,7 @@ jobs:
cd ~
git clone https://gitlab.com/conradsnicta/armadillo-code.git
cd armadillo-code
git checkout tags/14.6.3
cmake .
make install

Expand All @@ -62,7 +65,7 @@ jobs:
run: |
# The flags are necessary to ignore the pyproject.toml
# See https://github.com/pypa/pip/issues/9738
python -m pip install --no-use-pep517 --no-build-isolation -vvv -e .
python -m pip install --no-use-pep517 --no-build-isolation -v -e .

- name: Downloading data files for tests
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run_windows_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ jobs:
cd BanditPAM
# The flags are necessary to ignore the pyproject.toml
# See https://github.com/pypa/pip/issues/9738
python -m pip install -vvvv --no-use-pep517 .
python -m pip install -v --no-use-pep517 .
cd scripts
sh retrieve_windows_python_files.sh
cd ..
python -m pip install -vvvv --no-use-pep517 .
python -m pip install -v --no-use-pep517 .

- name: Run smaller suite of test cases
run: |
Expand Down
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,31 @@
[![Run style checks](https://github.com/motiwari/BanditPAM/actions/workflows/run_style_checks.yml/badge.svg)](https://github.com/motiwari/BanditPAM/actions/workflows/run_style_checks.yml)


This repo contains a high-performance implementation of BanditPAM from [BanditPAM: Almost Linear-Time k-Medoids Clustering](https://proceedings.neurips.cc/paper/2020/file/73b817090081cef1bca77232f4532c5d-Paper.pdf). The code can be called directly from Python, R, or C++.
This repo contains a high-performance implementation of BanditPAM from [BanditPAM: Almost Linear-Time k-Medoids Clustering](https://proceedings.neurips.cc/paper/2020/file/73b817090081cef1bca77232f4532c5d-Paper.pdf) and [BanditPAM++: Faster k-medoids Clustering](https://proceedings.neurips.cc/paper_files/paper/2023/file/e885e5bc6e13b9dd8f80bc5482b1fa2f-Paper-Conference.pdf). The code can be called directly from Python, R, or C++.

If you use this software, please cite:

Mo Tiwari, Martin Jinye Zhang, James Mayclin, Sebastian Thrun, Chris Piech, Ilan Shomorony. "BanditPAM: Almost Linear Time *k*-medoids Clustering via Multi-Armed Bandits" Advances in Neural Information Processing Systems (NeurIPS) 2020.

Mo Tiwari, Ryan Kang*, Donghyun Lee*, Sebastian Thrun, Chris Piech, Ilan Shomorony, Martin Jinye Zhang. "BanditPAM++: Faster k-medoids Clustering" Advances in Neural Information Processing Systems (NeurIPS) 2023.

```python
@inproceedings{BanditPAM,
title={BanditPAM: Almost Linear Time k-medoids Clustering via Multi-Armed Bandits},
@inproceedings{tiwari2020banditpam,
title={BanditPAM: Almost Linear Time $k$-medoids Clustering via Multi-Armed Bandits},
author={Tiwari, Mo and Zhang, Martin J and Mayclin, James and Thrun, Sebastian and Piech, Chris and Shomorony, Ilan},
booktitle={Advances in Neural Information Processing Systems},
pages={368--374},
year={2020}
}

@inproceedings{tiwari2023banditpam++,
title={BanditPAM++: Faster $k$-medoids Clustering},
author={Tiwari, Mo and Kang, Ryan and Lee, Donghyun and Thrun, Sebastian and Shomorony, Ilan and Zhang, Martin J},
journal={Advances in Neural Information Processing Systems},
volume={36},
pages={73371--73382},
year={2023}
}
```

# Requirements
Expand All @@ -34,7 +45,8 @@ Mo Tiwari, Martin Jinye Zhang, James Mayclin, Sebastian Thrun, Chris Piech, Ilan
If you have any difficulties, please see the [platform-specific guides](https://github.com/motiwari/BanditPAM#platform-specific-installation-guides) and file a Github issue if you have additional trouble.

## Further Reading
* [Full paper](https://proceedings.neurips.cc/paper/2020/file/73b817090081cef1bca77232f4532c5d-Paper.pdf)
* [NeurIPS 2020 Paper](https://proceedings.neurips.cc/paper/2020/file/73b817090081cef1bca77232f4532c5d-Paper.pdf)
* [NeurIPS 2023 Paper](https://proceedings.neurips.cc/paper_files/paper/2023/file/e885e5bc6e13b9dd8f80bc5482b1fa2f-Paper-Conference.pdf)
* [3-minute summary video](https://slideslive.com/38936275/banditpam-almost-linear-time-kmedoids-clustering-via-multiarmed-bandits)
* [Blog post](https://ai.stanford.edu/blog/banditpam/)
* [Code](https://github.com/motiwari/BanditPAM)
Expand Down
21 changes: 16 additions & 5 deletions R_package/banditpam/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,33 @@
<!-- badges: end -->

We provide an R interface to the high-performance implementation of
[banditpam](https://proceedings.neurips.cc/paper/2020/file/73b817090081cef1bca77232f4532c5d-Paper.pdf),
[BanditPAM](https://proceedings.neurips.cc/paper/2020/file/73b817090081cef1bca77232f4532c5d-Paper.pdf) and [BanditPAM++](https://proceedings.neurips.cc/paper_files/paper/2023/file/e885e5bc6e13b9dd8f80bc5482b1fa2f-Paper-Conference.pdf),
a $k$-medoids clustering algorithm.

If you use this software, please cite:

>>Mo Tiwari, Martin Jinye Zhang, James Mayclin, Sebastian Thrun, Chris Piech, Ilan Shomorony. "banditpam: Almost Linear Time *k*-medoids Clustering via Multi-Armed Bandits" Advances in Neural Information Processing Systems (NeurIPS) 2020.
>>Mo Tiwari, Martin Jinye Zhang, James Mayclin, Sebastian Thrun, Chris Piech, Ilan Shomorony. "BanditPAM: Almost Linear Time *k*-medoids Clustering via Multi-Armed Bandits" Advances in Neural Information Processing Systems (NeurIPS) 2020.

Here's a BibTeX entry:
>>Mo Tiwari, Ryan Kang*, Donghyun Lee*, Sebastian Thrun, Chris Piech, Ilan Shomorony, Martin Jinye Zhang. "BanditPAM++: Faster k-medoids Clustering" Advances in Neural Information Processing Systems (NeurIPS) 2023.

Here's the BibTeX:
```
@inproceedings{banditpam,
title={banditpam: Almost Linear Time k-medoids Clustering via Multi-Armed Bandits},
@inproceedings{tiwari2020banditpam,
title={BanditPAM: Almost Linear Time %k%-medoids Clustering via Multi-Armed Bandits},
author={Tiwari, Mo and Zhang, Martin J and Mayclin, James and Thrun, Sebastian and Piech, Chris and Shomorony, Ilan},
booktitle={Advances in Neural Information Processing Systems},
pages={368--374},
year={2020}
}

@inproceedings{tiwari2023banditpam++,
title={BanditPAM++: Faster $k$-medoids Clustering},
author={Tiwari, Mo and Kang, Ryan and Lee, Donghyun and Thrun, Sebastian and Shomorony, Ilan and Zhang, Martin J},
journal={Advances in Neural Information Processing Systems},
volume={36},
pages={73371--73382},
year={2023}
}
```

## Installation
Expand Down
23 changes: 20 additions & 3 deletions R_package/banditpam/src/kmedoids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ SEXP KMedoids__get_build_conf(SEXP xp) {
//// Set the build_conf property
////
//// @param xp the km::KMedoids Object XPtr
// [[Rcpp::export(.KMedoids__set_iter)]]
// [[Rcpp::export(.KMedoids__set_build_conf)]]
void KMedoids__set_build_conf(SEXP xp, IntegerVector bc) {
// grab the object as a XPtr (smart pointer)
XPtr<km::KMedoids> ptr(xp);
Expand All @@ -170,21 +170,38 @@ SEXP KMedoids__get_swap_conf(SEXP xp) {
//// Set the swap_conf property
////
//// @param xp the km::KMedoids Object XPtr
// [[Rcpp::export(.KMedoids__set_iter)]]
// [[Rcpp::export(.KMedoids__set_swap_conf)]]
void KMedoids__set_swap_conf(SEXP xp, IntegerVector bc) {
// grab the object as a XPtr (smart pointer)
XPtr<km::KMedoids> ptr(xp);
ptr->setSwapConfidence(bc[0]);
}

//// Convenience function to convert LossType to string
////
//// @param lt the km::KMedoids LossType
// [[Rcpp::export(.loss_to_string)]]
static inline std::string loss_to_string(km::LossType lt) {
switch (lt) {
case km::LossType::MANHATTAN: return "manhattan";
case km::LossType::COS: return "cos";
case km::LossType::COSINE: return "cos";
case km::LossType::INF: return "inf";
case km::LossType::EUCLIDEAN: return "euclidean";
case km::LossType::LP_NORM: return "lp";
case km::LossType::UNKNOWN: return "unknown";
default: return "unknown";
}
}

//// Return the loss_fn property
////
//// @param xp the km::KMedoids Object XPtr
// [[Rcpp::export(.KMedoids__get_loss_fn)]]
SEXP KMedoids__get_loss_fn(SEXP xp) {
// grab the object as a XPtr (smart pointer)
XPtr<km::KMedoids> ptr(xp);
return wrap(ptr->getLossFn());
return wrap(loss_to_string(ptr->getLossFn()));
}

//// Set the loss_fn property
Expand Down
2 changes: 1 addition & 1 deletion R_package/banditpam/src/kmedoids_algorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ void KMedoids::setLossFn(std::string loss) {
c = ::tolower(c); // TODO(@motiwari): Put something before ::
});

switch (getLossType(loss)) {
switch (KMedoids::getLossType(loss)) {
case LossType::MANHATTAN:
lossFn = &KMedoids::manhattan;
break;
Expand Down
46 changes: 45 additions & 1 deletion R_package/banditpam/src/kmedoids_algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,28 @@
#include <functional>
#include <unordered_map>
#include <string>
#include <regex>

namespace km {

/**
* @brief Enum for different loss function types
*/
enum class LossType {
MANHATTAN,
COS,
COSINE,
INF,
EUCLIDEAN,
LP_NORM,
UNKNOWN
};

/**
* @brief Enum for different distance categories
*/
enum class AlgorithmStep { MISC, BUILD, SWAP };

/**
* @brief KMedoids class. Creates a KMedoids object that can be used to find the medoids
* for a particular set of input data.
Expand Down Expand Up @@ -189,7 +209,7 @@ class KMedoids {
*
* @returns Loss function currently being recognized
*/
std::string getLossFn() const;
LossType getLossFn() const;

/**
* @brief Get the average loss from the prior clustering
Expand Down Expand Up @@ -462,6 +482,30 @@ class KMedoids {
*/
void checkAlgorithm(const std::string& algorithm) const;

/**
* @brief Converts a string loss function name to LossType enum
*
* @param loss The loss function string
* @returns The corresponding LossType enum value
*/
LossType getLossType(const std::string &loss) const {
if (loss == "manhattan") {
return LossType::MANHATTAN;
} else if (loss == "cos") {
return LossType::COS;
} else if (loss == "cosine") {
return LossType::COSINE;
} else if (loss == "inf") {
return LossType::INF;
} else if (loss == "euclidean") {
return LossType::EUCLIDEAN;
} else if (std::regex_match(loss, std::regex("l\\d*"))) {
return LossType::LP_NORM;
} else {
return LossType::UNKNOWN;
}
}

/// Number of medoids to use -- the "k" in k-medoids
size_t nMedoids;

Expand Down
2 changes: 1 addition & 1 deletion docs/install_mac.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Installation Tutorial for MacOS

The following is a more detailed description of the installation process of BanditPAM for MacOS.
The following is a more detailed description of the installation process of BanditPAM for MacOS 15.0+.

## Prerequisites
Please ensure the following dependencies are installed:
Expand Down
18 changes: 8 additions & 10 deletions headers/algorithms/kmedoids_algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ enum class LossType {
/**
* @brief Enum for different distance categories
*/
enum class AlgorithmStep {
MISC,
BUILD,
SWAP
};
enum class AlgorithmStep { MISC, BUILD, SWAP };

/**
* @brief KMedoids class. Creates a KMedoids object that can be used to find the
Expand Down Expand Up @@ -468,17 +464,18 @@ class KMedoids {
* @returns The Manhattan distance between points i and j
*/
float manhattan(const arma::fmat &data, const size_t i, const size_t j) const;

/**
* @brief Assigns ranks to each element in the input vector.
* Smallest element receives rank 1, the next 2, and so on.
* Ties are assigned the average of the ranks they would encompass.
*
* @param vec A vector containing the elements to be ranked.
*
* @returns A vector of the same size as `vec`, with each element replaced by its rank.
* @returns A vector of the same size as `vec`, with each element replaced by
* its rank.
*/
arma::fvec rank(const arma::fvec& vec) const;
arma::fvec rank(const arma::fvec &vec) const;

/**
* @brief Computes the Pearson correlation between the
Expand All @@ -491,7 +488,8 @@ class KMedoids {
* @returns The Pearson correlation between points i and j
*/
float pearson(const arma::fmat &data, const size_t i, const size_t j) const;
float clippedCos(const arma::fmat &data, const size_t i, const size_t j) const;
float clippedCos(const arma::fmat &data, const size_t i,
const size_t j) const;

/**
* @brief Computes the Spearman correlation between the
Expand All @@ -517,7 +515,7 @@ class KMedoids {

/**
* @brief Converts a string loss function name to LossType enum
*
*
* @param loss The loss function string
* @returns The corresponding LossType enum value
*/
Expand Down
Loading
Loading