Skip to content

Commit ce544aa

Browse files
committed
introduce detect changes api
1 parent e3205de commit ce544aa

10 files changed

+360
-97
lines changed

R/RcppExports.R

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ weighted_uncert_probs <- function(data_lst, unc_lst) {
99
.Call(`_sits_weighted_uncert_probs`, data_lst, unc_lst)
1010
}
1111

12+
dtw_distance <- function(ts1, ts2) {
13+
.Call(`_sits_dtw_distance`, ts1, ts2)
14+
}
15+
1216
C_kernel_median <- function(x, ncols, nrows, band, window_size) {
1317
.Call(`_sits_C_kernel_median`, x, ncols, nrows, band, window_size)
1418
}

R/sits_detect_change.R

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#' @title Detect changes in time series
2+
#' @name sits_detect_change
3+
#'
4+
#' @author Gilberto Camara, \email{gilberto.camara@@inpe.br}
5+
#' @author Felipe Carlos, \email{efelipecarlos@@gmail.com}
6+
#' @author Felipe Carvalho, \email{felipe.carvalho@@inpe.br}
7+
#'
8+
#' @description Given a set of time series or an image, this function compares
9+
#' each time series with a set of change/no-change patterns, and indicates
10+
#' places and dates where change has been detected.
11+
#'
12+
#' @param data Set of time series.
13+
#' @param cd_method Change detection method (with parameters).
14+
#' @param ... Other relevant parameters.
15+
#' @param filter_fn Smoothing filter function to be applied to the data.
16+
#' @param multicores Number of threads to process the time series.
17+
#' @param progress Show progress bar?
18+
#' @return Set of time series where significant change has been
19+
#' detected.
20+
#' @export
21+
sits_detect_change <- function(data,
22+
cd_method,
23+
...,
24+
filter_fn = NULL,
25+
multicores = 2L,
26+
progress = TRUE) {
27+
UseMethod("sits_detect_change", data)
28+
}
29+
30+
#' @rdname sits_detect_change
31+
#' @export
32+
sits_detect_change.sits <- function(data,
33+
cd_method,
34+
...,
35+
filter_fn = NULL,
36+
multicores = 2L,
37+
progress = TRUE) {
38+
# set caller for error messages
39+
.check_set_caller("sits_detect_change_sits")
40+
# Pre-conditions
41+
data <- .check_samples_ts(data)
42+
.check_is_sits_model(cd_method)
43+
.check_int_parameter(multicores, min = 1, max = 2048)
44+
.check_progress(progress)
45+
# Do detection
46+
detections <- .detect_change_ts(
47+
samples = data,
48+
cd_method = cd_method,
49+
filter_fn = filter_fn,
50+
multicores = multicores,
51+
progress = progress
52+
)
53+
return(detections)
54+
}
55+
56+
#' @rdname sits_detect_change
57+
#' @export
58+
sits_detect_change.default <- function(data, cd_method, ...) {
59+
stop("Input should be a sits tibble or a data cube")
60+
}

R/sits_detect_change_method.R

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#' @title Create detect change method.
2+
#' @name sits_detect_change_method
3+
#'
4+
#' @author Gilberto Camara, \email{gilberto.camara@@inpe.br}
5+
#' @author Felipe Carlos, \email{efelipecarlos@@gmail.com}
6+
#'
7+
#' @description Prepare detection change method. Currently, sits supports the
8+
#' following methods: 'dtw' (see \code{\link[sits]{sits_dtw}})
9+
#'
10+
#' @param samples Time series with the training samples.
11+
#' @param cd_method Change detection method.
12+
#' @return Change detection method prepared
13+
#' to be passed to
14+
#' \code{\link[sits]{sits_detect_change}}
15+
#' @export
16+
#'
17+
sits_detect_change_method <- function(samples, cd_method = sits_dtw()) {
18+
# set caller to show in errors
19+
.check_set_caller("sits_detect_change_method")
20+
# check if samples are valid
21+
.check_samples_train(samples)
22+
# is the train method a function?
23+
.check_that(inherits(cd_method, "function"),
24+
msg = .conf("messages", "sits_detect_change_method_model")
25+
)
26+
# are the timelines OK?
27+
timeline_ok <- .timeline_check(samples)
28+
.check_that(timeline_ok,
29+
msg = .conf("messages", "sits_detect_change_method_timeline")
30+
)
31+
# compute the training method by the given data
32+
result <- cd_method(samples)
33+
# return a valid detect change method
34+
return(result)
35+
}

