@@ -52,7 +52,8 @@ static int cmp_float_asc(const void *a, const void *b)
5252 }
5353}
5454
55- static float tda_choose_threshold_from_dist (const float * dist ,
55+ static float tda_choose_threshold_from_dist (struct tda_proc_ctx * ctx ,
56+ const float * dist ,
5657 size_t n ,
5758 double quantile )
5859{
@@ -64,16 +65,27 @@ static float tda_choose_threshold_from_dist(const float *dist,
6465 size_t k = 0 ;
6566 float thr = 0.0f ;
6667 double pos ;
68+ double q ;
6769
6870 if (!dist || n < 2 ) {
6971 return 0.0f ;
7072 }
7173
72- if (quantile <= 0.0 ) {
73- quantile = 0.0 ;
74+ /* if user specified threshold as quantile (0 < q < 1),
75+ * override the default quantile argument.
76+ */
77+ if (ctx && ctx -> threshold > 0.0 && ctx -> threshold < 1.0 ) {
78+ q = ctx -> threshold ;
7479 }
75- else if (quantile >= 1.0 ) {
76- quantile = 1.0 ;
80+ else {
81+ q = quantile ;
82+ }
83+
84+ if (q <= 0.0 ) {
85+ q = 0.0 ;
86+ }
87+ else if (q >= 1.0 ) {
88+ q = 1.0 ;
7789 }
7890
7991 /* number of unique off-diagonal distances */
@@ -107,7 +119,7 @@ static float tda_choose_threshold_from_dist(const float *dist,
107119 idx = 0 ;
108120 }
109121 else {
110- pos = quantile * (double ) (k - 1 );
122+ pos = q * (double ) (k - 1 );
111123 if (pos < 0.0 ) {
112124 pos = 0.0 ;
113125 }
@@ -120,7 +132,7 @@ static float tda_choose_threshold_from_dist(const float *dist,
120132 thr = vals [idx ];
121133
122134 flb_debug ("[tda] chosen distance threshold=%.6f (quantile=%.2f, m=%zu)" ,
123- thr , quantile , k );
135+ thr , q , k );
124136
125137 flb_free (vals );
126138
@@ -914,19 +926,18 @@ static void tda_window_run_ripser(struct tda_window *w,
914926 /* --- choose a scale for TDA ---
915927 * Use the number of embedded points n_embed to determine the threshold.
916928 */
917- threshold = tda_choose_threshold_from_dist (dist , n_embed , q );
929+ threshold = tda_choose_threshold_from_dist (ctx , dist , n_embed , q );
918930 if (threshold <= 0.0f ) {
919931 threshold = 0.0f ;
920932 }
921- threshold = 0.0f ;
922933
923934 memset (& betti , 0 , sizeof (betti ));
924935
925936 nq = sizeof (q_candidates ) / sizeof (q_candidates [0 ]);
926937
927938 for (qi = 0 ; qi < nq ; qi ++ ) {
928939 qc = q_candidates [qi ];
929- thr = tda_choose_threshold_from_dist (dist , n_embed , qc );
940+ thr = tda_choose_threshold_from_dist (ctx , dist , n_embed , qc );
930941
931942 if (thr < 0.0f ) {
932943 thr = 0.0f ;
@@ -950,13 +961,28 @@ static void tda_window_run_ripser(struct tda_window *w,
950961 best_b1 = tmp .betti [1 ];
951962 best_b0 = tmp .betti [0 ];
952963 best_b2 = (tmp .num_dims > 2 ) ? tmp .betti [2 ] : 0 ;
953- best_q_for_b1 = q ;
964+
965+ /* if user forced ctx->threshold as quantile, report that,
966+ * otherwise report the candidate quantile qc.
967+ */
968+ if (ctx && ctx -> threshold > 0.0 && ctx -> threshold < 1.0 ) {
969+ best_q_for_b1 = ctx -> threshold ;
970+ }
971+ else {
972+ best_q_for_b1 = qc ;
973+ }
954974 }
955975 /* If all H1 are zero, fall back to H0. */
956976 else if (best_b1 == 0 && tmp .betti [0 ] > best_b0 ) {
957977 best_b0 = tmp .betti [0 ];
958978 best_b2 = (tmp .num_dims > 2 ) ? tmp .betti [2 ] : 0 ;
959- best_q_for_b1 = q ;
979+
980+ if (ctx && ctx -> threshold > 0.0 && ctx -> threshold < 1.0 ) {
981+ best_q_for_b1 = ctx -> threshold ;
982+ }
983+ else {
984+ best_q_for_b1 = qc ;
985+ }
960986 }
961987 }
962988
@@ -1177,6 +1203,12 @@ static struct flb_config_map config_map[] = {
11771203 0 , FLB_TRUE , offsetof(struct tda_proc_ctx , embed_delay ),
11781204 "Delay embedding lag tau in samples. This means that 1 delaying sample."
11791205 },
1206+ {
1207+ FLB_CONFIG_MAP_DOUBLE , "threshold" , "0" ,
1208+ 0 , FLB_TRUE , offsetof(struct tda_proc_ctx , threshold ),
1209+ "Distance scale selector. 0 = auto multi-quantile scan; "
1210+ "(0,1) = use as quantile to pick the distance threshold."
1211+ },
11801212 /* EOF */
11811213 {0 }
11821214};
0 commit comments