40#if (_MSC_VER == 1500 || _MSC_VER == 1600)
41#define NO_INCLUDE_FENV
47#define NO_INCLUDE_FENV
67#error The constant DBL_MANT_DIG could not be defined.
69#define T_FLOAT_MANT_DIG DBL_MANT_DIG
75#error The constant LONG_MAX could not be defined.
78#error The constant INT_MAX could not be defined.
84#define __STDC_LIMIT_MACROS
87typedef __int32 int_fast32_t;
88typedef __int64 int64_t;
91#define __STDC_LIMIT_MACROS
96#define FILL_N std::fill_n
100#define FILL_N stdext::unchecked_fill_n
106 #pragma warning (disable:4700)
109#ifndef HAVE_DIAGNOSTIC
110#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))
111#define HAVE_DIAGNOSTIC 1
115#ifndef HAVE_VISIBILITY
117#define HAVE_VISIBILITY 1
128#pragma GCC visibility push(hidden)
131typedef int_fast32_t t_index;
133#define MAX_INDEX 0x7fffffffL
135#define MAX_INDEX INT32_MAX
137#if (LONG_MAX < MAX_INDEX)
138#error The integer format "t_index" must not have a greater range than "long int".
140#if (INT_MAX > MAX_INDEX)
141#error The integer format "int" must not have a greater range than "t_index".
143typedef double t_float;
152 METHOD_METR_SINGLE = 0,
153 METHOD_METR_COMPLETE = 1,
154 METHOD_METR_AVERAGE = 2,
155 METHOD_METR_WEIGHTED = 3,
156 METHOD_METR_WARD = 4,
157 METHOD_METR_WARD_D = METHOD_METR_WARD,
158 METHOD_METR_CENTROID = 5,
159 METHOD_METR_MEDIAN = 6,
160 METHOD_METR_WARD_D2 = 7,
166enum method_codes_vector {
168 METHOD_VECTOR_SINGLE = 0,
169 METHOD_VECTOR_WARD = 1,
170 METHOD_VECTOR_CENTROID = 2,
171 METHOD_VECTOR_MEDIAN = 3,
173 MIN_METHOD_VECTOR_CODE = 0,
174 MAX_METHOD_VECTOR_CODE = 3
178template <
typename type>
182 auto_array_ptr(auto_array_ptr
const &);
183 auto_array_ptr& operator=(auto_array_ptr
const &);
188 template <
typename index>
189 auto_array_ptr(
index const size)
190 : ptr(new
type[size])
192 template <
typename index,
typename value>
193 auto_array_ptr(
index const size, value
const val)
194 : ptr(new
type[size])
196 FILL_N(ptr, size, val);
204 template <
typename index>
205 void init(
index const size) {
206 ptr =
new type [size];
208 template <
typename index,
typename value>
209 void init(
index const size, value
const val) {
211 FILL_N(ptr, size, val);
213 inline operator type *()
const {
return ptr; }
217 t_index node1, node2;
221inline bool operator< (
const node
a,
const node
b) {
222 return (
a.dist <
b.dist);
225class cluster_result {
227 auto_array_ptr<node> Z;
231 cluster_result(
const t_index size)
236 void append(
const t_index node1,
const t_index node2,
const t_float dist) {
237 Z[pos].node1 = node1;
238 Z[pos].node2 = node2;
243 node * operator[] (
const t_index idx)
const {
return Z + idx; }
249 for (node * ZZ=Z; ZZ!=Z+pos; ++ZZ) {
250 ZZ->dist = std::sqrt(ZZ->dist);
254 void sqrt(
const t_float)
const {
258 void sqrtdouble(
const t_float)
const {
259 for (node * ZZ=Z; ZZ!=Z+pos; ++ZZ) {
260 ZZ->dist = std::sqrt(2*ZZ->dist);
267 #define my_pow std::pow
270 void power(
const t_float
p)
const {
271 t_float
const q = 1/
p;
272 for (node * ZZ=Z; ZZ!=Z+pos; ++ZZ) {
273 ZZ->dist = my_pow(ZZ->dist,q);
277 void plusone(
const t_float)
const {
278 for (node * ZZ=Z; ZZ!=Z+pos; ++ZZ) {
283 void divide(
const t_float denom)
const {
284 for (node * ZZ=Z; ZZ!=Z+pos; ++ZZ) {
290class doubly_linked_list {
302 auto_array_ptr<t_index> succ;
305 auto_array_ptr<t_index> pred;
309 doubly_linked_list(
const t_index size)
315 for (t_index i=0; i<size; ++i) {
323 ~doubly_linked_list() {}
325 void remove(
const t_index idx) {
331 succ[pred[idx]] = succ[idx];
332 pred[succ[idx]] = pred[idx];
337 bool is_inactive(t_index idx)
const {
338 return (succ[idx]==0);
345#define D_(r_,c_) ( D[(static_cast<std::ptrdiff_t>(2*N-3-(r_))*(r_)>>1)+(c_)-1] )
347#define Z_(_r, _c) (Z[(_r)*4 + (_c)])
359 auto_array_ptr<t_index> parent;
363 union_find(
const t_index size)
364 : parent(size>0 ? 2*size-1 : 0, 0)
368 t_index Find (t_index idx)
const {
369 if (parent[idx] != 0 ) {
372 if (parent[idx] != 0 ) {
375 }
while (parent[idx] != 0);
377 t_index tmp = parent[
p];
380 }
while (parent[
p] != idx);
386 void Union (
const t_index node1,
const t_index node2) {
387 parent[node1] = parent[node2] = nextparent++;
396static void MST_linkage_core(
const t_index N,
const t_float *
const D,
397 cluster_result & Z2) {
410 doubly_linked_list active_nodes(N);
411 auto_array_ptr<t_float> d(N);
418 min = std::numeric_limits<t_float>::infinity();
419 for (i=1; i<N; ++i) {
422#pragma GCC diagnostic push
423#pragma GCC diagnostic ignored "-Wfloat-equal"
430 assert(
false &&
"fastcluster: nan error");
432#pragma GCC diagnostic pop
435 Z2.append(0, idx2, min);
437 for (t_index j=1; j<N-1; ++j) {
439 active_nodes.remove(prev_node);
441 idx2 = active_nodes.succ[0];
443 for (i=idx2; i<prev_node; i=active_nodes.succ[i]) {
444 t_float tmp = D_(i, prev_node);
446#pragma GCC diagnostic push
447#pragma GCC diagnostic ignored "-Wfloat-equal"
452 assert(
false &&
"fastcluster: nan error");
454#pragma GCC diagnostic pop
461 for (; i<N; i=active_nodes.succ[i]) {
462 t_float tmp = D_(prev_node, i);
464#pragma GCC diagnostic push
465#pragma GCC diagnostic ignored "-Wfloat-equal"
470 assert(
false &&
"fastcluster: nan error");
472#pragma GCC diagnostic pop
479 Z2.append(prev_node, idx2, min);
485inline static void f_single( t_float *
const b,
const t_float
a ) {
488inline static void f_complete( t_float *
const b,
const t_float
a ) {
491inline static void f_average( t_float *
const b,
const t_float
a,
const t_float s,
const t_float t) {
495#pragma GCC diagnostic push
496#pragma GCC diagnostic ignored "-Wfloat-equal"
499 assert(
false &&
"fastcluster: nan error");
502#pragma GCC diagnostic pop
506inline static void f_weighted( t_float *
const b,
const t_float
a) {
510#pragma GCC diagnostic push
511#pragma GCC diagnostic ignored "-Wfloat-equal"
514 assert(
false &&
"fastcluster: nan error");
517#pragma GCC diagnostic pop
521inline static void f_ward( t_float *
const b,
const t_float
a,
const t_float c,
const t_float s,
const t_float t,
const t_float v) {
522 *
b = ( (v+s)*
a - v*c + (v+t)*(*b) ) / (s+t+v);
526#pragma GCC diagnostic push
527#pragma GCC diagnostic ignored "-Wfloat-equal"
530 assert(
false &&
"fastcluster: nan error");
533#pragma GCC diagnostic pop
537inline static void f_centroid( t_float *
const b,
const t_float
a,
const t_float stc,
const t_float s,
const t_float t) {
538 *
b = s*
a - stc + t*(*b);
541 assert(
false &&
"fastcluster: nan error");
544#pragma GCC diagnostic pop
548inline static void f_median( t_float *
const b,
const t_float
a,
const t_float c_4) {
549 *
b = (
a+(*b))*.5 - c_4;
552#pragma GCC diagnostic push
553#pragma GCC diagnostic ignored "-Wfloat-equal"
556 assert(
false &&
"fastcluster: nan error");
559#pragma GCC diagnostic pop
564template <method_codes method,
typename t_members>
565static void NN_chain_core(
const t_index N, t_float *
const D, t_members *
const members, cluster_result & Z2) {
578 auto_array_ptr<t_index> NN_chain(N);
579 t_index NN_chain_tip = 0;
583 t_float size1, size2;
584 doubly_linked_list active_nodes(N);
588 for (t_float
const * DD=D; DD!=D+(
static_cast<std::ptrdiff_t
>(N)*(N-1)>>1);
591#pragma GCC diagnostic push
592#pragma GCC diagnostic ignored "-Wfloat-equal"
595 assert(
false &&
"fastcluster: nan error");
598#pragma GCC diagnostic pop
603 if (feclearexcept(FE_INVALID)) assert(
false &&
"fastcluster: fenv error");
606 for (t_index j=0; j<N-1; ++j) {
607 if (NN_chain_tip <= 3) {
608 NN_chain[0] = idx1 = active_nodes.start;
611 idx2 = active_nodes.succ[idx1];
613 for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i]) {
614 if (D_(idx1,i) < min) {
622 idx1 = NN_chain[NN_chain_tip-1];
623 idx2 = NN_chain[NN_chain_tip];
624 min = idx1<idx2 ? D_(idx1,idx2) : D_(idx2,idx1);
628 NN_chain[NN_chain_tip] = idx2;
630 for (i=active_nodes.start; i<idx2; i=active_nodes.succ[i]) {
631 if (D_(i,idx2) < min) {
636 for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i]) {
637 if (D_(idx2,i) < min) {
644 idx1 = NN_chain[NN_chain_tip++];
646 }
while (idx2 != NN_chain[NN_chain_tip-2]);
648 Z2.append(idx1, idx2, min);
656 if (method==METHOD_METR_AVERAGE ||
657 method==METHOD_METR_WARD) {
658 size1 =
static_cast<t_float
>(members[idx1]);
659 size2 =
static_cast<t_float
>(members[idx2]);
660 members[idx2] += members[idx1];
664 active_nodes.remove(idx1);
667 case METHOD_METR_SINGLE:
674 for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
675 f_single(&D_(i, idx2), D_(i, idx1) );
677 for (; i<idx2; i=active_nodes.succ[i])
678 f_single(&D_(i, idx2), D_(idx1, i) );
680 for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
681 f_single(&D_(idx2, i), D_(idx1, i) );
684 case METHOD_METR_COMPLETE:
691 for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
692 f_complete(&D_(i, idx2), D_(i, idx1) );
694 for (; i<idx2; i=active_nodes.succ[i])
695 f_complete(&D_(i, idx2), D_(idx1, i) );
697 for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
698 f_complete(&D_(idx2, i), D_(idx1, i) );
701 case METHOD_METR_AVERAGE: {
708 t_float s = size1/(size1+size2);
709 t_float t = size2/(size1+size2);
710 for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
711 f_average(&D_(i, idx2), D_(i, idx1), s, t );
713 for (; i<idx2; i=active_nodes.succ[i])
714 f_average(&D_(i, idx2), D_(idx1, i), s, t );
716 for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
717 f_average(&D_(idx2, i), D_(idx1, i), s, t );
721 case METHOD_METR_WEIGHTED:
728 for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
729 f_weighted(&D_(i, idx2), D_(i, idx1) );
731 for (; i<idx2; i=active_nodes.succ[i])
732 f_weighted(&D_(i, idx2), D_(idx1, i) );
734 for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
735 f_weighted(&D_(idx2, i), D_(idx1, i) );
738 case METHOD_METR_WARD:
747 for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
748 f_ward(&D_(i, idx2), D_(i, idx1), min,
749 size1, size2,
static_cast<t_float
>(members[i]) );
751 for (; i<idx2; i=active_nodes.succ[i])
752 f_ward(&D_(i, idx2), D_(idx1, i), min,
753 size1, size2,
static_cast<t_float
>(members[i]) );
755 for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
756 f_ward(&D_(idx2, i), D_(idx1, i), min,
757 size1, size2,
static_cast<t_float
>(members[i]) );
761 assert(
false &&
"fastcluster: invalid method");
765 if (fetestexcept(FE_INVALID)) assert(
false &&
"fastcluster: fenv error");
769class binary_min_heap {
794 auto_array_ptr<t_index> I;
795 auto_array_ptr<t_index> R;
800 binary_min_heap(binary_min_heap
const &);
801 binary_min_heap & operator=(binary_min_heap
const &);
804 binary_min_heap(t_float *
const A_,
const t_index size_)
805 : A(A_), size(size_), I(size), R(size)
808 for (t_index i=0; i<size; ++i)
812 binary_min_heap(t_float *
const A_,
const t_index size1,
const t_index size2,
814 : A(A_), size(size1), I(size1), R(size2)
817 for (t_index i=0; i<size; ++i) {
823 ~binary_min_heap() {}
833 for (idx=(size>>1); idx>0; ) {
839 inline t_index argmin()
const {
852 void remove(t_index idx) {
857 if ( H(size)<=A[idx] ) {
865 void replace (
const t_index idxold,
const t_index idxnew,
867 R[idxnew] = R[idxold];
868 I[R[idxnew]] = idxnew;
870 update_leq(idxnew, val);
872 update_geq(idxnew, val);
875 void update (
const t_index idx,
const t_float val )
const {
879 update_leq(idx, val);
881 update_geq(idx, val);
884 void update_leq (
const t_index idx,
const t_float val )
const {
890 void update_geq (
const t_index idx,
const t_float val )
const {
897 void update_leq_ (t_index i)
const {
899 for ( ; (i>0) && ( H(i)<H(j=(i-1)>>1) ); i=j)
903 void update_geq_ (t_index i)
const {
905 for ( ; (j=2*i+1)<size; i=j) {
908 if ( j>=size || H(j)>=H(i) )
break;
910 else if ( j+1<size && H(j+1)<H(j) ) ++j;
915 void heap_swap(
const t_index i,
const t_index j)
const {
924 inline t_float H(
const t_index i)
const {
930template <method_codes method,
typename t_members>
931static void generic_linkage(
const t_index N, t_float *
const D, t_members *
const members, cluster_result & Z2) {
938 const t_index N_1 = N-1;
942 auto_array_ptr<t_index> n_nghbr(N_1);
943 auto_array_ptr<t_float> mindist(N_1);
944 auto_array_ptr<t_index> row_repr(N);
946 doubly_linked_list active_nodes(N);
947 binary_min_heap nn_distances(&*mindist, N_1);
949 t_index node1, node2;
950 t_float size1, size2;
963 t_float
const * DD = D;
964 for (i=0; i<N_1; ++i) {
965 min = std::numeric_limits<t_float>::infinity();
966 for (idx=j=i+1; j<N; ++j, ++DD) {
968#pragma GCC diagnostic push
969#pragma GCC diagnostic ignored "-Wfloat-equal"
976 assert(
false &&
"fastcluster: nan error");
979#pragma GCC diagnostic pop
987 nn_distances.heapify();
990 if (feclearexcept(FE_INVALID)) assert(
false &&
"fastcluster: fenv error");
994 for (i=0; i<N_1; ++i) {
1028 idx1 = nn_distances.argmin();
1029 if (method != METHOD_METR_SINGLE) {
1030 while ( mindist[idx1] < D_(idx1, n_nghbr[idx1]) ) {
1032 n_nghbr[idx1] = j = active_nodes.succ[idx1];
1034 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1035 if (D_(idx1,j)<min) {
1042 nn_distances.update_geq(idx1, min);
1043 idx1 = nn_distances.argmin();
1047 nn_distances.heap_pop();
1048 idx2 = n_nghbr[idx1];
1051 node1 = row_repr[idx1];
1052 node2 = row_repr[idx2];
1054 if (method==METHOD_METR_AVERAGE ||
1055 method==METHOD_METR_WARD ||
1056 method==METHOD_METR_CENTROID) {
1057 size1 =
static_cast<t_float
>(members[idx1]);
1058 size2 =
static_cast<t_float
>(members[idx2]);
1059 members[idx2] += members[idx1];
1061 Z2.append(node1, node2, mindist[idx1]);
1064 active_nodes.remove(idx1);
1066 row_repr[idx2] = N+i;
1070 case METHOD_METR_SINGLE:
1077 for (j=active_nodes.start; j<idx1; j=active_nodes.succ[j]) {
1078 f_single(&D_(j, idx2), D_(j, idx1));
1079 if (n_nghbr[j] == idx1)
1083 for (; j<idx2; j=active_nodes.succ[j]) {
1084 f_single(&D_(j, idx2), D_(idx1, j));
1087 if (D_(j, idx2) < mindist[j]) {
1088 nn_distances.update_leq(j, D_(j, idx2));
1095 min = mindist[idx2];
1096 for (j=active_nodes.succ[idx2]; j<N; j=active_nodes.succ[j]) {
1097 f_single(&D_(idx2, j), D_(idx1, j) );
1098 if (D_(idx2, j) < min) {
1103 nn_distances.update_leq(idx2, min);
1107 case METHOD_METR_COMPLETE:
1114 for (j=active_nodes.start; j<idx1; j=active_nodes.succ[j]) {
1115 f_complete(&D_(j, idx2), D_(j, idx1) );
1116 if (n_nghbr[j] == idx1)
1120 for (; j<idx2; j=active_nodes.succ[j])
1121 f_complete(&D_(j, idx2), D_(idx1, j) );
1123 for (j=active_nodes.succ[idx2]; j<N; j=active_nodes.succ[j])
1124 f_complete(&D_(idx2, j), D_(idx1, j) );
1127 case METHOD_METR_AVERAGE: {
1134 t_float s = size1/(size1+size2);
1135 t_float t = size2/(size1+size2);
1136 for (j=active_nodes.start; j<idx1; j=active_nodes.succ[j]) {
1137 f_average(&D_(j, idx2), D_(j, idx1), s, t);
1138 if (n_nghbr[j] == idx1)
1142 for (; j<idx2; j=active_nodes.succ[j]) {
1143 f_average(&D_(j, idx2), D_(idx1, j), s, t);
1144 if (D_(j, idx2) < mindist[j]) {
1145 nn_distances.update_leq(j, D_(j, idx2));
1151 n_nghbr[idx2] = j = active_nodes.succ[idx2];
1152 f_average(&D_(idx2, j), D_(idx1, j), s, t);
1154 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1155 f_average(&D_(idx2, j), D_(idx1, j), s, t);
1156 if (D_(idx2,j) < min) {
1161 nn_distances.update(idx2, min);
1166 case METHOD_METR_WEIGHTED:
1173 for (j=active_nodes.start; j<idx1; j=active_nodes.succ[j]) {
1174 f_weighted(&D_(j, idx2), D_(j, idx1) );
1175 if (n_nghbr[j] == idx1)
1179 for (; j<idx2; j=active_nodes.succ[j]) {
1180 f_weighted(&D_(j, idx2), D_(idx1, j) );
1181 if (D_(j, idx2) < mindist[j]) {
1182 nn_distances.update_leq(j, D_(j, idx2));
1188 n_nghbr[idx2] = j = active_nodes.succ[idx2];
1189 f_weighted(&D_(idx2, j), D_(idx1, j) );
1191 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1192 f_weighted(&D_(idx2, j), D_(idx1, j) );
1193 if (D_(idx2,j) < min) {
1198 nn_distances.update(idx2, min);
1202 case METHOD_METR_WARD:
1210 for (j=active_nodes.start; j<idx1; j=active_nodes.succ[j]) {
1211 f_ward(&D_(j, idx2), D_(j, idx1), mindist[idx1],
1212 size1, size2,
static_cast<t_float
>(members[j]) );
1213 if (n_nghbr[j] == idx1)
1217 for (; j<idx2; j=active_nodes.succ[j]) {
1218 f_ward(&D_(j, idx2), D_(idx1, j), mindist[idx1], size1, size2,
1219 static_cast<t_float
>(members[j]) );
1220 if (D_(j, idx2) < mindist[j]) {
1221 nn_distances.update_leq(j, D_(j, idx2));
1227 n_nghbr[idx2] = j = active_nodes.succ[idx2];
1228 f_ward(&D_(idx2, j), D_(idx1, j), mindist[idx1],
1229 size1, size2,
static_cast<t_float
>(members[j]) );
1231 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1232 f_ward(&D_(idx2, j), D_(idx1, j), mindist[idx1],
1233 size1, size2,
static_cast<t_float
>(members[j]) );
1234 if (D_(idx2,j) < min) {
1239 nn_distances.update(idx2, min);
1243 case METHOD_METR_CENTROID: {
1251 t_float s = size1/(size1+size2);
1252 t_float t = size2/(size1+size2);
1253 t_float stc = s*t*mindist[idx1];
1254 for (j=active_nodes.start; j<idx1; j=active_nodes.succ[j]) {
1255 f_centroid(&D_(j, idx2), D_(j, idx1), stc, s, t);
1256 if (D_(j, idx2) < mindist[j]) {
1257 nn_distances.update_leq(j, D_(j, idx2));
1260 else if (n_nghbr[j] == idx1)
1264 for (; j<idx2; j=active_nodes.succ[j]) {
1265 f_centroid(&D_(j, idx2), D_(idx1, j), stc, s, t);
1266 if (D_(j, idx2) < mindist[j]) {
1267 nn_distances.update_leq(j, D_(j, idx2));
1273 n_nghbr[idx2] = j = active_nodes.succ[idx2];
1274 f_centroid(&D_(idx2, j), D_(idx1, j), stc, s, t);
1276 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1277 f_centroid(&D_(idx2, j), D_(idx1, j), stc, s, t);
1278 if (D_(idx2,j) < min) {
1283 nn_distances.update(idx2, min);
1288 case METHOD_METR_MEDIAN: {
1296 t_float c_4 = mindist[idx1]*.25;
1297 for (j=active_nodes.start; j<idx1; j=active_nodes.succ[j]) {
1298 f_median(&D_(j, idx2), D_(j, idx1), c_4 );
1299 if (D_(j, idx2) < mindist[j]) {
1300 nn_distances.update_leq(j, D_(j, idx2));
1303 else if (n_nghbr[j] == idx1)
1307 for (; j<idx2; j=active_nodes.succ[j]) {
1308 f_median(&D_(j, idx2), D_(idx1, j), c_4 );
1309 if (D_(j, idx2) < mindist[j]) {
1310 nn_distances.update_leq(j, D_(j, idx2));
1316 n_nghbr[idx2] = j = active_nodes.succ[idx2];
1317 f_median(&D_(idx2, j), D_(idx1, j), c_4 );
1319 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1320 f_median(&D_(idx2, j), D_(idx1, j), c_4 );
1321 if (D_(idx2,j) < min) {
1326 nn_distances.update(idx2, min);
1332 assert(
false &&
"fastcluster: invalid method");
1336 if (fetestexcept(FE_INVALID)) assert(
false &&
"fastcluster: fenv error");
1344template <
typename t_dissimilarity>
1345static void MST_linkage_core_vector(
const t_index N,
1346 t_dissimilarity & dist,
1347 cluster_result & Z2) {
1360 doubly_linked_list active_nodes(N);
1361 auto_array_ptr<t_float> d(N);
1368 min = std::numeric_limits<t_float>::infinity();
1369 for (i=1; i<N; ++i) {
1372#pragma GCC diagnostic push
1373#pragma GCC diagnostic ignored "-Wfloat-equal"
1380 assert(
false &&
"fastcluster: nan error");
1382#pragma GCC diagnostic pop
1386 Z2.append(0, idx2, min);
1388 for (t_index j=1; j<N-1; ++j) {
1390 active_nodes.remove(prev_node);
1392 idx2 = active_nodes.succ[0];
1395 for (i=idx2; i<N; i=active_nodes.succ[i]) {
1396 t_float tmp = dist(i, prev_node);
1398#pragma GCC diagnostic push
1399#pragma GCC diagnostic ignored "-Wfloat-equal"
1404 assert(
false &&
"fastcluster: nan error");
1406#pragma GCC diagnostic pop
1413 Z2.append(prev_node, idx2, min);
1417template <method_codes_vector method,
typename t_dissimilarity>
1418static void generic_linkage_vector(
const t_index N,
1419 t_dissimilarity & dist,
1420 cluster_result & Z2) {
1429 const t_index N_1 = N-1;
1433 auto_array_ptr<t_index> n_nghbr(N_1);
1434 auto_array_ptr<t_float> mindist(N_1);
1435 auto_array_ptr<t_index> row_repr(N);
1437 doubly_linked_list active_nodes(N);
1438 binary_min_heap nn_distances(&*mindist, N_1);
1440 t_index node1, node2;
1451 for (i=0; i<N_1; ++i) {
1452 min = std::numeric_limits<t_float>::infinity();
1454 for (idx=j=i+1; j<N; ++j) {
1457 case METHOD_VECTOR_WARD:
1458 tmp = dist.ward_initial(i,j);
1461 tmp = dist.template sqeuclidean<true>(i,j);
1469 case METHOD_VECTOR_WARD:
1470 mindist[i] = t_dissimilarity::ward_initial_conversion(min);
1480 nn_distances.heapify();
1483 for (i=0; i<N_1; ++i) {
1484 idx1 = nn_distances.argmin();
1486 while ( active_nodes.is_inactive(n_nghbr[idx1]) ) {
1488 n_nghbr[idx1] = j = active_nodes.succ[idx1];
1490 case METHOD_VECTOR_WARD:
1491 min = dist.ward(idx1,j);
1492 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1493 t_float
const tmp = dist.ward(idx1,j);
1501 min = dist.template sqeuclidean<true>(idx1,j);
1502 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1503 t_float
const tmp = dist.template sqeuclidean<true>(idx1,j);
1512 nn_distances.update_geq(idx1, min);
1513 idx1 = nn_distances.argmin();
1516 nn_distances.heap_pop();
1517 idx2 = n_nghbr[idx1];
1520 node1 = row_repr[idx1];
1521 node2 = row_repr[idx2];
1523 Z2.append(node1, node2, mindist[idx1]);
1526 case METHOD_VECTOR_WARD:
1527 case METHOD_VECTOR_CENTROID:
1528 dist.merge_inplace(idx1, idx2);
1530 case METHOD_VECTOR_MEDIAN:
1531 dist.merge_inplace_weighted(idx1, idx2);
1534 assert(
false &&
"fastcluster: invalid method");
1538 row_repr[idx2] = N+i;
1540 active_nodes.remove(idx1);
1544 case METHOD_VECTOR_WARD:
1552 for (j=active_nodes.start; j<idx1; j=active_nodes.succ[j]) {
1553 if (n_nghbr[j] == idx2) {
1558 for ( ; j<idx2; j=active_nodes.succ[j]) {
1559 t_float
const tmp = dist.ward(j, idx2);
1560 if (tmp < mindist[j]) {
1561 nn_distances.update_leq(j, tmp);
1564 else if (n_nghbr[j]==idx2) {
1570 n_nghbr[idx2] = j = active_nodes.succ[idx2];
1571 min = dist.ward(idx2,j);
1572 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1573 t_float
const tmp = dist.ward(idx2,j);
1579 nn_distances.update(idx2, min);
1590 for (j=active_nodes.start; j<idx2; j=active_nodes.succ[j]) {
1591 t_float
const tmp = dist.template sqeuclidean<true>(j, idx2);
1592 if (tmp < mindist[j]) {
1593 nn_distances.update_leq(j, tmp);
1596 else if (n_nghbr[j] == idx2)
1601 n_nghbr[idx2] = j = active_nodes.succ[idx2];
1602 min = dist.template sqeuclidean<true>(idx2,j);
1603 for (j=active_nodes.succ[j]; j<N; j=active_nodes.succ[j]) {
1604 t_float
const tmp = dist.template sqeuclidean<true>(idx2, j);
1610 nn_distances.update(idx2, min);
1616template <method_codes_vector method,
typename t_dissimilarity>
1617static void generic_linkage_vector_alternative(
const t_index N,
1618 t_dissimilarity & dist,
1619 cluster_result & Z2) {
1628 const t_index N_1 = N-1;
1632 auto_array_ptr<t_index> n_nghbr(2*N-2);
1633 auto_array_ptr<t_float> mindist(2*N-2);
1635 doubly_linked_list active_nodes(N+N_1);
1636 binary_min_heap nn_distances(&*mindist, N_1, 2*N-2, 1);
1644 for (i=1; i<N; ++i) {
1645 min = std::numeric_limits<t_float>::infinity();
1647 for (idx=j=0; j<i; ++j) {
1650 case METHOD_VECTOR_WARD:
1651 tmp = dist.ward_initial(i,j);
1654 tmp = dist.template sqeuclidean<true>(i,j);
1662 case METHOD_VECTOR_WARD:
1663 mindist[i] = t_dissimilarity::ward_initial_conversion(min);
1673 nn_distances.heapify();
1676 for (i=N; i<N+N_1; ++i) {
1696 idx1 = nn_distances.argmin();
1697 while ( active_nodes.is_inactive(n_nghbr[idx1]) ) {
1699 n_nghbr[idx1] = j = active_nodes.start;
1701 case METHOD_VECTOR_WARD:
1702 min = dist.ward_extended(idx1,j);
1703 for (j=active_nodes.succ[j]; j<idx1; j=active_nodes.succ[j]) {
1704 t_float tmp = dist.ward_extended(idx1,j);
1712 min = dist.sqeuclidean_extended(idx1,j);
1713 for (j=active_nodes.succ[j]; j<idx1; j=active_nodes.succ[j]) {
1714 t_float
const tmp = dist.sqeuclidean_extended(idx1,j);
1723 nn_distances.update_geq(idx1, min);
1724 idx1 = nn_distances.argmin();
1727 idx2 = n_nghbr[idx1];
1728 active_nodes.remove(idx1);
1729 active_nodes.remove(idx2);
1731 Z2.append(idx1, idx2, mindist[idx1]);
1735 case METHOD_VECTOR_WARD:
1736 case METHOD_VECTOR_CENTROID:
1737 dist.merge(idx1, idx2, i);
1740 case METHOD_VECTOR_MEDIAN:
1741 dist.merge_weighted(idx1, idx2, i);
1745 assert(
false &&
"fastcluster: invalid method");
1748 n_nghbr[i] = active_nodes.start;
1749 if (method==METHOD_VECTOR_WARD) {
1756 min = dist.ward_extended(active_nodes.start, i);
1757 for (j=active_nodes.succ[active_nodes.start]; j<i;
1758 j=active_nodes.succ[j]) {
1759 t_float tmp = dist.ward_extended(j, i);
1773 min = dist.sqeuclidean_extended(active_nodes.start, i);
1774 for (j=active_nodes.succ[active_nodes.start]; j<i;
1775 j=active_nodes.succ[j]) {
1776 t_float tmp = dist.sqeuclidean_extended(j, i);
1783 if (idx2<active_nodes.start) {
1784 nn_distances.remove(active_nodes.start);
1786 nn_distances.remove(idx2);
1788 nn_distances.replace(idx1, i, min);
1794#pragma GCC visibility pop