9 #include <vaucanson/int_boolean_automaton.hh>
13 #include "dependence_graph.h"
14 #include "eqv2_options.h"
19 #include <isl/constraint.h>
21 #ifdef HAVE_OMEGA_PLUS
24 using namespace omega
;
26 typedef std::vector
<Variable_ID
> varvector
;
27 typedef std::vector
<Global_Var_Decl
*> globalvector
;
29 static void create_globals(globalvector
&globals
, __isl_keep isl_space
*dim
)
31 unsigned nparam
= isl_space_dim(dim
, isl_dim_param
);
32 for (int i
= 0; i
< nparam
; ++i
) {
34 name
= isl_space_get_dim_name(dim
, isl_dim_param
, i
);
35 globals
.push_back(new Global_Var_Decl(name
));
50 static int add_constraint(__isl_take isl_constraint
*c
, void *user
)
52 struct map2rel_data
*data
= (struct map2rel_data
*) user
;
55 if (isl_constraint_is_equality(c
))
56 h
= data
->base
->add_EQ();
58 h
= data
->base
->add_GEQ();
60 for (int i
= 0; i
< data
->in
.size(); ++i
) {
61 isl_constraint_get_coefficient(c
, isl_dim_in
, i
, &data
->v
);
62 h
.update_coef(data
->in
[i
], isl_int_get_si(data
->v
));
64 for (int i
= 0; i
< data
->out
.size(); ++i
) {
65 isl_constraint_get_coefficient(c
, isl_dim_out
, i
, &data
->v
);
66 h
.update_coef(data
->out
[i
], isl_int_get_si(data
->v
));
68 for (int i
= 0; i
< data
->params
.size(); ++i
) {
69 isl_constraint_get_coefficient(c
, isl_dim_param
, i
, &data
->v
);
70 h
.update_coef(data
->params
[i
], isl_int_get_si(data
->v
));
72 for (int i
= 0; i
< data
->exists
.size(); ++i
) {
73 isl_constraint_get_coefficient(c
, isl_dim_div
, i
, &data
->v
);
74 h
.update_coef(data
->exists
[i
], isl_int_get_si(data
->v
));
76 isl_constraint_get_constant(c
, &data
->v
);
77 h
.update_const(isl_int_get_si(data
->v
));
79 isl_constraint_free(c
);
84 static Relation
basic_map2relation(isl_basic_map
*bmap
,
85 const Variable_ID_Tuple
*globals
)
87 struct map2rel_data data
;
89 Relation
r(isl_basic_map_dim(bmap
, isl_dim_in
),
90 isl_basic_map_dim(bmap
, isl_dim_out
));
91 F_Exists
*e
= r
.add_exists();
92 data
.base
= e
->add_and();
94 for (int j
= 1; j
<= r
.n_inp(); ++j
)
95 data
.in
.push_back(r
.input_var(j
));
96 for (int j
= 1; j
<= r
.n_out(); ++j
)
97 data
.out
.push_back(r
.output_var(j
));
98 for (int i
= 0; i
< isl_basic_map_dim(bmap
, isl_dim_div
); ++i
)
99 data
.exists
.push_back(e
->declare());
100 for (int i
= 0; i
< globals
->size(); ++i
)
101 data
.params
.push_back(r
.get_local((*globals
)[i
+1]));
103 isl_int_init(data
.v
);
105 isl_basic_map_foreach_constraint(bmap
, &add_constraint
, &data
);
107 isl_int_clear(data
.v
);
113 static int bm2r(__isl_take isl_basic_map
*bmap
, void *user
)
115 Relation
*r
= (Relation
*)user
;
117 *r
= Union(*r
, basic_map2relation(bmap
, r
->global_decls()));
119 isl_basic_map_free(bmap
);
124 static Relation
map2relation(__isl_keep isl_map
*map
,
125 const globalvector
&globals
)
127 Relation
r(isl_map_dim(map
, isl_dim_in
), isl_map_dim(map
, isl_dim_out
));
128 for (int i
= 0; i
< globals
.size(); ++i
)
129 r
.get_local(globals
[i
]);
133 isl_map_foreach_basic_map(map
, &bm2r
, &r
);
138 static void set_constraint(isl_constraint
*c
, Constraint_Handle h
,
139 varvector
&in
, varvector
&out
, varvector
¶ms
)
145 for (int i
= 0; i
< in
.size(); ++i
) {
146 isl_int_set_si(v
, h
.get_coef(in
[i
]));
147 isl_constraint_set_coefficient(c
, isl_dim_in
, i
, v
);
149 for (int i
= 0; i
< out
.size(); ++i
) {
150 isl_int_set_si(v
, h
.get_coef(out
[i
]));
151 isl_constraint_set_coefficient(c
, isl_dim_out
, i
, v
);
153 for (int i
= 0; i
< params
.size(); ++i
) {
154 isl_int_set_si(v
, h
.get_coef(params
[i
]));
155 isl_constraint_set_coefficient(c
, isl_dim_param
, i
, v
);
157 isl_int_set_si(v
, h
.get_const());
158 isl_constraint_set_constant(c
, v
);
163 static void max_index(Constraint_Handle c
, varvector
& vv
, varvector
& params
)
165 for (Constr_Vars_Iter
cvi(c
); cvi
; ++cvi
) {
166 Variable_ID var
= (*cvi
).var
;
167 if (find(vv
.begin(), vv
.end(), var
) == vv
.end() &&
168 find(params
.begin(), params
.end(), var
) == params
.end())
173 static void set_constraint(isl_constraint
*c
, Constraint_Handle h
,
174 varvector
&vv
, varvector
¶ms
)
180 for (int i
= 0; i
< vv
.size(); ++i
) {
181 isl_int_set_si(v
, h
.get_coef(vv
[i
]));
182 isl_constraint_set_coefficient(c
, isl_dim_set
, i
, v
);
184 for (int i
= 0; i
< params
.size(); ++i
) {
185 isl_int_set_si(v
, h
.get_coef(params
[i
]));
186 isl_constraint_set_coefficient(c
, isl_dim_param
, i
, v
);
188 isl_int_set_si(v
, h
.get_const());
189 isl_constraint_set_constant(c
, v
);
194 static isl_basic_set
*disjunct2basic_set(DNF_Iterator
&di
, isl_space
*dim
,
195 varvector
&vv
, varvector
¶ms
)
202 for (EQ_Iterator ei
= (*di
)->EQs(); ei
; ++ei
)
203 max_index((*ei
), vv
, params
);
204 for (GEQ_Iterator gi
= (*di
)->GEQs(); gi
; ++gi
)
205 max_index((*gi
), vv
, params
);
207 dim
= isl_space_add_dims(dim
, isl_dim_set
, vv
.size() - d
);
208 bset
= isl_basic_set_universe(isl_space_copy(dim
));
209 ls
= isl_local_space_from_space(dim
);
211 for (EQ_Iterator ei
= (*di
)->EQs(); ei
; ++ei
) {
212 c
= isl_equality_alloc(isl_local_space_copy(ls
));
213 set_constraint(c
, (*ei
), vv
, params
);
214 bset
= isl_basic_set_add_constraint(bset
, c
);
216 for (GEQ_Iterator gi
= (*di
)->GEQs(); gi
; ++gi
) {
217 c
= isl_inequality_alloc(isl_local_space_copy(ls
));
218 set_constraint(c
, (*gi
), vv
, params
);
219 bset
= isl_basic_set_add_constraint(bset
, c
);
222 isl_local_space_free(ls
);
224 bset
= isl_basic_set_project_out(bset
, isl_dim_set
, d
, vv
.size() - d
);
230 static __isl_give isl_map
*relation2map(__isl_take isl_space
*dim
, Relation
&r
)
238 for (int j
= 1; j
<= r
.n_inp(); ++j
)
239 vv
.push_back(r
.input_var(j
));
240 for (int j
= 1; j
<= r
.n_out(); ++j
)
241 vv
.push_back(r
.output_var(j
));
243 const Variable_ID_Tuple
*globals
= r
.global_decls();
244 for (int i
= 0; i
< globals
->size(); ++i
)
245 params
.push_back(r
.get_local((*globals
)[i
+1]));
247 ctx
= isl_space_get_ctx(dim
);
248 dim_set
= isl_space_set_alloc(ctx
, params
.size(), vv
.size());
249 map
= isl_map_empty(isl_space_copy(dim
));
251 for (DNF_Iterator
di(r
.query_DNF()); di
; ++di
) {
255 bset
= disjunct2basic_set(di
, isl_space_copy(dim_set
), vv
, params
);
256 bmap
= isl_basic_map_from_basic_set(bset
, isl_space_copy(dim
));
257 map
= isl_map_union(map
, isl_map_from_basic_map(bmap
));
260 isl_space_free(dim_set
);
266 /* Compute transitive closure using Omega+.
267 * Note that the result computed by Omega also contains the identity
268 * mapping on the intersection of domain and range, but we will include
269 * the entire identity mapping later, so this shouldn't be a problem.
271 static __isl_give isl_map
*omega_closure(__isl_take isl_map
*map
)
273 isl_ctx
*ctx
= isl_map_get_ctx(map
);
274 struct options
*options
= isl_ctx_peek_eqv2_options(ctx
);
276 globalvector globals
;
278 dim
= isl_map_get_space(map
);
279 create_globals(globals
, dim
);
281 Relation R
= map2relation(map
, globals
);
285 if (options
->try_lower
) {
287 TC
= TransitiveClosure(copy(R
));
288 Relation test
= Composition(copy(TC
), copy(R
));
290 exact
= TC
.is_exact() &&
291 Must_Be_Subset(copy(R
), copy(TC
)) &&
292 Must_Be_Subset(test
, copy(TC
));
294 TC
= Upper_Bound(ApproxClosure(R
));
296 TC
= Upper_Bound(ApproxClosure(R
));
298 map
= relation2map(dim
, TC
);
304 /* Compute transitive closure */
305 static __isl_give isl_map
*closure(__isl_take isl_map
*map
)
307 isl_ctx
*ctx
= isl_map_get_ctx(map
);
308 struct options
*options
= isl_ctx_peek_eqv2_options(ctx
);
310 #ifdef HAVE_OMEGA_PLUS
312 return omega_closure(map
);
315 return isl_map_transitive_closure(map
, NULL
);
318 using namespace vcsn::int_boolean_automaton
;
319 using namespace vcsn
;
321 template <class Exp_
, class Dispatch_
>
322 class acc_visitor
: public algebra::KRatExpMatcher
<
323 acc_visitor
<Exp_
, Dispatch_
>, Exp_
, isl_map
*, Dispatch_
>
326 typedef typename
Exp_::monoid_elt_value_t monoid_elt_value_t
;
327 typedef acc_visitor
<Exp_
, Dispatch_
> this_class
;
328 typedef isl_map
* return_type
;
334 acc_visitor(const MSA
&msa
) : msa(msa
) {}
336 INHERIT_CONSTRUCTORS(this_class
, Exp_
, isl_map
*, Dispatch_
);
338 MATCH__(Product
, lhs
, rhs
) {
339 return isl_map_apply_range(match(lhs
), match(rhs
));
342 MATCH__(Sum
, lhs
, rhs
) {
343 return isl_map_union(match(lhs
), match(rhs
));
349 map
= closure(match(node
));
350 dim
= isl_map_get_space(map
);
351 return isl_map_union(map
, isl_map_identity(dim
));
354 MATCH__(LeftWeight
, w
, node
) {
359 MATCH__(RightWeight
, node
, w
) {
364 MATCH_(Constant
, m
) {
366 typename
monoid_elt_value_t::const_iterator i
= m
.begin();
367 assert(i
!= m
.end());
368 map
= isl_map_copy(msa
.firing
[*i
]);
370 assert(i
== m
.end());
375 /* By construction, there should always be a path */
381 /* There can be no zero-length path */
388 template<typename Exp
>
389 isl_map
*accessibility(const MSA
&msa
, const Exp
&kexp
)
391 acc_visitor
<Exp
, algebra::DispatchFunction
<Exp
> > m(msa
);
392 return m
.match(kexp
);
395 static unsigned update_out_dim(pdg::PDG
*pdg
, unsigned out_dim
)
397 for (int i
= 0; i
< pdg
->arrays
.size(); ++i
) {
398 pdg::array
*array
= pdg
->arrays
[i
];
399 if (array
->type
!= pdg::array::output
)
401 if (array
->dims
.size() + 1 > out_dim
)
402 out_dim
= array
->dims
.size() + 1;
408 /* The input arrays of the two programs are supposed to be the same,
409 * so they should at least have the same dimension. Make sure
410 * this is true, because we depend on it later on.
412 static int check_input_arrays(dependence_graph
*dg1
, dependence_graph
*dg2
)
414 for (int i
= 0; i
< dg1
->input_computations
.size(); ++i
)
415 for (int j
= 0; j
< dg2
->input_computations
.size(); ++j
) {
416 if (strcmp(dg1
->input_computations
[i
]->operation
,
417 dg2
->input_computations
[j
]->operation
))
419 if (dg1
->input_computations
[i
]->dim
==
420 dg2
->input_computations
[j
]->dim
)
423 "input arrays \"%s\" do not have the same dimension\n",
424 dg1
->input_computations
[i
]->operation
);
431 /* Compute a map between the domains of the output nodes of
432 * the dependence graphs that expresses that array1 in dg1
433 * and array2 in dg2 are equal.
434 * This map is then returned as a set.
436 static __isl_give isl_set
*compute_equal_array(
437 dependence_graph
*dg1
, dependence_graph
*dg2
, int array1
, int array2
)
439 const char *array_name
= dg1
->output_arrays
[array1
];
440 isl_set
*out1
= isl_set_copy(dg1
->out
->domain
);
441 isl_set
*out2
= isl_set_copy(dg2
->out
->domain
);
442 unsigned dim1
= isl_set_n_dim(out1
);
443 unsigned dim2
= isl_set_n_dim(out2
);
445 out1
= isl_set_fix_dim_si(out1
, dim1
- 1, array1
);
446 out2
= isl_set_fix_dim_si(out2
, dim2
- 1, array2
);
447 out1
= isl_set_remove_dims(out1
, isl_dim_set
, dim1
- 1, 1);
448 out2
= isl_set_remove_dims(out2
, isl_dim_set
, dim2
- 1, 1);
449 int equal
= isl_set_is_equal(out1
, out2
);
454 fprintf(stderr
, "different output domains for array %s\n",
459 out1
= isl_set_copy(dg1
->out
->domain
);
460 out2
= isl_set_copy(dg2
->out
->domain
);
461 out1
= isl_set_fix_dim_si(out1
, dim1
- 1, array1
);
462 out2
= isl_set_fix_dim_si(out2
, dim2
- 1, array2
);
463 out1
= isl_set_coalesce(out1
);
464 out2
= isl_set_coalesce(out2
);
465 isl_space
*dim
= isl_space_map_from_set(isl_set_get_space(out2
));
466 isl_map
*id
= isl_map_identity(dim
);
467 id
= isl_map_remove_dims(id
, isl_dim_in
, isl_map_n_in(id
) - 1, 1);
468 id
= isl_map_apply_domain(id
, isl_map_copy(id
));
469 id
= isl_map_intersect_domain(id
, out1
);
470 id
= isl_map_intersect_range(id
, out2
);
472 return isl_map_wrap(id
);
475 /* Compute a map between the domains of the output nodes of
476 * the dependence graphs that expresses that arrays with
477 * the same names in both graphs are equal.
478 * The map is returned as a set.
480 static __isl_give isl_set
*compute_equal_output(
481 dependence_graph
*dg1
, dependence_graph
*dg2
)
486 isl_set
*equal_output
;
489 dim
= isl_set_get_space(dg1
->out
->domain
);
490 d
= isl_space_dim(dim
, isl_dim_set
);
491 map
= isl_map_empty(isl_space_map_from_set(dim
));
492 equal_output
= isl_map_wrap(map
);
494 while (i1
< dg1
->output_arrays
.size() || i2
< dg2
->output_arrays
.size()) {
496 cmp
= i1
== dg1
->output_arrays
.size() ? 1 :
497 i2
== dg2
->output_arrays
.size() ? -1 :
498 strcmp(dg1
->output_arrays
[i1
], dg2
->output_arrays
[i2
]);
501 "Array \"%s\" only in program 1; not checked\n",
502 dg1
->output_arrays
[i1
]);
504 } else if (cmp
> 0) {
506 "Array \"%s\" only in program 2; not checked\n",
507 dg2
->output_arrays
[i2
]);
511 eq_array
= compute_equal_array(dg1
, dg2
, i1
, i2
);
512 equal_output
= isl_set_union(equal_output
, eq_array
);
518 equal_output
= isl_set_set_tuple_name(equal_output
, "s0");
523 static int check_equivalence(isl_ctx
*ctx
,
524 dependence_graph
*dg1
, dependence_graph
*dg2
)
532 if (check_input_arrays(dg1
, dg2
))
535 p
= isl_printer_to_file(ctx
, stdout
);
537 root
= msa
.add(dg1
->out
, dg2
->out
);
540 for (int i
= 0; i
< msa
.firing
.size(); ++i
)
543 automaton_t a
= make_automaton(alpha
);
544 std::vector
<hstate_t
> state
;
545 for (int i
= 0; i
< msa
.state
.size(); ++i
)
546 state
.push_back(a
.add_state());
548 for (int i
= 0; i
< msa
.transition
.size(); ++i
) {
549 int s1
= msa
.transition
[i
].first
.first
;
550 int s2
= msa
.transition
[i
].first
.second
;
551 int f
= msa
.transition
[i
].second
;
552 a
.add_letter_transition(state
[s1
], state
[s2
], f
);
555 a
.set_initial(state
[root
]);
557 isl_set
*equal_output
;
558 equal_output
= compute_equal_output(dg1
, dg2
);
560 for (int i
= 0; i
< msa
.input_state
.size(); ++i
) {
566 a
.set_final(state
[msa
.input_state
[i
]]);
567 rat_exp_t ratexp
= aut_to_exp(a
);
570 acc
= accessibility(msa
, ratexp
.value());
571 set
= isl_set_apply(isl_set_copy(equal_output
),
573 map
= isl_set_unwrap(set
);
575 id
= isl_map_identity(isl_map_get_space(map
));
576 map
= isl_map_subtract(map
, id
);
578 set
= isl_map_wrap(map
);
579 set
= isl_set_set_tuple_name(set
,
580 isl_map_get_tuple_name(acc
, isl_dim_out
));
581 set
= isl_set_apply(set
, isl_map_reverse(acc
));
582 d
= isl_set_dim(set
, isl_dim_set
) / 2;
583 set
= isl_set_remove_dims(set
, isl_dim_set
, d
, d
);
584 if (!isl_set_is_empty(set
)) {
586 isl_printer_print_str(p
, "NOT equivalent");
587 isl_printer_end_line(p
);
588 set
= isl_set_coalesce(set
);
589 isl_printer_print_set(p
, set
);
590 isl_printer_end_line(p
);
596 /* Consider each fail state in turn as the corresponding
597 * domains may have different dimensions.
599 for (int i
= 0; i
< msa
.fail_state
.size(); ++i
) {
603 a
.set_final(state
[msa
.fail_state
[i
]]);
604 rat_exp_t ratexp
= aut_to_exp(a
);
607 acc
= accessibility(msa
, ratexp
.value());
608 acc
= isl_map_intersect_domain(acc
, isl_set_copy(equal_output
));
610 set
= isl_map_domain(acc
);
611 d
= isl_set_dim(set
, isl_dim_set
) / 2;
612 set
= isl_set_remove_dims(set
, isl_dim_set
, d
, d
);
613 if (!isl_set_is_empty(set
)) {
615 isl_printer_print_str(p
, "NOT equivalent");
616 isl_printer_end_line(p
);
617 set
= isl_set_coalesce(set
);
618 isl_printer_print_set(p
, set
);
619 isl_printer_end_line(p
);
625 isl_set_free(equal_output
);
628 isl_printer_print_str(p
, "NOT ");
629 isl_printer_print_str(p
, "OK");
630 isl_printer_end_line(p
);
637 int main(int argc
, char *argv
[])
640 struct options
*options
= eqv2_options_new_with_defaults();
641 isl_set
*context
= NULL
;
642 dependence_graph
*dg
[2];
644 argc
= eqv2_options_parse(options
, argc
, argv
, ISL_ARG_ALL
);
646 ctx
= isl_ctx_alloc_with_options(&options_args
, options
);
648 fprintf(stderr
, "Unable to allocate ctx\n");
652 if (options
->context
)
653 context
= isl_set_read_from_str(ctx
, options
->context
);
656 unsigned out_dim
= 0;
657 for (int i
= 0; i
< 2; ++i
) {
659 in
= fopen(options
->program
[i
], "r");
661 fprintf(stderr
, "Unable to open %s\n", options
->program
[i
]);
664 pdg
[i
] = yaml::Load
<pdg::PDG
>(in
, ctx
);
667 fprintf(stderr
, "Unable to read %s\n", options
->program
[i
]);
670 out_dim
= update_out_dim(pdg
[i
], out_dim
);
673 pdg
[i
]->params
.size() != isl_set_dim(context
, isl_dim_param
)) {
675 "Parameter dimension mismatch; context ignored\n");
676 isl_set_free(context
);
681 for (int i
= 0; i
< 2; ++i
) {
682 dg
[i
] = pdg_to_dg(pdg
[i
], out_dim
, isl_set_copy(context
));
687 int res
= check_equivalence(ctx
, dg
[0], dg
[1]);
689 for (int i
= 0; i
< 2; ++i
)
691 isl_set_free(context
);