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