Documentation: x2r.io
Python and standalone C++ sources are published separately in
fastcpd-py and
fastcpd-cpp.
Installation: R, Python, and C++
R package:
install.packages("fastcpd")Python package:
python -m pip install fastcpdC++ library (requires Armadillo and Abseil 20260526 or newer):
git clone https://github.com/doccstat/fastcpd-cpp.git
cmake -S fastcpd-cpp -B fastcpd-cpp/build -DFASTCPD_BUILD_EXAMPLES=OFF
cmake --build fastcpd-cpp/build --parallel
cmake --install fastcpd-cpp/build --prefix fastcpd-installset.seed(1)
n <- 10^7
mean_data <- c(rnorm(n / 2, 0, 1), rnorm(n / 2, 50, 1))
print(run_isolated(fastcpd::detect_mean(mean_data, cp_only = TRUE, variance_estimation = 1)))
#> user system elapsed
#> 0.745 0.194 0.981
print(run_isolated(mosum::mosum(c(mean_data), G = 40)))
#> user system elapsed
#> 1.282 0.696 2.236
print(run_isolated(changepoint::cpt.mean(mean_data, method = "PELT")))
#> user system elapsed
#> 3.381 0.665 4.418
print(run_isolated(fpop::Fpop(mean_data, 2 * log(n))))
#> user system elapsed
#> 4.027 0.299 4.483import numpy as np
import ruptures as rpt
from fastcpd import detect_mean
from sdt.changepoint import Pelt as SdtPelt
from skchange.detectors import PELT
from skchange.interval_scorers import L2Cost
rng = np.random.default_rng(1)
n = 1_000
x = np.r_[rng.normal(0, 1, n // 2), rng.normal(50, 1, n // 2)]
benchmark("fastcpd", lambda: detect_mean(x, variance_estimation=1, cp_only=True))
benchmark("skchange", lambda: PELT(cost=L2Cost(), penalty=2 * np.log(n), min_segment_length=1).fit_predict(x.reshape(-1, 1)))
benchmark("sdt-python", lambda: SdtPelt(cost="l2", min_size=1, jump=1).find_changepoints(x, penalty=2 * np.log(n)))
benchmark("ruptures", lambda: rpt.Pelt(model="l2", min_size=1, jump=1).fit(x).predict(pen=2 * np.log(n)))Native fastcpd and fpop on Linux ARM64, with 1,000,000 observations. Source and build instructions.



