3 #include <barvinok/options.h>
4 #include <barvinok/util.h>
7 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
9 /* RANGE : normal range for evalutations (-RANGE -> RANGE) */
12 /* SRANGE : small range for evalutations */
15 /* if dimension >= BIDDIM, use SRANGE */
18 /* VSRANGE : very small range for evalutations */
21 /* if dimension >= VBIDDIM, use VSRANGE */
24 static struct argp_option argp_options
[] = {
25 { "verify", 'T', 0, 0 },
26 { "exact", 'E', 0, 0 },
27 { "print-all", 'A', 0, 0 },
28 { "continue-on-error", 'C', 0, 0 },
29 { "min", 'm', "int", 0 },
30 { "max", 'M', "int", 0 },
31 { "range", 'r', "int", 0 },
35 static error_t
parse_opt(int key
, char *arg
, struct argp_state
*state
)
37 struct verify_options
*options
= state
->input
;
43 options
->print_all
= 0;
44 options
->continue_on_error
= 0;
58 options
->print_all
= 1;
61 options
->continue_on_error
= 1;
64 options
->m
= atoi(arg
);
68 options
->M
= atoi(arg
);
72 options
->r
= atoi(arg
);
73 options
->M
= atoi(arg
);
74 options
->m
= -options
->M
;
78 return ARGP_ERR_UNKNOWN
;
83 void verify_options_set_range(struct verify_options
*options
, int dim
)
89 else if (dim
>= BIGDIM
)
93 /* If the user didn't set m or M, then we try to adjust the window
94 * to the context in check_poly_context_scan.
96 if (options
->m
== INT_MAX
&& options
->M
== INT_MIN
)
98 if (options
->M
== INT_MIN
)
100 if (options
->m
== INT_MAX
)
103 if (options
->verify
&& options
->m
> options
->M
) {
104 fprintf(stderr
,"Nothing to do: min > max !\n");
109 struct argp verify_argp
= {
110 argp_options
, parse_opt
, 0, 0
113 static Polyhedron
*project_on(Polyhedron
*P
, int i
)
115 unsigned dim
= P
->Dimension
;
120 return Polyhedron_Copy(P
);
122 T
= Matrix_Alloc(2, dim
+1);
123 value_set_si(T
->p
[0][i
], 1);
124 value_set_si(T
->p
[1][dim
], 1);
125 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
130 static void set_bounds(Polyhedron
*C
, Value
**rows
, int i
, unsigned nparam
,
131 const struct verify_options
*options
)
138 value_set_si(min
, options
->m
);
139 value_set_si(max
, options
->M
);
141 if (options
->r
> 0) {
142 Polyhedron
*I
= project_on(C
, i
);
143 line_minmax(I
, &min
, &max
);
144 if (value_cmp_si(min
, options
->M
) >= 0)
145 value_add_int(max
, min
, options
->r
);
146 else if (value_cmp_si(max
, options
->m
) <= 0)
147 value_sub_int(min
, max
, options
->r
);
149 value_set_si(min
, options
->m
);
150 value_set_si(max
, options
->M
);
154 value_set_si(rows
[0][0], 1);
155 value_set_si(rows
[0][1+i
], 1);
156 value_oppose(rows
[0][1+nparam
], min
);
157 value_set_si(rows
[1][0], 1);
158 value_set_si(rows
[1][1+i
], -1);
159 value_assign(rows
[1][1+nparam
], max
);
165 Polyhedron
*check_poly_context_scan(Polyhedron
*P
, Polyhedron
**C
,
167 const struct verify_options
*options
)
171 Polyhedron
*CC
, *CC2
, *CS
, *U
;
172 unsigned MaxRays
= options
->barvinok
->MaxRays
;
180 CC
= Polyhedron_Project(P
, nparam
);
182 CC2
= DomainIntersection(*C
, CC
, MaxRays
);
188 /* Intersect context with range */
189 MM
= Matrix_Alloc(2*nparam
, nparam
+2);
190 for (i
= 0; i
< nparam
; ++i
)
191 set_bounds(CC
, &MM
->p
[2*i
], i
, nparam
, options
);
192 CC2
= AddConstraints(MM
->p
[0], 2*nparam
, CC
, options
->barvinok
->MaxRays
);
196 U
= Universe_Polyhedron(0);
197 CS
= Polyhedron_Scan(CC
, U
, MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
204 void check_poly_init(Polyhedron
*C
, struct verify_options
*options
)
208 if (options
->print_all
)
210 if (C
->Dimension
<= 0)
213 d
= options
->M
- options
->m
;
215 options
->st
= 1+d
/80;
218 for (i
= options
->m
; i
<= options
->M
; i
+= options
->st
)
224 static void print_rational(FILE *out
, Value n
, Value d
)
226 value_print(out
, VALUE_FMT
, n
);
227 if (value_notone_p(d
)) {
229 value_print(out
, VALUE_FMT
, d
);
233 void check_poly_print(int ok
, int nparam
, Value
*z
,
234 Value want_n
, Value want_d
,
235 Value got_n
, Value got_d
,
236 const char *op
, const char *check
,
238 const struct verify_options
*options
)
242 if (options
->print_all
) {
244 value_print(stdout
, VALUE_FMT
, z
[0]);
245 for (k
= 1; k
< nparam
; ++k
) {
247 value_print(stdout
, VALUE_FMT
, z
[k
]);
250 print_rational(stdout
, got_n
, got_d
);
251 printf(", %s = ", check
);
252 print_rational(stdout
, want_n
, want_d
);
259 fprintf(stderr
, "Error !\n");
260 fprintf(stderr
, "%s(", op
);
261 value_print(stderr
, VALUE_FMT
, z
[0]);
262 for (k
= 1; k
< nparam
; ++k
) {
263 fprintf(stderr
,", ");
264 value_print(stderr
, VALUE_FMT
, z
[k
]);
266 fprintf(stderr
, ") should be ");
267 print_rational(stderr
, want_n
, want_d
);
268 fprintf(stderr
, ", while %s gives ", long_op
);
269 print_rational(stderr
, got_n
, got_d
);
270 fprintf(stderr
, ".\n");
271 } else if (options
->print_all
)
275 /****************************************************/
276 /* function check_poly : */
277 /* scans the parameter space from Min to Max (all */
278 /* directions). Computes the number of points in */
279 /* the polytope using both methods, and compare them*/
280 /* returns 1 on success */
281 /****************************************************/
283 int check_poly(Polyhedron
*CS
, const struct check_poly_data
*data
,
284 int nparam
, int pos
, Value
*z
,
285 const struct verify_options
*options
)
288 if (!data
->check(data
, nparam
, z
, options
) && !options
->continue_on_error
)
295 ok
= !(lower_upper_bounds(1+pos
, CS
, z
-1, &LB
, &UB
));
297 for (; value_le(LB
, UB
); value_increment(LB
, LB
)) {
298 if (!options
->print_all
) {
299 int k
= VALUE_TO_INT(LB
);
300 if (!pos
&& !(k
% options
->st
)) {
306 value_assign(z
[pos
], LB
);
307 if (!check_poly(CS
->next
, data
, nparam
, pos
+1, z
, options
)) {
313 value_set_si(z
[pos
], 0);
320 void check_EP_set_scan(struct check_EP_data
*data
, Polyhedron
*C
,
323 const evalue
*EP
= data
->EP
;
327 for (i
= 0; i
< EP
->x
.p
->size
/2; ++i
) {
328 Polyhedron
*A
= EVALUE_DOMAIN(EP
->x
.p
->arr
[2*i
]);
329 for (; A
; A
= A
->next
)
334 data
->S
= ALLOCN(Polyhedron
*, n_S
);
336 for (i
= 0; i
< EP
->x
.p
->size
/2; ++i
) {
337 Polyhedron
*A
= EVALUE_DOMAIN(EP
->x
.p
->arr
[2*i
]);
338 for (; A
; A
= A
->next
) {
339 Polyhedron
*next
= A
->next
;
341 data
->S
[n_S
++] = Polyhedron_Scan(A
, C
,
342 MaxRays
& POL_NO_DUAL
? 0 : MaxRays
);
348 void check_EP_clear_scan(struct check_EP_data
*data
)
352 for (i
= 0; i
< data
->n_S
; ++i
)
353 Domain_Free(data
->S
[i
]);
357 static int check_EP_on_poly(Polyhedron
*P
,
358 struct check_EP_data
*data
,
359 unsigned nvar
, unsigned nparam
,
360 struct verify_options
*options
)
363 unsigned MaxRays
= options
->barvinok
->MaxRays
;
365 const evalue
*EP
= data
->EP
;
367 CS
= check_poly_context_scan(NULL
, &P
, P
->Dimension
, options
);
369 check_poly_init(P
, options
);
371 if (!(CS
&& emptyQ2(CS
))) {
372 check_EP_set_scan(data
, P
, MaxRays
);
373 ok
= check_poly(CS
, &data
->cp
, nparam
, 0, data
->cp
.z
+1+nvar
, options
);
374 check_EP_clear_scan(data
);
377 if (!options
->print_all
)
389 * Project on final dim dimensions
391 Polyhedron
*DomainProject(Polyhedron
*D
, unsigned dim
, unsigned MaxRays
)
396 R
= Polyhedron_Project(D
, dim
);
397 for (P
= D
->next
; P
; P
= P
->next
) {
398 Polyhedron
*R2
= Polyhedron_Project(P
, dim
);
399 Polyhedron
*R3
= DomainUnion(R
, R2
, MaxRays
);
407 static Polyhedron
*evalue_parameter_domain(const evalue
*e
, unsigned nparam
,
411 Polyhedron
*U
= NULL
;
413 if (EVALUE_IS_ZERO(*e
))
414 return Universe_Polyhedron(0);
416 assert(value_zero_p(e
->d
));
417 assert(e
->x
.p
->type
== partition
);
418 assert(e
->x
.p
->size
>= 2);
420 for (i
= 0; i
< e
->x
.p
->size
/2; ++i
) {
421 Polyhedron
*D
= EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]);
422 Polyhedron
*P
= DomainProject(D
, nparam
, MaxRays
);
427 U
= DomainUnion(U
, P
, MaxRays
);
435 int check_EP(struct check_EP_data
*data
, unsigned nvar
, unsigned nparam
,
436 struct verify_options
*options
)
443 p
= Vector_Alloc(nvar
+nparam
+2);
444 value_set_si(p
->p
[nvar
+nparam
+1], 1);
448 D
= evalue_parameter_domain(data
->EP
, nparam
, options
->barvinok
->MaxRays
);
450 for (P
= D
; P
; P
= P
->next
) {
451 ok
= check_EP_on_poly(P
, data
, nvar
, nparam
, options
);
452 if (!ok
&& !options
->continue_on_error
)
462 static void optimum(Polyhedron
*S
, int pos
, const struct check_EP_data
*data
,
463 Value
*opt
, int *found
, int sign
)
469 /* value_set_double rounds to zero; give it some slop */
470 d
= compute_evalue(data
->EP
, data
->cp
.z
+1);
475 value_set_double(c
, d
);
477 value_assign(*opt
, c
);
481 if (value_gt(c
, *opt
))
482 value_assign(*opt
, c
);
484 if (value_lt(c
, *opt
))
485 value_assign(*opt
, c
);
494 ok
= !(lower_upper_bounds(1+pos
, S
, data
->cp
.z
, &LB
, &UB
));
496 for (; value_le(LB
, UB
); value_increment(LB
, LB
)) {
497 value_assign(data
->cp
.z
[1+pos
], LB
);
498 optimum(S
->next
, pos
+1, data
, opt
, found
, sign
);
500 value_set_si(data
->cp
.z
[1+pos
], 0);
506 void evalue_optimum(const struct check_EP_data
*data
, Value
*opt
, int sign
)
511 for (i
= 0; i
< data
->n_S
; ++i
)
512 if (!(data
->S
[i
] && emptyQ(data
->S
[i
])))
513 optimum(data
->S
[i
], 0, data
, opt
, &found
, sign
);