man/sits_detect_change.Rd

+57
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/sits_detect_change_method.Rd

+27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/RcppExports.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ BEGIN_RCPP
3636
return rcpp_result_gen;
3737
END_RCPP
3838
}
39+
// dtw_distance
40+
double dtw_distance(const NumericMatrix& ts1, const NumericMatrix& ts2);
41+
RcppExport SEXP _sits_dtw_distance(SEXP ts1SEXP, SEXP ts2SEXP) {
42+
BEGIN_RCPP
43+
Rcpp::RObject rcpp_result_gen;
44+
Rcpp::RNGScope rcpp_rngScope_gen;
45+
Rcpp::traits::input_parameter< const NumericMatrix& >::type ts1(ts1SEXP);
46+
Rcpp::traits::input_parameter< const NumericMatrix& >::type ts2(ts2SEXP);
47+
rcpp_result_gen = Rcpp::wrap(dtw_distance(ts1, ts2));
48+
return rcpp_result_gen;
49+
END_RCPP
50+
}
3951
// C_kernel_median
4052
NumericVector C_kernel_median(const NumericMatrix& x, int ncols, int nrows, int band, int window_size);
4153
RcppExport SEXP _sits_C_kernel_median(SEXP xSEXP, SEXP ncolsSEXP, SEXP nrowsSEXP, SEXP bandSEXP, SEXP window_sizeSEXP) {
@@ -672,6 +684,7 @@ END_RCPP
672684
static const R_CallMethodDef CallEntries[] = {
673685
{"_sits_weighted_probs", (DL_FUNC) &_sits_weighted_probs, 2},
674686
{"_sits_weighted_uncert_probs", (DL_FUNC) &_sits_weighted_uncert_probs, 2},
687+
{"_sits_dtw_distance", (DL_FUNC) &_sits_dtw_distance, 2},
675688
{"_sits_C_kernel_median", (DL_FUNC) &_sits_C_kernel_median, 5},
676689
{"_sits_C_kernel_mean", (DL_FUNC) &_sits_C_kernel_mean, 5},
677690
{"_sits_C_kernel_sd", (DL_FUNC) &_sits_C_kernel_sd, 5},

src/detect_change_distances.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include <Rcpp.h>
2+
#include "./dtw.h"
3+
4+
using namespace Rcpp;
5+
6+
/**
7+
* Convert `NumericMatrix` to 2D `std::vector`.
8+
*
9+
* @description
10+
* This function converts a `NumericMatrix` into a 2D `std::vector`.
11+
*
12+
* @param mat A `NumericMatrix` with single or multi variate time-series.
13+
*/
14+
std::vector<std::vector<double>> to_cpp_vector(NumericMatrix mat) {
15+
size_t rows = mat.nrow();
16+
size_t cols = mat.ncol();
17+
18+
std::vector<std::vector<double>> result(rows, std::vector<double>(cols));
19+
20+
for(size_t i = 0; i < rows; ++i) {
21+
for(size_t j = 0; j < cols; ++j) {
22+
result[i][j] = mat(i, j);
23+
}
24+
}
25+
26+
return result;
27+
}
28+
29+
/**
30+
* Dynamic Time Warping (DTW) distance.
31+
*
32+
* @description
33+
* This function calculates the Dynamic Time Warping (DTW) distance between
34+
* two time-series.
35+
*
36+
* @param x A `double *` Time-series data.
37+
* @param y A `double *` Self-Organizing Maps (SOM) codebook.
38+
* @param np `int` Number of points in arrays `p1` and `p2`.
39+
* @param nNA `int` Number of `NA` values in the arrays `p1` and `p2`.
40+
*
41+
* @reference
42+
* Giorgino, T. (2009). Computing and Visualizing Dynamic Time Warping
43+
* Alignments in R: The dtw Package. Journal of Statistical Software, 31(7),
44+
* 1–24. https://doi.org/10.18637/jss.v031.i07
45+
*
46+
* @return DTW distance.
47+
*/
48+
// [[Rcpp::export]]
49+
double dtw_distance(
50+
const NumericMatrix& ts1,
51+
const NumericMatrix& ts2
52+
)
53+
{
54+
std::vector<std::vector<double>> ts1_vec = to_cpp_vector(ts1);
55+
std::vector<std::vector<double>> ts2_vec = to_cpp_vector(ts2);
56+
57+
return (distance_dtw_op(ts1_vec, ts2_vec, 2));
58+
}

src/dtw.cpp

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#include <Rcpp.h>
2+
#include "./dtw.h"
3+
4+
using namespace Rcpp;
5+
6+
/**
7+
* Compute the p-norm between two time-series.
8+
*
9+
* @description
10+
* The `p-norm`, also known as the `Minkowski space`, is a generalized norm
11+
* calculation that includes several types of distances based on the value
12+
* of `p`.
13+
*
14+
* Common values of `p` include:
15+
*
16+
* - `p = 1` for the Manhattan (city block) distance;
17+
* - `p = 2` for the Euclidean norm (distance).
18+
*
19+
* More details about p-norms can be found on Wikipedia:
20+
* https://en.wikipedia.org/wiki/Norm_(mathematics)#p-norm
21+
*
22+
* @param a A `std::vector<double>` with time-series values.
23+
* @param b A `std::vector<double>` with time-series values.
24+
* @param p A `double` value of the norm to use, determining the type of
25+
* distance calculated.
26+
*
27+
* @note
28+
* Both vectors `a` and `b` must have the same length.
29+
*
30+
* @note
31+
* The implementation of this DTW distance calculation was adapted from the
32+
* `DTW_cpp` single header library (https://github.com/cjekel/DTW_cpp).
33+
*
34+
* @return The `p-norm` value between vectors `a` and `b`.
35+
*/
36+
double p_norm(std::vector<double> a, std::vector<double> b, double p)
37+
{
38+
double d = 0;
39+
40+
size_t index;
41+
size_t a_size = a.size();
42+
43+
for (index = 0; index < a_size; index++)
44+
{
45+
d += std::pow(std::abs(a[index] - b[index]), p);
46+
}
47+
return std::pow(d, 1.0 / p);
48+
}
49+
50+
/**
51+
* Dynamic Time Warping (DTW) distance.
52+
*
53+
* @description
54+
* This function calculates the Dynamic Time Warping (DTW) distance between
55+
* two time-series.
56+
*
57+
* @param x A `std::vector<std::vector<double>>` with time-series values.
58+
* @param y A `std::vector<std::vector<double>>` with time-series values.
59+
*
60+
* @reference
61+
* Giorgino, T. (2009). Computing and Visualizing Dynamic Time Warping
62+
* Alignments in R: The dtw Package. Journal of Statistical Software, 31(7),
63+
* 1–24. https://doi.org/10.18637/jss.v031.i07
64+
*
65+
* @note
66+
* The implementation of this DTW distance calculation was adapted from the
67+
* `DTW_cpp` single header library (https://github.com/cjekel/DTW_cpp).
68+
*
69+
* @return DTW distance.
70+
*/
71+
double distance_dtw_op(std::vector<std::vector<double>> a,
72+
std::vector<std::vector<double>> b,
73+
double p)
74+
{
75+
int n = a.size();
76+
int o = b.size();
77+
78+
std::vector<std::vector<double>> d(n, std::vector<double>(o, 0.0));
79+
80+
d[0][0] = p_norm(a[0], b[0], p);
81+
82+
for (int i = 1; i < n; i++)
83+
{
84+
d[i][0] = d[i - 1][0] + p_norm(a[i], b[0], p);
85+
}
86+
for (int i = 1; i < o; i++)
87+
{
88+
d[0][i] = d[0][i - 1] + p_norm(a[0], b[i], p);
89+
}
90+
for (int i = 1; i < n; i++)
91+
{
92+
for (int j = 1; j < o; j++)
93+
{
94+
d[i][j] = p_norm(a[i], b[j], p) + std::fmin(
95+
std::fmin(d[i - 1][j], d[i][j - 1]), d[i - 1][j - 1]
96+
);
97+
}
98+
}
99+
return d[n - 1][o - 1];
100+
}

src/dtw.h

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
#pragma once
3+
double distance_dtw_op(std::vector<std::vector<double>> a,
4+
std::vector<std::vector<double>> b,
5+
double p);

0 commit comments

Comments
 (0)