1 #include "cado.h" // IWYU pragma: keep
2 #include <math.h>
3 #include <stdlib.h>
4 #include <float.h>
5 #include <stdio.h>
6 #include "convex_hull.h"
7 #include "generate_strategies.h"
8 #include "facul.hpp"
9 #include "facul_ecm.h"
10 #include "macros.h"
11 #include "modredc_ul.h" // MODREDCUL_MAXBITS
12 #include "point.h"      // point_get_number
13 
14 
15 
is_good_decomp(decomp_t * dec,int len_p_min,int len_p_max)16 static int is_good_decomp(decomp_t * dec, int len_p_min, int len_p_max)
17 {
18     int len = dec->len;
19     for (int i = 0; i < len; i++)
20 	if (dec->tab[i] > len_p_max || dec->tab[i] < len_p_min)
21 	    return false;
22     return true;
23 }
24 
25 /************************************************************************/
26 /*                      COLLECT DATA FOR ONLY ONE COFACTOR              */
27 /************************************************************************/
28 /*
29   Compute the probability to doesn't find a non-trivial factor when we
30   use this method 'fm'.
31  */
32 double
compute_proba_method_one_decomp(decomp_t * dec,fm_t * fm)33 compute_proba_method_one_decomp (decomp_t* dec, fm_t* fm)
34 {
35     double *proba_suc = fm_get_proba(fm);
36     int len_proba = fm_get_len_proba(fm);
37     double proba_fail = 1;
38     for (int i = 0; i < dec->len; i++) {
39 	int j = dec->tab[i] - fm->len_p_min;
40 	ASSERT (j >= 0);
41 	/* j < 0 => This probability wasn't computed in the
42 	   precomputed benchmark.
43 	*/
44 	if (j < len_proba)
45 	    proba_fail *= (1 - proba_suc[j]);
46 	//else //the probability seems closest to 0.
47     }
48     return proba_fail;
49 }
50 
51 /*
52   Compute the probability to find a non-trivial factor in a good decomposition.
53  */
54 double
compute_proba_strategy(tabular_decomp_t * init_tab,strategy_t * strat,int len_p_min,int len_p_max)55 compute_proba_strategy(tabular_decomp_t * init_tab, strategy_t * strat,
56 		       int len_p_min, int len_p_max)
57 {
58     double all = 0.0;
59     double nb_found_elem = 0;
60     int nb_fm = tabular_fm_get_index(strat->tab_fm);
61     int nb_decomp = init_tab->index;
62     tabular_fm_t *tab_fm = strat->tab_fm;
63 
64     for (int index_decomp = 0; index_decomp < nb_decomp; index_decomp++) {
65 	decomp_t *dec = init_tab->tab[index_decomp];
66 	if (is_good_decomp(dec, len_p_min, len_p_max)) {
67 	    //the probability to doesn't find a non trivial factor
68 	    //with all methods in our strategy.
69 	    double p_fail_all = 1;
70 	    for (int index_fm = 0; index_fm < nb_fm; index_fm++) {
71 		fm_t* elem = tabular_fm_get_fm(tab_fm, index_fm);
72 		double p_fail_one = compute_proba_method_one_decomp (dec, elem);
73 		p_fail_all *= p_fail_one;
74 		if (elem->method[0] == PM1_METHOD ||
75 		    elem->method[0] == PP1_27_METHOD ||
76 		    elem->method[0] == PP1_65_METHOD)
77 		    //because if you chain PP1||PM1 to PM1||PP1-->they are
78 		    //not independant.
79 		    p_fail_all = (p_fail_one + p_fail_all) / 2;
80 	    }
81 	    nb_found_elem += (1 - p_fail_all) * dec->nb_elem;
82 	}
83 	all += dec->nb_elem;
84     }
85     if (all < (double)LDBL_EPSILON) // all == 0.0 -> it exists any decomposition!
86       return 0;
87     return nb_found_elem / all;
88 }
89 
90 /*
91   Compute the average time when we apply our strategy 'strat' in a
92   cofactor of r bits!
93 */
compute_time_strategy(tabular_decomp_t * init_tab,strategy_t * strat,int r)94 double compute_time_strategy(tabular_decomp_t * init_tab, strategy_t * strat, int r)
95 {
96     int nb_fm = tabular_fm_get_index(strat->tab_fm);
97     int nb_decomp = init_tab->index;
98     tabular_fm_t *tab_fm = strat->tab_fm;
99     //{{
100     /*
101       We add 0.5 to the length of one word, because for our times the
102       lenght is inclusive. For example, if MODREDCUL_MAXBITS = 64
103       bits, a cofactor is in one word if is lenght is less OR equal to
104       64 bits. So, if you don't add 0.5 to MODREDCUL_MAXBITS, you
105       lost the equal and thus insert an error in your maths.
106     */
107     double half_word = (MODREDCUL_MAXBITS+0.5)/2.0;
108     int number_half_wd = floor(r /half_word);
109     //the next computation is necessary in the relation with the
110     //benchmark in gfm!
111     int ind_time = (number_half_wd <2)? 0: number_half_wd - 1;
112     //}}
113 
114     double time_average = 0;
115     //store the number of elements in the different decompositions!
116     double all = 0.0;
117     for (int index_decomp = 0; index_decomp < nb_decomp; index_decomp++) {
118 	decomp_t *dec = init_tab->tab[index_decomp];
119 	double time_dec = 0;
120 	double proba_fail_all = 1;
121 	double time_method = 0;
122 	//compute the time of each decomposition
123 	for (int index_fm = 0; index_fm < nb_fm; index_fm++) {
124 	    fm_t* elem = tabular_fm_get_fm(tab_fm, index_fm);
125 	    int len_time = fm_get_len_time (elem);
126 	    if (ind_time >= len_time)
127 	      time_method = elem->time[len_time-1];
128 	    else
129 	      time_method = elem->time[ind_time];
130 	    time_dec += time_method * proba_fail_all;
131 
132 	    double proba_fail_method =
133 	      compute_proba_method_one_decomp (dec, elem);
134 	    proba_fail_all *= proba_fail_method;
135 	    if (elem->method[0] == PM1_METHOD ||
136 		elem->method[0] == PP1_27_METHOD ||
137 		elem->method[0] == PP1_65_METHOD)
138 	      //because if you chain PP1||PM1 to PM1||PP1-->they are
139 	      //not independant.
140 	      proba_fail_all = (proba_fail_all + proba_fail_method) / 2;
141 	}
142 
143 	time_average += time_dec * dec->nb_elem;
144 	all += dec->nb_elem;
145     }
146     if (all < (double)LDBL_EPSILON) // all == 0.0 -> it exists any decomposition!
147       return 0;
148 
149     return time_average / all;
150 }
151 
152 /*
153   As their name suggests, this function adds one strategy to our array
154   't' without the zero methods.
155 */
156 static void
tabular_strategy_add_strategy_without_zero(tabular_strategy_t * t,strategy_t * strategy)157 tabular_strategy_add_strategy_without_zero(tabular_strategy_t * t,
158 					   strategy_t * strategy)
159 {
160     if (t->index >= t->size)
161 	tabular_strategy_realloc(t);
162 
163     strategy_t *elem = strategy_create();
164     int len = strategy->tab_fm->index;
165     int strat_is_zero = true;
166     for (int i = 0; i < len; i++) {
167 	if (!tabular_fm_is_zero(strategy->tab_fm, i)) {
168 	    strat_is_zero = false;
169 	    tabular_fm_add_fm(elem->tab_fm, strategy->tab_fm->tab[i]);
170 	}
171     }
172     if (strat_is_zero)
173 	tabular_fm_add_fm(elem->tab_fm, strategy->tab_fm->tab[0]);
174 
175     elem->proba = strategy->proba;
176     elem->time = strategy->time;
177     t->tab[t->index] = elem;
178     t->index++;
179 }
180 
181 /************************************************************************/
182 /*                   GENERATE MATRIX                                    */
183 /************************************************************************/
184 /*
185   This function add differents chains of ecm to the strategy 'strat'.
186   Note that the variable 'lbucket' allows to add ecm by bucket of
187   length 'lbucket'.
188  */
189 static void
generate_collect_iter_ecm(fm_t * zero,tabular_fm_t * ecm,int ind_ecm,strategy_t * strat,int ind_tab,int index_iter,int len_iteration,int lbucket,tabular_decomp_t * init_tab,tabular_strategy_t ** all_strat_ptr,int fbb,int lpb,int r,int is_already_used_B12M16)190 generate_collect_iter_ecm(fm_t * zero, tabular_fm_t * ecm,
191 			  int ind_ecm, strategy_t * strat, int ind_tab,
192 			  int index_iter, int len_iteration, int lbucket,
193 			  tabular_decomp_t *init_tab,
194 			  tabular_strategy_t**all_strat_ptr,
195 			  int fbb, int lpb, int r, int is_already_used_B12M16)
196 {
197     tabular_strategy_t * all_strat = *all_strat_ptr;
198     if (index_iter >= len_iteration) {
199 	int nb_strat = all_strat->index;
200 	tabular_strategy_add_strategy_without_zero(all_strat, strat);
201 	double proba =
202 	    compute_proba_strategy(init_tab, all_strat->tab[nb_strat], fbb,lpb);
203 	double time =
204 	    compute_time_strategy(init_tab, all_strat->tab[nb_strat], r);
205 
206 	strategy_set_proba(all_strat->tab[nb_strat], proba);
207 	strategy_set_time(all_strat->tab[nb_strat], time);
208     } else {
209 	for (int i = ind_ecm; i < ecm->index; i++) {
210 	  /* The curve BRENT12 and MONTY16 are curves with only one
211 	  sigma. So use it only one time.*/
212 	  if (ecm->tab[i]->method[1] == MONTY16 || //MONTY16
213 	      ecm->tab[i]->method[1] == BRENT12) //BRENT12
214 	    {
215 	      if (is_already_used_B12M16)
216 		continue;
217 	      tabular_fm_set_fm_index(strat->tab_fm, ecm->tab[i], ind_tab);
218 	      generate_collect_iter_ecm(zero, ecm, i+1, strat,ind_tab+1,
219 					index_iter + 1, len_iteration,
220 					lbucket, init_tab, all_strat_ptr,
221 					fbb, lpb, r, true);
222 	    }
223 	  else //MONTY12
224 	    {
225 	      for (int j = 0; j < lbucket && ind_tab+j < strat->tab_fm->index; j++)
226 		{
227 		  tabular_fm_set_fm_index(strat->tab_fm, ecm->tab[i], ind_tab+j);
228 		}
229 	      generate_collect_iter_ecm(zero, ecm, i, strat,ind_tab+lbucket,
230 					index_iter + lbucket, len_iteration,
231 					lbucket+1, init_tab, all_strat_ptr,
232 					fbb, lpb,r, is_already_used_B12M16);
233 	    }
234 	}
235         all_strat = *all_strat_ptr; // might have changed during recursive call
236     	/* to protect the ram, we reduce the number of strategies by
237 	   the convex hull when this number become too big.*/
238 	if (all_strat->index < 100000) {
239 	    tabular_strategy_t* ch = convex_hull_strategy(all_strat);
240 	    //clear previous collect and start a new collect.
241 	    tabular_strategy_free(all_strat);
242 	    *all_strat_ptr = tabular_strategy_create();
243 	    tabular_strategy_concat(*all_strat_ptr, ch);
244 	    tabular_strategy_free(ch);
245 	}
246     }
247 }
248 
249 /*
250   This function allows to generate strategies, computes their data,
251   and selects the convex hull of these strategies for one size of
252   cofactor 'r'.  It allows to avoid to full the RAM when we generated
253   strategies!
254   Moreover, this generator chains our factoring methods
255   such that:
256  PM1 (0/1) + PP1 (0/1) + ECM-M12(0/1/2...)+ ECM-M16/B12(0/1)+ ECM-M12(0/1/...)
257 */
generate_strategies_oneside(tabular_decomp_t * init_tab,fm_t * zero,tabular_fm_t * pm1,tabular_fm_t * pp1,tabular_fm_t * ecm,int ncurves,unsigned long lim,int lpb,int r)258 tabular_strategy_t *generate_strategies_oneside(tabular_decomp_t * init_tab,
259 						fm_t * zero, tabular_fm_t * pm1,
260 						tabular_fm_t * pp1,
261 						tabular_fm_t * ecm,
262 						int ncurves, unsigned long lim,
263 						int lpb, int r)
264 {
265     //contains the final result
266     tabular_strategy_t *res;
267 
268     //check the cases where r is trivial!!
269     //{{
270     int fbb = ceil (log2 ((double) (lim + 1)));
271     int lim_is_prime = 2 * fbb - 1;
272 
273     ASSERT_ALWAYS((init_tab != NULL) == (r >= lim_is_prime));
274 
275     /*
276       In this case, r is already a prime number!
277       We define two zero strategies to manage:
278       - the case where r is a good prime number (fbb<r<lpb)
279       |-> the probability is equal to 1.
280       - the case where r is a prime number too big (lpb < r <
281       fbb^2) or because the lenght of r is impossible (r<fbb).
282       - |-> the probability is equal to 0.
283     */
284     if (r < lim_is_prime) {
285 	strategy_t *st_zero = strategy_create();
286 	strategy_add_fm(st_zero, zero);
287 	strategy_set_time(st_zero, 0.0);
288 
289 	if (r != 1 && (r < fbb || r > lpb))
290 	    strategy_set_proba(st_zero, 0);
291 	else	// r==1 or fbb<= r0 <= lpb
292 	    strategy_set_proba(st_zero, 1.0);
293 	res = tabular_strategy_create();
294 	tabular_strategy_add_strategy(res, st_zero);
295 	strategy_free(st_zero);
296 	return res;
297     }
298     //}}
299     //contains strategies which will be processed.
300     tabular_strategy_t *all_strat = tabular_strategy_create();
301 
302     int len_pm1 = pm1->index;
303     int len_pp1 = pp1->index;
304 
305     //init strat
306     int len_strat = 2 + ncurves;
307     //printf ("len_strat = %d, ncurve = %d\n",len_strat, ncurves);
308     strategy_t *strat = strategy_create();
309     for (int i = 0; i < len_strat; i++)
310 	strategy_add_fm(strat, zero);
311 
312     tabular_fm_t *tab_strat = strat->tab_fm;
313     //PM1
314     for (int ind_pm1 = 0; ind_pm1 < len_pm1; ind_pm1++) {
315       double current_proba_pm1 = pm1->tab[ind_pm1]->proba[0];
316       tabular_fm_set_fm_index(tab_strat, pm1->tab[ind_pm1], 0);
317       //PP1
318       for (int ind_pp1 = 0; ind_pp1 < len_pp1; ind_pp1++) {
319         if ( pp1->tab[ind_pp1]->method[2] != 0 //B1==0
320 	     && pp1->tab[ind_pp1]->proba[0] < current_proba_pm1)
321 	  continue;
322 	tabular_fm_set_fm_index(tab_strat, pp1->tab[ind_pp1], 1);
323 
324 	//ECM (M12-B12-M16)
325 	generate_collect_iter_ecm(zero, ecm, 0, strat, 2,
326 				  0, ncurves, 0, init_tab,
327 				  &all_strat, fbb, lpb, r, false);
328       }
329     }
330     //compute the final convex hull.
331     res = convex_hull_strategy(all_strat);
332     tabular_strategy_free(all_strat);
333     strategy_free(strat);
334     return res;
335 }
336 
337 /*
338   As their name suggests, this function concatenates two strategies but
339   take into account the side of each strategy: st1 will be the
340   first_side and st2 the other side.
341 */
342 
concat_strategies(strategy_t * st1,strategy_t * st2,int first_side)343 static strategy_t *concat_strategies(strategy_t * st1, strategy_t * st2,
344 				     int first_side)
345 {
346     strategy_t *st = strategy_create();
347     int len1 = st1->tab_fm->index;
348     int len2 = st2->tab_fm->index;
349     st->len_side = len1 + len2;
350     if (st->side == NULL)
351 	st->side = (int*) malloc(sizeof(int) * (st->len_side));
352     else
353 	st->side = (int*) realloc(st->side, sizeof(int) * (st->len_side));
354     int side = first_side;
355     for (int i = 0; i < len1; i++) {
356 	strategy_add_fm(st, st1->tab_fm->tab[i]);
357 	st->side[i] = side;
358     }
359     side = first_side ? 0 : 1;
360     for (int i = 0; i < len2; i++) {
361 	strategy_add_fm(st, st2->tab_fm->tab[i]);
362 	st->side[len1 + i] = side;
363     }
364     return st;
365 }
366 
367 /*
368   returns the best strategies to factor a couple (r0, r1), from a set
369   of optimal strategies for each side. Note that, the probability and
370   the time to find a non-trivial for each side must be previously
371   computed!
372  */
generate_strategy_r0_r1(tabular_strategy_t * strat_r0,tabular_strategy_t * strat_r1)373 tabular_strategy_t *generate_strategy_r0_r1(tabular_strategy_t * strat_r0,
374 					    tabular_strategy_t * strat_r1)
375 {
376     int len_r0 = strat_r0->index;
377     int len_r1 = strat_r1->index;
378 
379     tabular_strategy_t *strat_r0_r1 = tabular_strategy_create();
380     tabular_strategy_t *ch = tabular_strategy_create();
381     unsigned long nb_strat = 0;
382 
383     /*
384        for each array of strategies, the first one is the zero strategy.
385        There are two cases :
386        -first, we have a success at 0%.
387        -Secondly, we have a success at 100%, because the cofactor is already
388        prime and not too big.  The four lines below allow to avoid to
389        have several unless methods with a zero probability.
390      */
391 
392     strategy_t *st;
393     for (int r = 0; r < len_r0; r++)	//first side
394     {
395 	double p0 = strat_r0->tab[r]->proba;
396 	double c0 = strat_r0->tab[r]->time;
397 	for (int a = 0; a < len_r1; a++)	//second side
398 	{
399 	    nb_strat++;
400 	    //compute success ans cost:
401 	    double p1 = strat_r1->tab[a]->proba;
402 	    double c1 = strat_r1->tab[a]->time;
403 	    double proba = p0 * p1;
404 	    double tps0 = c0 + p0 * c1;
405 	    //time when we begin with side 0
406 	    double tps1 = c1 + p1 * c0;
407             //time when we begin with side 1
408 	    if (tps0 < tps1) {
409 		st = concat_strategies(strat_r0->tab[r], strat_r1->tab[a], 0);
410 		strategy_set_proba(st, proba);
411 		strategy_set_time(st, tps0);
412 	    } else {
413 		st = concat_strategies(strat_r1->tab[a], strat_r0->tab[r], 1);
414 		strategy_set_proba(st, proba);
415 		strategy_set_time(st, tps1);
416 	    }
417 	    tabular_strategy_add_strategy(strat_r0_r1, st);
418 	    strategy_free(st);
419 	}
420 
421 	//process data to avoid to full the RAM!!!
422 	if (nb_strat > 100000 || r == (len_r0 - 1)) {
423 	    //add strategies of the old convexhull and recompute the new
424 	    //convex hull
425 
426 	    tabular_strategy_concat(strat_r0_r1, ch);
427 	    tabular_strategy_free(ch);
428 
429 	    ch = convex_hull_strategy(strat_r0_r1);
430 	    //clear previous collect and start a new collect.
431 	    tabular_strategy_free(strat_r0_r1);
432 	    strat_r0_r1 = tabular_strategy_create();
433 	    nb_strat = 0;
434 	}
435     }
436 
437     //free
438     tabular_strategy_free(strat_r0_r1);
439 
440     return ch;
441 }
442 
443 /*
444   returns the best strategies for each couple of cofactors of lenght
445   (r0, r1), from a set of factoring methods. Note that this function
446   use the previous functions, and need all probabilities and
447   times for each method must be previously computed. (to do that, you
448   could use the binary gfm).
449  */
450 
generate_matrix(const char * name_directory_decomp,tabular_fm_t * pm1,tabular_fm_t * pp1,tabular_fm_t * ecm,int ncurves,unsigned long lim0,int lpb0,int mfb0,unsigned long lim1,int lpb1,int mfb1)451 tabular_strategy_t ***generate_matrix(const char *name_directory_decomp,
452 				      tabular_fm_t* pm1, tabular_fm_t* pp1,
453 				      tabular_fm_t*ecm, int ncurves,
454 				      unsigned long lim0, int lpb0, int mfb0,
455 				      unsigned long lim1, int lpb1, int mfb1)
456 {
457 
458     int fbb0 = ceil (log2 ((double) (lim0 + 1)));
459     int fbb1 = ceil (log2 ((double) (lim1 + 1)));
460 
461     /*
462        allocates the matrix which contains all optimal strategies for
463        each couple (r0, r1): r0 is the lenght of the cofactor in
464        the first side, and r1 for the second side.
465      */
466     tabular_strategy_t ***matrix = (tabular_strategy_t***) malloc(sizeof(*matrix) * (mfb0 + 1));
467     ASSERT(matrix != NULL);
468 
469     for (int r0 = 0; r0 <= mfb0; r0++) {
470 	matrix[r0] = (tabular_strategy_t**) malloc(sizeof(*matrix[r0]) * (mfb1 + 1));
471 	ASSERT(matrix[r0] != NULL);
472     }
473 
474     /*
475        For each r0 in [fbb0..mfb0], we precompute and strore the data
476        for all strategies.  Whereas, for each r1, the values will be
477        computed sequentially.
478      */
479     fm_t *zero = fm_create();
480     unsigned long method_zero[4] = { 0, 0, 0, 0 };
481     fm_set_method(zero, method_zero, 4);
482 
483     tabular_strategy_t **data_rat = (tabular_strategy_t**) malloc(sizeof(*data_rat) * (mfb0 + 1));
484     ASSERT (data_rat);
485 
486     int lim_is_prime = 2 * fbb0 - 1;
487     for (int r0 = 0; r0 <= mfb0; r0++) {
488 	tabular_decomp_t *tab_decomp = NULL;
489 	if (r0 >= lim_is_prime) {
490 	    char name_file[200];
491 	    snprintf(name_file, sizeof(name_file),
492 		    "%s/decomp_%lu_%d", name_directory_decomp, lim0, r0);
493 	    FILE *file = fopen(name_file, "r");
494 
495 	    tab_decomp = tabular_decomp_fscan(file);
496 
497 	    if (tab_decomp == NULL) {
498 		fprintf(stderr, "impossible to read '%s'\n", name_file);
499 		exit(EXIT_FAILURE);
500 	    }
501 	    fclose(file);
502 	}
503 	data_rat[r0] =
504 	    generate_strategies_oneside(tab_decomp, zero, pm1, pp1,
505 					ecm, ncurves, lim0, lpb0, r0);
506 	tabular_decomp_free(tab_decomp);
507     }
508 
509     /*
510        read good elements for r_2 in the array data_r1 and compute the
511        data for each r_1. So :
512      */
513     lim_is_prime = 2 * fbb1 - 1;
514     for (int r1 = 0; r1 <= mfb1; r1++) {
515 	tabular_decomp_t *tab_decomp = NULL;
516 	if (r1 >= lim_is_prime) {
517 	    char name_file[200];
518 	    snprintf(name_file, sizeof(name_file),
519 		    "%s/decomp_%lu_%d", name_directory_decomp, lim1, r1);
520 	    FILE *file = fopen(name_file, "r");
521 
522 	    tab_decomp = tabular_decomp_fscan(file);
523 
524 	    if (tab_decomp == NULL) {
525 		fprintf(stderr, "impossible to read '%s'\n", name_file);
526 		exit(EXIT_FAILURE);
527 	    }
528 	    fclose(file);
529 	}
530 
531 	tabular_strategy_t *strat_r1 =
532 	  generate_strategies_oneside(tab_decomp, zero, pm1, pp1,
533 				      ecm, ncurves, lim1, lpb1, r1);
534 	tabular_decomp_free(tab_decomp);
535 
536 	for (int r0 = 0; r0 <= mfb0; r0++) {
537 	    tabular_strategy_t *res =
538 		generate_strategy_r0_r1(data_rat[r0], strat_r1);
539 	    matrix[r0][r1] = res;
540 	}
541 	tabular_strategy_free(strat_r1);
542     }
543 
544     //free
545     for (int r0 = 0; r0 <= mfb0; r0++)
546 	tabular_strategy_free(data_rat[r0]);
547     free(data_rat);
548 
549     fm_free(zero);
550     return matrix;
551 }
552 
553 /************************************************************************/
554 /*                      CONVEX_HULL_FM                                  */
555 /************************************************************************/
556 
557 /*
558   These following functions allow to use the module convex_hull, to
559   compute the convex hull of a set of strategies.
560  */
561 
convert_tab_point_to_tab_strategy(tabular_strategy_t * t)562 tabular_point_t *convert_tab_point_to_tab_strategy(tabular_strategy_t * t)
563 {
564     tabular_point_t *res = tabular_point_create();
565     int len = t->index;
566     strategy_t *elem;
567     for (int i = 0; i < len; i++) {
568 	elem = t->tab[i];
569 	tabular_point_add(res, i, elem->proba, elem->time);
570     }
571     return res;
572 }
573 
convert_tab_strategy_to_tab_point(tabular_point_t * t,tabular_strategy_t * init)574 tabular_strategy_t *convert_tab_strategy_to_tab_point(tabular_point_t * t,
575 						      tabular_strategy_t * init)
576 {
577     tabular_strategy_t *res = tabular_strategy_create();
578     int len = tabular_point_get_index(t);
579     for (int i = 0; i < len; i++) {
580 	int index = point_get_number(tabular_point_get_point(t, i));
581 	tabular_strategy_add_strategy(res, init->tab[index]);
582     }
583     return res;
584 }
585 
convex_hull_strategy(tabular_strategy_t * t)586 tabular_strategy_t *convex_hull_strategy(tabular_strategy_t * t)
587 {
588     tabular_point_t *tmp = convert_tab_point_to_tab_strategy(t);
589     tabular_point_t *res = convex_hull(tmp);
590     tabular_strategy_t *res_strat = convert_tab_strategy_to_tab_point(res, t);
591     tabular_point_free(tmp);
592     tabular_point_free(res);
593     return res_strat;
594 }
595