Skip to content

Commit dfd12e4

Browse files
author
Oscar Torreno
committed
Fix kShape for double array (#91)
1 parent deca820 commit dfd12e4

File tree

2 files changed

+80
-31
lines changed

2 files changed

+80
-31
lines changed

src/khiva/clustering.cpp

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* @param k The number of centroids.
1919
* @return The new centroids.
2020
*/
21-
af::array calculateInitialMeans(af::array tss, int k) { return af::constant(0.0f, tss.dims(0), k); }
21+
af::array calculateInitialMeans(af::array tss, int k) { return af::constant(0, tss.dims(0), k, tss.type()); }
2222

2323
/**
2424
* Computes The euclidean distance for a tiled time series agains k-means.
@@ -40,13 +40,13 @@ af::array kEuclideanDistance(af::array tts, af::array means) {
4040
* @param labels The ids of the closes mean for all time series.
4141
*/
4242
void euclideanDistance(af::array tss, af::array means, af::array &minDistance, af::array &idxs) {
43-
int nseries = tss.dims(1);
44-
af::array kDistances = af::constant(0.0, means.dims(1), nseries);
43+
int nSeries = tss.dims(1);
44+
af::array kDistances = af::constant(0.0, means.dims(1), nSeries, tss.type());
4545

4646
// This for loop could be parallel, not parallelized to keep memory footprint low
47-
for (int i = 0; i < nseries; i++) {
48-
af::array tiledSerie = af::tile(tss.col(i), 1, means.dims(1));
49-
kDistances(af::span, i) = kEuclideanDistance(tiledSerie, means);
47+
for (int i = 0; i < nSeries; i++) {
48+
af::array tiledSeries = af::tile(tss.col(i), 1, means.dims(1));
49+
kDistances(af::span, i) = kEuclideanDistance(tiledSeries, means);
5050
}
5151
af::min(minDistance, idxs, kDistances, 0);
5252
}
@@ -61,7 +61,7 @@ void euclideanDistance(af::array tss, af::array means, af::array &minDistance, a
6161
*/
6262
af::array computeNewMeans(af::array tss, af::array labels, int k) {
6363
af::array labelsTiled = af::tile(labels, tss.dims(0));
64-
af::array newMeans = af::constant(0.0, tss.dims(0), k);
64+
af::array newMeans = af::constant(0.0, tss.dims(0), k, tss.type());
6565

6666
gfor(af::seq ii, k) {
6767
newMeans(af::span, ii) = af::sum(tss * (labelsTiled == ii), 1) / (af::sum(af::sum((labels == ii), 3), 1));
@@ -133,7 +133,7 @@ void khiva::clustering::kMeans(af::array tss, int k, af::array &centroids, af::a
133133
labels = generateRandomLabels(tss.dims(1), k);
134134
}
135135

136-
af::array distances = af::constant(0.0f, tss.dims(1));
136+
af::array distances = af::constant(0, tss.dims(1), tss.type());
137137
af::array newMeans;
138138
int iter = 0;
139139

@@ -204,18 +204,36 @@ af::array eigenValues(af::array matrix) {
204204
* @return The first Eigen vector.
205205
*/
206206
af::array getFirstEigenVector(af::array m) {
207-
float *matHost = m.host<float>();
208-
Eigen::MatrixXf mat = Eigen::Map<Eigen::MatrixXf>(matHost, m.dims(0), m.dims(1));
209-
210-
// Compute Eigen Values.
211-
Eigen::VectorXcf eivals = mat.eigenvalues();
212-
Eigen::VectorXf reEIVals = eivals.real();
213-
af::array eigenValues = af::array(m.dims(0), reEIVals.data());
214-
215-
// Compute Eigen Vectors.
216-
Eigen::EigenSolver<Eigen::MatrixXf> solution(mat);
217-
Eigen::MatrixXf reEIVectors = solution.eigenvectors().real();
218-
af::array eigenVectors = af::array(m.dims(0), m.dims(1), reEIVectors.data());
207+
af::array eigenValues;
208+
af::array eigenVectors;
209+
210+
if (m.type() == af::dtype::f64) {
211+
double *matHost = m.host<double>();
212+
Eigen::MatrixXd mat = Eigen::Map<Eigen::MatrixXd>(matHost, m.dims(0), m.dims(1));
213+
214+
// Compute Eigen Values.
215+
Eigen::VectorXcd eivals = mat.eigenvalues();
216+
Eigen::VectorXd reEIVals = eivals.real();
217+
eigenValues = af::array(m.dims(0), reEIVals.data());
218+
219+
// Compute Eigen Vectors.
220+
Eigen::EigenSolver<Eigen::MatrixXd> solution(mat);
221+
Eigen::MatrixXd reEIVectors = solution.eigenvectors().real();
222+
eigenVectors = af::array(m.dims(0), m.dims(1), reEIVectors.data());
223+
} else if (m.type() == af::dtype::f32) {
224+
float *matHost = m.host<float>();
225+
Eigen::MatrixXf mat = Eigen::Map<Eigen::MatrixXf>(matHost, m.dims(0), m.dims(1));
226+
227+
// Compute Eigen Values.
228+
Eigen::VectorXcf eivals = mat.eigenvalues();
229+
Eigen::VectorXf reEIVals = eivals.real();
230+
eigenValues = af::array(m.dims(0), reEIVals.data());
231+
232+
// Compute Eigen Vectors.
233+
Eigen::EigenSolver<Eigen::MatrixXf> solution(mat);
234+
Eigen::MatrixXf reEIVectors = solution.eigenvectors().real();
235+
eigenVectors = af::array(m.dims(0), m.dims(1), reEIVectors.data());
236+
}
219237

220238
// Get maximum Eigen Value
221239
af::array maxEigenValue;
@@ -256,7 +274,7 @@ af::array ncc3Dim(af::array tss, af::array centroids) {
256274
int distanceSize = static_cast<unsigned int>(centroids.dims(0)) * 2 - 1;
257275

258276
af::array cc = af::constant(0, static_cast<unsigned int>(centroids.dims(1)), static_cast<unsigned int>(tss.dims(1)),
259-
distanceSize);
277+
distanceSize, tss.type());
260278
for (unsigned int i = 0; i < static_cast<unsigned int>(centroids.dims(1)); i++) {
261279
for (unsigned int j = 0; j < static_cast<unsigned int>(tss.dims(1)); j++) {
262280
cc(i, j, af::span) = af::convolve(tss.col(j), af::flip(centroids.col(i), 0), AF_CONV_EXPAND);
@@ -286,9 +304,9 @@ af::array SBDShifted(af::array ts, af::array centroid) {
286304
int shift = index - tsLength + 1;
287305

288306
if (shift >= 0) {
289-
shiftedTS = af::join(0, af::constant(0, shift), ts(af::range(tsLength - shift), 0));
307+
shiftedTS = af::join(0, af::constant(0, shift, ts.type()), ts(af::range(tsLength - shift), 0));
290308
} else {
291-
shiftedTS = af::join(0, ts(af::range(tsLength + shift) - shift, 0), af::constant(0, -shift));
309+
shiftedTS = af::join(0, ts(af::range(tsLength + shift) - shift, 0), af::constant(0, -shift, ts.type()));
292310
}
293311

294312
return shiftedTS;
@@ -304,8 +322,8 @@ af::array SBDShifted(af::array ts, af::array centroid) {
304322
af::array shapeExtraction(af::array tss, af::array centroid) {
305323
int ntss = tss.dims(1);
306324
int nelements = tss.dims(0);
307-
af::array shiftedTSS = af::constant(0.0f, tss.dims(0), tss.dims(1));
308-
af::array shiftedTSi = af::constant(0.0f, tss.dims(0), 1);
325+
af::array shiftedTSS = af::constant(0, tss.dims(0), tss.dims(1), tss.type());
326+
af::array shiftedTSi = af::constant(0, tss.dims(0), 1, tss.type());
309327
af::array dist;
310328

311329
for (int i = 0; i < ntss; i++) {
@@ -316,7 +334,8 @@ af::array shapeExtraction(af::array tss, af::array centroid) {
316334

317335
shiftedTSS = khiva::normalization::znorm(shiftedTSS);
318336
af::array s = af::matmul(shiftedTSS, shiftedTSS.T());
319-
af::array q = af::identity(nelements, nelements) - (af::constant(1.0, nelements, nelements) / nelements);
337+
af::array q =
338+
af::identity(nelements, nelements) - (af::constant(1.0, nelements, nelements, tss.type()) / nelements);
320339
af::array m = af::matmul(q.T(), s, q);
321340

322341
af::array first = getFirstEigenVector(m);
@@ -365,7 +384,7 @@ af::array refinementStep(af::array tss, af::array centroids, af::array labels) {
365384
* @return The new set of labels.
366385
*/
367386
af::array assignmentStep(af::array tss, af::array centroids, af::array labels) {
368-
af::array min = af::constant(std::numeric_limits<float>::max(), tss.dims(1));
387+
af::array min = af::constant(std::numeric_limits<float>::max(), tss.dims(1), tss.type());
369388
af::array distances = 1 - af::max(ncc3Dim(tss, centroids), 2);
370389
af::min(min, labels, distances, 0);
371390
labels = labels.T();
@@ -379,15 +398,15 @@ void khiva::clustering::kShape(af::array tss, int k, af::array &centroids, af::a
379398
unsigned int nElements = static_cast<unsigned int>(tss.dims(0));
380399

381400
if (centroids.isempty()) {
382-
centroids = af::constant(0.0f, nElements, k);
401+
centroids = af::constant(0, nElements, k, tss.type());
383402
}
384403

385404
if (labels.isempty()) {
386405
labels = generateUniformLabels(nTimeseries, k);
387406
}
388407

389408
af::array normTSS = khiva::normalization::znorm(tss);
390-
af::array distances = af::constant(0.0f, nTimeseries, k);
409+
af::array distances = af::constant(0, nTimeseries, k, tss.type());
391410
af::array newCentroids;
392411

393412
float error = std::numeric_limits<float>::max();

test/clusteringTest.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ void kmeans2() {
5454
}
5555
}
5656

57-
void kShape() {
57+
void kShapeFloat() {
5858
float tolerance = 1e-10;
5959
int maxIter = 100;
6060
float a[35] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 0.0f, 10.0f, 4.0f, 5.0f, 7.0f,
@@ -84,6 +84,36 @@ void kShape() {
8484
}
8585
}
8686

87+
void kShapeDouble() {
88+
double tolerance = 1e-10;
89+
int maxIter = 100;
90+
double a[35] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 0.0, 10.0, 4.0, 5.0, 7.0, -3.0, 0.0, -1.0, 15.0, -12.0, 8.0,
91+
9.0, 4.0, 5.0, 2.0, 8.0, 7.0, -6.0, -1.0, 2.0, 9.0, -5.0, -5.0, -6.0, 7.0, 9.0, 9.0, 0.0};
92+
93+
unsigned int idxh[5] = {0, 1, 2, 0, 1};
94+
95+
double expected_c[21] = {-0.5234, 0.1560, -0.3627, -1.2764, -0.7781, 0.9135, 1.8711,
96+
-0.7825, 1.5990, 0.1701, 0.4082, 0.8845, -1.4969, -0.7825,
97+
-0.6278, 1.3812, -2.0090, 0.5022, 0.6278, -0.0000, 0.1256};
98+
int k = 3;
99+
int nElements = 7;
100+
int ntss = 5;
101+
102+
af::array data = af::array(nElements, ntss, a);
103+
af::array idx = af::array(ntss, 1, idxh);
104+
af::array centroids = af::constant(0, nElements, k, data.type());
105+
106+
khiva::clustering::kShape(data, k, centroids, idx, tolerance, maxIter);
107+
108+
double *calculated_c = centroids.host<double>();
109+
unsigned int *calculated_l = idx.host<unsigned int>();
110+
111+
for (size_t i = 0; i < 21; i++) {
112+
ASSERT_NEAR(calculated_c[i], expected_c[i], 1e-3);
113+
}
114+
}
115+
87116
KHIVA_TEST(ClusteringTests, KMeans, kmeans)
88117
KHIVA_TEST(ClusteringTests, KMeans2, kmeans2)
89-
KHIVA_TEST(ClusteringTests, KShape, kShape)
118+
KHIVA_TEST(ClusteringTests, KShapeFloat, kShapeFloat)
119+
KHIVA_TEST(ClusteringTests, KShapeDouble, kShapeDouble)

0 commit comments

Comments
 (0)