1 #include <FPG/Static_filter_with_scaling.h>
2 #include <FPG/Misc_visitors.h>
3 #include <FPG/Abstract_interpretation_visitor.h>
4 #include <FPG/Prettyprint_visitor.h>
5 #include <FPG/Transformation.h>
6 #include <FPG/Error_bound_value.h>
7 #include <FPG/Static_filter_error.h>
8 #include <FPG/Group_index_value.h>
9 #include <CGALmini/basic.h>
10
11 #include <cassert>
12 #include <vector>
13 #include <set>
14 #include <algorithm>
15 #include <cmath>
16 #include <limits>
17 #include <sstream>
18
19 extern "C" {
20 #include <fenv.h>
21 }
22
23 //#define DEBUG 0
24 #include <FPG/MSG.h>
25
26
27 using namespace Static_filter_with_scaling;
28
29 struct Contains_translation_on_fresh_values :
30 public Attribute_visitor<bool>
31 {
32 Abstract_interpretation_visitor *absint_is_fresh;
33
34 // sfe knows, which AST::Expression*s are fresh
Contains_translation_on_fresh_valuesContains_translation_on_fresh_values35 Contains_translation_on_fresh_values( Abstract_interpretation_visitor *absint_is_fresh )
36 : /* inter-procedural, */
37 absint_is_fresh(absint_is_fresh)
38 {
39 set_default_value( false );
40 set_shortcut_value( true );
41 }
42
combineContains_translation_on_fresh_values43 virtual bool combine( bool a, bool b ) {
44 return a || b;
45 }
46
visitContains_translation_on_fresh_values47 virtual void visit( AST::BinaryExpression* bexp ) {
48 Error_bound_value *is_fresh1 = dynamic_cast<Error_bound_value*>( absint_is_fresh->get_analysis_result( bexp->e1 ) );
49 Error_bound_value *is_fresh2 = dynamic_cast<Error_bound_value*>( absint_is_fresh->get_analysis_result( bexp->e2 ) );
50 assert( is_fresh1 != nullptr && is_fresh2 != nullptr );
51 if( is_fresh1->is_fresh() && is_fresh2->is_fresh() && bexp->kind == AST::BinaryExpression::SUB ) {
52 MSG("")
53 //bexp->dump(0);
54 result_value = true;
55 } else
56 Attribute_visitor<bool>::visit( bexp );
57 }
58 };
59
60 struct Contains_float_compare_on_derived_values :
61 public Attribute_visitor<bool>
62 {
63 Abstract_interpretation_visitor *absint_is_fresh;
64
65 // sfe knows, which AST::Expression*s are fresh
Contains_float_compare_on_derived_valuesContains_float_compare_on_derived_values66 Contains_float_compare_on_derived_values( Abstract_interpretation_visitor *absint_is_fresh )
67 : /* inter-procedural, */
68 absint_is_fresh(absint_is_fresh)
69 {
70 set_default_value( false );
71 set_shortcut_value( true );
72 }
73
combineContains_float_compare_on_derived_values74 virtual bool combine( bool a, bool b ) {
75 return a || b;
76 }
77
visitContains_float_compare_on_derived_values78 virtual void visit( AST::BinaryExpression* bexp ) {
79 if( is_float( bexp->e1->getType() ) ||
80 is_float( bexp->e2->getType() ) )
81 {
82 Error_bound_value *is_fresh1 = dynamic_cast<Error_bound_value*>( absint_is_fresh->get_analysis_result( bexp->e1 ) );
83 Error_bound_value *is_fresh2 = dynamic_cast<Error_bound_value*>( absint_is_fresh->get_analysis_result( bexp->e2 ) );
84 assert( is_fresh1 != nullptr && is_fresh2 != nullptr );
85 bool is_fresh = is_fresh1->is_fresh() && is_fresh2->is_fresh();
86 //MSG(is_fresh)
87 switch( bexp->kind ) {
88 case AST::BinaryExpression::EQ:
89 case AST::BinaryExpression::NEQ:
90 case AST::BinaryExpression::GEQ:
91 case AST::BinaryExpression::LEQ:
92 if( !is_fresh )
93 throw RuntimeError("no equality compare for derived values!", bexp->location );
94 // fallthrough
95 case AST::BinaryExpression::LE:
96 case AST::BinaryExpression::GR:
97 if( !is_fresh ) {
98 result_value = true;
99 return;
100 }
101 break;
102 default: break;
103 }
104 }
105 Attribute_visitor<bool>::visit( bexp );
106 }
107
visitContains_float_compare_on_derived_values108 virtual void visit( AST::UnaryFunction *uf ) {
109 Error_bound_value *is_fresh = dynamic_cast<Error_bound_value*>( absint_is_fresh->get_analysis_result( uf->e ) );
110 assert( is_fresh != nullptr );
111 if( uf->kind == AST::UnaryFunction::XSIGN && !is_fresh->is_fresh() )
112 result_value = true;
113 else
114 Attribute_visitor<bool>::visit( uf );
115 }
116 };
117
118
119
120 struct Subst_funcall_filter : Expression_filter {
121 Add_bound_variables *add_bounds;
122
Subst_funcall_filterSubst_funcall_filter123 Subst_funcall_filter( Add_bound_variables *add_bounds )
124 : add_bounds(add_bounds)
125 {}
126
operator ()Subst_funcall_filter127 virtual bool operator()( AST::Expression *e ) {
128 // this is not really efficient ....
129 MSG("")
130 //e->dump(0);
131 AST::FunctionCall *funcall = dynamic_cast<AST::FunctionCall*>(e);
132 assert( funcall != nullptr );
133 if( funcall->fun_type->is_extern )
134 return false;
135 assert( funcall->called_function != nullptr );
136 Contains_translation_on_fresh_values has_fresh_sub ( add_bounds->absint_is_fresh );
137 Contains_float_compare_on_derived_values has_float_comp( add_bounds->absint_is_fresh );
138 funcall->called_function->accept( &has_fresh_sub );
139 funcall->called_function->accept( &has_float_comp );
140 //std::cout << has_fresh_sub.result_value << has_float_comp.result_value << std::endl;
141 return has_fresh_sub.result_value || has_float_comp.result_value;
142 }
143 };
144
145 // for each group g, check if another group h
146 // is a subset/is equal to g. store this subset/dependency relation
147 void
make_partial_order()148 Group_cache::make_partial_order() {
149 subset_relation.clear();
150 for( iterator g_it = begin(); g_it!= end(); ++g_it ) {
151 const Group &g = g_it->first;
152 Variable *vg = g_it->second;
153 /*std::cout << "group g:" << vg->id << " with: ";
154 for( Group::iterator xx_it = g.begin(); xx_it != g.end(); ++xx_it )
155 std::cout << (*xx_it)->id << " ";
156 std::cout << std::endl;*/
157 for( iterator h_it = begin(); h_it!= end(); ++h_it ) {
158 if( g_it == h_it )
159 continue;
160 const Group &h = h_it->first;
161 Variable *vh = h_it->second;
162 /*std::cout << "checking group " << vh->id << " with: ";
163 for( Group::iterator xx_it = h.begin(); xx_it != h.end(); ++xx_it )
164 std::cout << (*xx_it)->id << " ";
165 std::cout << std::endl;*/
166
167 // check if h is a subset of g (or equal to g)
168 if( std::includes( g.begin(), g.end(), h.begin(), h.end() ) ) {
169 // the variable vh can only appear once, so no need to check for
170 // duplicates
171 subset_relation[vg].insert( vh );
172 //std::cout << " ++ var " << vh->id << " is subset" << std::endl;
173 } //else
174 //std::cout << " -- var " << vh->id << " no subset" << std::endl;
175 }
176 }
177 }
178
179 bool
is_intersection_free(Variable * maxvar)180 Group_cache::is_intersection_free( Variable *maxvar /*, std::vector< Variable* >& other_max_vars */ ) {
181 Reverse_mapping::iterator g_it = reverse_mapping.find( maxvar );
182 assert( g_it != reverse_mapping.end() );
183 const Group &g = g_it->second;
184 for( iterator h_it = begin(); h_it!= end(); ++h_it ) {
185 const Group &h = h_it->first;
186 if( g == h )
187 continue;
188 std::set< Variable* > intersection;
189 std::set_intersection( g.begin(), g.end(), h.begin(), h.end(),
190 std::inserter( intersection, intersection.begin() ) );
191 if( intersection.empty() )
192 continue;
193 //bool g_includes_h = std::includes( g.begin(), g.end(), h.begin(), h.end() );
194 //bool h_includes_g = std::includes( h.begin(), h.end(), g.begin(), g.end() );
195 bool g_includes_h = subset_relation[g_it->first].find( h_it->second ) != subset_relation[g_it->first].end();
196 bool h_includes_g = subset_relation[h_it->second].find( g_it->first ) != subset_relation[h_it->second].end();
197 if( ! g_includes_h && ! h_includes_g ) {
198 /*std::set< Variable* >::iterator it;
199 std::cout << "g: ";
200 for( it = g.begin(); it != g.end(); ++ it )
201 std::cout << (*it)->id << " ";
202 std::cout << std::endl << "h: ";
203 for( it = h.begin(); it != h.end(); ++ it )
204 std::cout << (*it)->id << " ";
205 std::cout << std::endl;*/
206 return false;
207 }
208 }
209 return true;
210 }
211
212 bool
is_maximum(Variable * maxvar,std::vector<Variable * > & other_max_vars)213 Group_cache::is_maximum( Variable* maxvar, std::vector< Variable* >& other_max_vars ) {
214 std::vector< Variable* >::iterator begin = other_max_vars.begin(),
215 end = other_max_vars.end();
216 for( ; begin != end; ++begin ) {
217 if( maxvar == *begin )
218 continue;
219 //std::cout << "varname: " << (*begin)->id << std::endl;
220 if( subset_relation[maxvar].find( *begin ) == subset_relation[maxvar].end() )
221 return false;
222 }
223 return true;
224 }
225
226 unsigned int
number_of_subsets(Variable * maxvar,std::vector<Variable * > & max_vars,std::set<Variable * > & ignore)227 Group_cache::number_of_subsets( Variable* maxvar, std::vector< Variable* >& max_vars, std::set< Variable*> &ignore ) {
228 std::vector< Variable* >::iterator begin = max_vars.begin(),
229 end = max_vars.end();
230 unsigned int counter = 0;
231 for( ; begin != end; ++begin ) {
232 if( maxvar == *begin )
233 continue;
234 //std::cout << "varname: " << (*begin)->id << std::endl;
235 if( subset_relation[maxvar].find( *begin ) != subset_relation[maxvar].end() ) {
236 ignore.insert( *begin );
237 ++counter;
238 }
239 }
240 return counter;
241 }
242
243 Variable*
find_maximum(std::vector<Variable * > & max_vars,std::set<Variable * > & ignore)244 Group_cache::find_maximum( std::vector< Variable* >& max_vars, std::set< Variable*> &ignore ) {
245 std::vector< Variable* >::iterator begin = max_vars.begin(),
246 end = max_vars.end();
247 Variable *result = nullptr;
248 std::set< Variable*> ignore_tmp;
249 unsigned int max_subsets = 0;
250 for( ; begin != end; ++begin ) {
251 //std::cout << "varname: " << (*begin)->id << std::endl;
252 ignore_tmp.clear();
253 unsigned int n = number_of_subsets( *begin, max_vars, ignore_tmp );
254 if( n > max_subsets ) {
255 result = *begin;
256 // not terribly efficient ...
257 ignore = ignore_tmp;
258 max_subsets = n;
259 }
260 }
261 return result;
262 }
263
264
265 // ----------------------
266 struct Use_as_max_value : public Abstract_value {
Use_as_max_valueUse_as_max_value267 Use_as_max_value(bool is_fresh = true,
268 bool use_as_max = false)
269 : is_fresh_(is_fresh),
270 use_as_max_(use_as_max)
271 {}
272
273 Use_as_max_value*
downcastUse_as_max_value274 downcast( Abstract_value* value ) {
275 Use_as_max_value *v= dynamic_cast<Use_as_max_value*>( value );
276 assert( v!= nullptr );
277 return v;
278 }
279 virtual Use_as_max_value*
get_initial_valueUse_as_max_value280 get_initial_value( Variable *var ) { argused(var); return new Use_as_max_value( true, true ); }
281
282 virtual Use_as_max_value*
addUse_as_max_value283 add( Abstract_value* other ) {
284 if( downcast(other)->is_fresh() && is_fresh() ) {
285 downcast(other)->use_as_max_ = false;
286 use_as_max_ = false;
287 return new Use_as_max_value( false, true );
288 } /*else {
289 if( downcast(other)->is_fresh() ) {
290 assert(!is_fresh());
291 downcast(other)->use_as_max_ = true;
292 } else if( is_fresh() ) {
293 assert(!downcast(other)->is_fresh());
294 use_as_max_ = true;
295 }
296 }*/
297 return new Use_as_max_value(false,false);
298 }
299
300 virtual Use_as_max_value*
subUse_as_max_value301 sub( Abstract_value* other ) {
302 return add( other );
303 }
304
305
306 virtual Use_as_max_value*
mulUse_as_max_value307 mul( Abstract_value* other ) {
308 argused(other);
309 return new Use_as_max_value(false,false);
310 }
311
312 //virtual void funcall( AST::Expression* funcall) { if( is_fresh() ) use_as_max_ = true; }
313
divUse_as_max_value314 virtual Use_as_max_value* div( Abstract_value* other ) { argused(other); CGAL_error(); return nullptr; }
sqrtUse_as_max_value315 virtual Use_as_max_value* sqrt() { CGAL_error(); return nullptr; }
joinUse_as_max_value316 virtual Use_as_max_value* join( Abstract_value* other ) { argused(other); return this; }
317
cloneUse_as_max_value318 virtual Use_as_max_value* clone() { return new Use_as_max_value(*this); }
319 // returns true if it is equivalent to a default constructed abstract value
is_freshUse_as_max_value320 virtual bool is_fresh() { return is_fresh_; }
321
dumpUse_as_max_value322 virtual std::ostream& dump( std::ostream& out ) {
323 out << "use as max: " << use_as_max_;
324 return out;
325 }
326
327 bool is_fresh_;
328 bool use_as_max_;
329 };
330
331 // --------------------------------------------------------------
332
333 struct CSE_max
334 : public Common_subexpression_elimination
335 {
CSE_maxCSE_max336 CSE_max( Add_bound_variables *add_bounds ) : add_bounds(add_bounds) {}
337
filterCSE_max338 virtual bool filter( AST::BinaryExpression *e ) {
339 return add_bounds->use_as_max( e );
340 }
341
visitCSE_max342 virtual void visit( AST::AssignmentExpression *e ) {
343 if( add_bounds->use_as_max( e ) )
344 Transformation_visitor::push( e );
345 else
346 Transformation_visitor::visit( e );
347 }
348
updateCSE_max349 virtual void update( AST::Node *node_old, AST::Node *node_new ) {
350 Transformation_visitor::update( node_old, node_new );
351 AST::Expression *e_old = dynamic_cast< AST::Expression* >(node_old);
352 AST::Expression *e_new = dynamic_cast< AST::Expression* >(node_new);
353 if( e_old != nullptr )
354 assert( e_new != nullptr );
355 add_bounds->absint_max->update( e_old, e_new );
356 }
357
358 Add_bound_variables *add_bounds;
359 };
360
361 struct Predicate_use_as_max : public Expression_filter {
Predicate_use_as_maxPredicate_use_as_max362 Predicate_use_as_max( Add_bound_variables *add_bounds ) : add_bounds(add_bounds) {}
operator ()Predicate_use_as_max363 virtual bool operator()( AST::Expression *e ) {
364 return add_bounds->use_as_max( e );
365 }
366 Add_bound_variables *add_bounds;
367 };
368
369
Add_bound_variables(bool use_aposteriori_check)370 Add_bound_variables::Add_bound_variables( bool use_aposteriori_check )
371 : epsilon_tmp_variable(nullptr),
372 absint_max(new Abstract_interpretation_visitor( new Use_as_max_value )),
373 max_var_counter(0),
374 use_aposteriori_check(use_aposteriori_check)
375 {
376 Expression_filter *f = new Predicate_use_as_max( this );
377
378 Abstract_value *sfe = new Static_filter_error( f );
379 absint_sfe = new Abstract_interpretation_visitor( sfe );
380
381 Abstract_value *giv = new Group_index_value( f );
382 absint_giv = new Abstract_interpretation_visitor( giv );
383
384 Abstract_value *is_fresh = new Error_bound_value();
385 absint_is_fresh = new Abstract_interpretation_visitor( is_fresh );
386 }
387
388
389 bool
use_as_max(AST::Expression * e)390 Add_bound_variables::use_as_max( AST::Expression* e) {
391 MSG("")
392 Use_as_max_value *uamv= dynamic_cast< Use_as_max_value* >( absint_max->get_analysis_result( e ) );
393 assert( uamv != nullptr );
394 return uamv->use_as_max_ ;
395 }
396
397
398
399 static bool
find_max_input(AST::FunctionDefinition * fundef,double & max_input)400 find_max_input( AST::FunctionDefinition *fundef, double &max_input ) {
401 max_input = std::numeric_limits<double>::max();
402 Abstract_interpretation_visitor
403 *absint = new Abstract_interpretation_visitor(
404 new Static_filter_error(new Expression_filter)
405 );
406 unsigned int phase = 0;
407 unsigned int counter = 0;
408 do {
409 ::feclearexcept( FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID );
410 //std::cout << "trying with max_input = " << max_input << " .... " << std::endl;
411 absint->clear( new Static_filter_error( new Expression_filter, CGAL::Static_filter_error(max_input) ) );
412 absint->visit( fundef );
413 bool overflow = ::fetestexcept ( FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID );
414 if( overflow == (phase % 2) ) {
415 ++phase;
416 //std::cout << "next phase: " << phase << std::endl;
417 }
418 if( max_input < 100.0 )
419 return false;
420 switch( phase ) {
421 case 0 : max_input = std::sqrt( max_input ); break;
422 case 1 : max_input *= std::sqrt( max_input ); break;
423 default : max_input /= 2.0; break;
424 }
425 if( ++counter > 1000000000 )
426 return false;
427 } while( phase <= 2 );
428 //std::cout << "success with max_input = " << max_input << std::endl;
429 delete absint;
430 return true;
431 }
432
433 void
visit(AST::TranslationUnit * tu)434 Add_bound_variables::visit( AST::TranslationUnit* tu) {
435 Compute_call_count compute_call_count;
436 Rewrite_float_comparisons rewrite_float_comp( this );
437 Rewrite_sign_of_fresh_values rewrite_fresh_sign( this );
438 Contains_float_compare_on_derived_values has_float_comp( absint_is_fresh );
439 Subst_funcall_filter subst_filter( this );
440 Substitute_funcalls subst_funcalls( &subst_filter );
441 AST::ListOfFunctions::iterator it;
442 AST::ListOfFunctions::reverse_iterator r_it;
443 subst_funcalls.collect_variables = collect_variables;
444
445 for( r_it = tu->functions.rbegin(); r_it != tu->functions.rend(); ++r_it ) {
446 collect_variables->clear();
447 absint_is_fresh->clear();
448 has_float_comp.reset();
449 AST::FunctionDefinition *fundef = *r_it;
450 if( !fundef->type->is_extern ) {
451 fundef->accept( collect_variables );
452 fundef->accept( absint_is_fresh );
453 fundef->accept( &has_float_comp );
454 if( !has_float_comp.result_value )
455 continue;
456 //std::cerr << "substituting function calls in " << fundef->type->id << std::endl;
457 // subst'ion works one funcall at a time, starting from the "outside":
458 // function calls that are made in the called function have to be replaced
459 // subsequently. repeat until no change has been made
460 //Prettyprint_visitor pretty( std::cout );
461 //fundef->accept( &pretty );
462 do {
463 subst_funcalls.is_dirty = false;
464 fundef->accept( &subst_funcalls );
465 fundef->accept( absint_is_fresh );
466 /*if( subst_funcalls.is_dirty ) {
467 std::cerr << " +++ iteration: " << std::endl;
468 fundef->accept( &pretty );
469 }*/
470 } while( subst_funcalls.is_dirty );
471 //std::cerr << "finished substituting. rewriting fresh sign expressions:" << std::endl;
472 fundef->accept( &rewrite_fresh_sign );
473 //fundef->accept( &pretty );
474 }
475 }
476
477 // here, each function only contains function calls without
478 // derived float comparisons. this allows to compute max groups
479 // in only that toplevel function
480 for( it = tu->functions.begin(); it != tu->functions.end(); ++it ) {
481 collect_variables->clear();
482 group_cache.clear();
483 max_var_counter = 0;
484 epsilon_tmp_variable = nullptr;
485 rewrite_float_comp.reset();
486 absint_is_fresh->clear();
487 absint_sfe->clear();
488 absint_giv->clear();
489 absint_max->clear();
490 has_float_comp.reset();
491 AST::FunctionDefinition *fundef = *it;
492
493 if( !fundef->type->is_extern ) {
494 fundef->accept( collect_variables );
495 fundef->accept( absint_is_fresh );
496 fundef->accept( &has_float_comp );
497 if( !has_float_comp.result_value )
498 continue;
499 std::cerr << "analyzing " << fundef->type->id << std::endl;
500
501 if( !use_aposteriori_check && !find_max_input( fundef, rewrite_float_comp.max_input ) )
502 CGAL_error_msg("failed to compute max_input for which no overflow occurs");
503 // find max expressions
504 absint_max->visit( fundef );
505 // for all max expressions: eliminate duplicate binary expressions
506 CSE_max cse( this );
507 fundef->accept( &cse );
508 absint_max->clear();
509 absint_max->visit( fundef );
510 // compute floating point errors
511 absint_sfe->visit( fundef );
512 // compute group indices
513 MSG("compute group indices of " << fundef->type->id )
514 absint_giv->visit( fundef );
515 handle( fundef );
516 group_cache.make_partial_order();
517 fundef->accept( &rewrite_float_comp );
518 fundef->type->return_type = filtered_predicate_return_type;
519 }
520 }
521 }
522
523
524 // -----------------
525
526
527 /*
528 case
529 ===========
530 groups: 1-3
531 group_indices: 1*2*2*3
532 compute max1
533 compute max2
534 compute max3
535 min/max of max123
536
537 case
538 ============
539 group 1-4
540 group_indices: 0*0*0*0
541 remaining groups: 1 - 4
542 compute max0 (use variables from group 1 - 4)
543 min/max = max0
544
545 case
546 ============
547 groups: 1 - 5
548 group_indices: 0*0*1*1*2*4
549 compute max1
550 compute max2
551 compute max4
552 remaining groups: 3,5
553 compute max0 (use only those variables that are in group 3 and 5)
554 compute min/max of max0124
555
556 ==========> approach:
557 g = group_indices
558 zeroes = number of 0 in g
559 g = remove 0 from g
560
561 for each i in g
562 if not already computed i
563 max_i = compute max value(i)
564 "eps = eps * max_i"
565 if zeroes > 0
566 g = groups_used_in_predicate - g
567 if g' is empty
568 maxvar = max_1
569 else
570 max_0 = compute max value(all i in g)
571 maxvar = max_0
572 "eps = eps * (maxvar ^ zeroes)"
573
574 */
575
576 void
visit(AST::UnaryFunction * uf)577 Add_bound_variables::visit( AST::UnaryFunction* uf ) {
578 Generic_visitor::visit( uf );
579 // SQRT and SIGN need special treatment in Rewrite_visitor
580 if( uf->kind == AST::UnaryFunction::XSIGN ) {
581 Variable *new_var = add_tmp_result( uf );
582 Statement_addition_visitor::add_stmt( new AST::VariableDeclaration( new_var ) );
583 if( dynamic_cast<AST::IdentifierExpression*>(uf->e) == nullptr ) {
584 new_var = add_tmp_result( uf->e );
585 Statement_addition_visitor::add_stmt( new AST::VariableDeclaration( new_var ) );
586 }
587 if( epsilon_tmp_variable == nullptr ) {
588 epsilon_tmp_variable = add_variable( "eps", type_float_bound );
589 Statement_addition_visitor::add_stmt_toplevel( new AST::VariableDeclaration( epsilon_tmp_variable ) );
590 }
591
592 Abstract_value *absval_giv = absint_giv->get_analysis_result( uf->e );
593 Group_index_value *giv = dynamic_cast< Group_index_value* >( absval_giv );
594 assert( giv != nullptr );
595 assert( giv->group_item->degree() > 0 );
596
597 Group_algebra::Group_varset groups;
598 giv->group_item->collect_groups( groups );
599 Group_algebra::Group_varset::iterator it;
600 for( it = groups.begin(); it != groups.end(); ++it ) {
601 const Group_cache::Group &group = it->second;
602 Group_cache::iterator gcit = group_cache.groups.find( group );
603 if( gcit == group_cache.end() ) {
604 // we have to allocate a new max variable:
605 std::stringstream varname;
606 varname << "max" << ++max_var_counter;
607 group_cache.add( group, add_variable( varname.str(), type_float ) );
608 MSG( "adding max var " << varname.str() )
609 }
610 }
611 }
612 }
613
614 void
visit(AST::BinaryExpression * bexp)615 Add_bound_variables::visit( AST::BinaryExpression* bexp ) {
616 Generic_visitor::visit( bexp );
617 MSG("")
618 if( is_float_or_int( bexp->e1->getType() ) ||
619 is_float_or_int( bexp->e2->getType() ) )
620 {
621 switch( bexp->kind ) {
622 case AST::BinaryExpression::EQ:
623 case AST::BinaryExpression::GEQ:
624 case AST::BinaryExpression::LEQ:
625 case AST::BinaryExpression::NEQ:
626 case AST::BinaryExpression::LE:
627 case AST::BinaryExpression::GR:
628 case AST::BinaryExpression::AND:
629 case AST::BinaryExpression::OR: {
630 Abstract_value *absval_sfe = absint_sfe->get_analysis_result( bexp->e1 );
631 Static_filter_error *sfe1 = dynamic_cast< Static_filter_error* >( absval_sfe );
632 assert( sfe1 != nullptr );
633 absval_sfe = absint_sfe->get_analysis_result( bexp->e1 );
634 Static_filter_error *sfe2 = dynamic_cast< Static_filter_error* >( absval_sfe );
635 assert( sfe2 != nullptr );
636 if( !sfe1->is_fresh() || !sfe2->is_fresh() )
637 throw RuntimeError( "comparison between derived values not yet supported. use 'sign' or 'compare' instead.", bexp->location );
638 break;
639 }
640 default: ;
641 }
642 }
643 }
644
645
646 void
visit(AST::UnaryFunction * uf)647 Rewrite_sign_of_fresh_values::visit( AST::UnaryFunction *uf ) {
648 Transformation_visitor::transform<AST::Expression>( uf->e );
649 MSG("")
650 AST::Expression *result = uf;
651 if( uf->kind == AST::UnaryFunction::XSIGN && is_float(uf->e->getType()) ) {
652 AST::BinaryExpression *bexp = dynamic_cast<AST::BinaryExpression* >(uf->e);
653 AST::IdentifierExpression *idexp = dynamic_cast<AST::IdentifierExpression*>(uf->e);
654
655 if( bexp != nullptr )
656 {
657 Error_bound_value *is_fresh1 = dynamic_cast<Error_bound_value*>( add_bounds->absint_is_fresh->get_analysis_result( bexp->e1 ) );
658 Error_bound_value *is_fresh2 = dynamic_cast<Error_bound_value*>( add_bounds->absint_is_fresh->get_analysis_result( bexp->e2 ) );
659 assert( is_fresh1 != nullptr && is_fresh2 != nullptr );
660 if( is_fresh1->is_fresh() && is_fresh2->is_fresh() && bexp->kind == AST::BinaryExpression::SUB ) {
661 AST::Expression *cond_e =
662 new AST::ConditionalExpression(
663 new AST::BinaryExpression( bexp->e1, bexp->e2, AST::BinaryExpression::GR ),
664 new AST::LiteralExpression( 1 ),
665 new AST::ConditionalExpression(
666 new AST::BinaryExpression( bexp->e1, bexp->e2, AST::BinaryExpression::LE ),
667 new AST::LiteralExpression( -1 ),
668 new AST::LiteralExpression( 0 )
669 )
670 );
671 result = cond_e;
672 }
673 } else if( idexp != nullptr ) {
674 Error_bound_value *is_fresh = dynamic_cast<Error_bound_value*>( add_bounds->absint_is_fresh->get_analysis_result( idexp ) );
675 assert( is_fresh != nullptr );
676 if( is_fresh->is_fresh() ) {
677 AST::Expression *cond_e =
678 new AST::ConditionalExpression(
679 new AST::BinaryExpression( idexp, new AST::LiteralExpression(0.0), AST::BinaryExpression::GR ),
680 new AST::LiteralExpression( 1 ),
681 new AST::ConditionalExpression(
682 new AST::BinaryExpression( idexp, new AST::LiteralExpression(0.0), AST::BinaryExpression::LE ),
683 new AST::LiteralExpression( -1 ),
684 new AST::LiteralExpression( 0 )
685 )
686 );
687 result = cond_e;
688 }
689 }
690 }
691 Transformation_visitor::push( result );
692 }
693
694 void
compute_max_from(Variable * maxvar,Variable * other,Statement_addition_visitor::Position scope,bool use_fabs)695 Rewrite_float_comparisons::compute_max_from(
696 Variable *maxvar,
697 Variable *other,
698 Statement_addition_visitor::Position scope,
699 bool use_fabs )
700 {
701 assert( maxvar != nullptr );
702 assert( other != nullptr );
703 //MSG( "maxvar: " << maxvar->id )
704 //MSG( "othervar: " << other->id )
705 AST::Expression *e = new AST::IdentifierExpression(other);
706 if( use_fabs )
707 e = new AST::UnaryFunction( e, AST::UnaryFunction::XABS );
708 /*
709 std::map< Variable*, std::set< Variable* > >::iterator
710 begin = add_bounds->group_cache.subset_relation.begin(),
711 end = add_bounds->group_cache.subset_relation.end();
712 */
713 if( max_var_cover.find( maxvar ) == max_var_cover.end() ) {
714 add_stmt_with_scope( make_assign_stmt( maxvar, e ), scope );
715 } else {
716 AST::Expression *cond_e =
717 new AST::BinaryExpression(
718 new AST::IdentifierExpression(maxvar),
719 e,
720 AST::BinaryExpression::LE );
721 AST::Statement *s = new AST::ConditionalStatement(
722 cond_e,
723 make_assign_stmt( maxvar, e ) );
724 add_stmt_with_scope( s, scope );
725 }
726 }
727
728
729
730 void
make_max_computation(Variable * maxvar)731 Rewrite_float_comparisons::make_max_computation( Variable *maxvar ) {
732 MSG( "maxvar: " << maxvar->id )
733 if( max_var_cover.find( maxvar ) == max_var_cover.end() ) {
734 MSG( maxvar->id << " not yet computed!" )
735 std::set<Variable*>::iterator m_begin = add_bounds->group_cache.subset_relation[maxvar].begin();
736 std::set<Variable*>::iterator m_end = add_bounds->group_cache.subset_relation[maxvar].end();
737 std::set<Variable*>::iterator v_begin = add_bounds->group_cache.reverse_mapping[ maxvar ].begin();
738 std::set<Variable*>::iterator v_end = add_bounds->group_cache.reverse_mapping[ maxvar ].end();
739 std::set< Variable* > vars, vars_tmp;
740 //std::copy( m_begin, m_end, std::inserter( vars_tmp, vars_tmp.begin() ) );
741 std::copy( v_begin, v_end, std::inserter( vars_tmp, vars_tmp.begin() ) );
742 std::set_difference( vars_tmp.begin(), vars_tmp.end(),
743 function_parameters.begin(), function_parameters.end(),
744 std::inserter( vars, vars.begin() ) );
745 Statement_addition_visitor::Position scope = get_scope( vars );
746 add_stmt_toplevel( new AST::VariableDeclaration( maxvar ) );
747 for( ; m_begin != m_end; ++m_begin ) {
748 Variable *othervar = *m_begin;
749 MSG("iterate: " << othervar->id )
750 make_max_computation( othervar );
751 compute_max_from( maxvar, othervar, scope, false );
752 std::copy( max_var_cover[othervar].begin(), max_var_cover[othervar].end(),
753 std::inserter( max_var_cover[maxvar], max_var_cover[maxvar].begin() ) );
754 }
755 MSG( maxvar->id << " first iteration ready")
756 assert( add_bounds->group_cache.reverse_mapping.find( maxvar ) != add_bounds->group_cache.reverse_mapping.end() );
757 for( ; v_begin != v_end; ++v_begin ) {
758 if( max_var_cover.find( maxvar ) == max_var_cover.end() ||
759 max_var_cover[maxvar].find( *v_begin ) == max_var_cover[maxvar].end() )
760 {
761 MSG("var left: " << (*v_begin)->id )
762 compute_max_from( maxvar, *v_begin, scope );
763 max_var_cover[maxvar].insert( *v_begin );
764 }
765 }
766 MSG("finished")
767 }
768 }
769
770 void
make_max_groups(Group_index_value * giv,double min_input,AST::Expression * & result_cond_underflow,AST::Expression * & result_cond_overflow)771 Rewrite_float_comparisons::make_max_groups( Group_index_value * giv,
772 double min_input,
773 AST::Expression *&result_cond_underflow,
774 //AST::Expression *&result_cond_zero,
775 AST::Expression *&result_cond_overflow )
776 {
777 assert( giv != nullptr );
778 assert( giv->group_item != nullptr );
779 Group_algebra::Group_varset groups;
780 giv->group_item->collect_groups( groups );
781 Group_algebra::Group_varset::iterator it;
782 // for each input variable degree, store the set of maxvars:
783 std::map< unsigned int, std::set< Variable* > > maxvars_per_degree;
784 for( it = groups.begin(); it != groups.end(); ++it ) {
785 unsigned int degree = it->first;
786 const std::set< Variable* > &group = it->second;
787 Group_cache::iterator gcit = add_bounds->group_cache.find( group );
788 assert( gcit != add_bounds->group_cache.end() );
789 Variable *var = gcit->second;
790 MSG( "using max var " << var->id );
791 make_max_computation( var );
792 maxvars_per_degree[ degree ].insert( var );
793 }
794 if( add_bounds->use_aposteriori_check )
795 return;
796 std::map< unsigned int, std::set< Variable* > >::iterator it2;
797 for( it2 = maxvars_per_degree.begin(); it2 != maxvars_per_degree.end(); ++it2 ) {
798 unsigned int degree = it2->first;
799 std::set< Variable* > maxvar_set = it2->second;
800 std::vector< Variable* > maxvars;
801 std::copy( maxvar_set.begin(), maxvar_set.end(), std::back_inserter( maxvars ) );
802 Variable *lb_var = nullptr, *ub_var = nullptr;
803 derive_min_max( degree, maxvars, lb_var, ub_var );
804
805 // compute actual allowable min/max input
806 /* for each degree:
807 o maintain a seperate lower/upper bound variable.
808 o "distribute" the bounds uniformly: for degree 2 input variables v2,
809 it is assumed that bound(v2) = bound(v1)^2 so that we have an over/underflow
810 if for one of the different degree's lb/ub variables, the actual input bound
811 violates the precomputed bound. example:
812
813 if( lb_1 < 1e-60 || lb_2 < 1e-120 )
814 UNDERFLOW!
815
816 where lb_1 is a degree 1 lower bound and lb_2 a degree 2 lower bound.
817 of course, other mechanisms are imaginable, but this one is easy and works.
818 */
819 CGAL::FPU_CW_t fpu_backup = CGAL::FPU_get_and_set_cw(CGAL_FE_UPWARD);
820 double actual_min_input = std::pow( min_input, (int)degree );
821 CGAL::FPU_set_cw(CGAL_FE_DOWNWARD);
822 double actual_max_input = std::pow( max_input, (int)degree );
823 CGAL::FPU_set_cw(fpu_backup);
824
825 AST::Expression *cond_underflow =
826 new AST::BinaryExpression(
827 new AST::IdentifierExpression( lb_var ),
828 new AST::LiteralExpression( actual_min_input ),
829 AST::BinaryExpression::LE
830 );
831 if( result_cond_underflow == nullptr )
832 result_cond_underflow = cond_underflow;
833 else
834 result_cond_underflow =
835 new AST::BinaryExpression(
836 result_cond_underflow,
837 cond_underflow,
838 AST::BinaryExpression::OR
839 );
840
841 /*AST::Expression *cond_zero =
842 new AST::BinaryExpression(
843 new AST::IdentifierExpression( lb_var ),
844 new AST::LiteralExpression( 0.0 ),
845 AST::BinaryExpression::EQ
846 );
847 if( result_cond_zero == nullptr )
848 result_cond_zero = cond_zero;
849 else
850 result_cond_zero =
851 new AST::BinaryExpression(
852 result_cond_zero,
853 cond_zero,
854 AST::BinaryExpression::AND
855 );*/
856
857 AST::Expression *cond_overflow =
858 new AST::BinaryExpression(
859 new AST::IdentifierExpression( ub_var ),
860 new AST::LiteralExpression( actual_max_input ),
861 AST::BinaryExpression::GR
862 );
863 if( result_cond_overflow == nullptr )
864 result_cond_overflow = cond_overflow;
865 else
866 result_cond_overflow =
867 new AST::BinaryExpression(
868 result_cond_overflow,
869 cond_overflow,
870 AST::BinaryExpression::OR
871 );
872 }
873 }
874
875 void
derive_min_max(unsigned int degree,std::vector<Variable * > & max_variables,Variable * & lb_var,Variable * & ub_var)876 Rewrite_float_comparisons::derive_min_max( unsigned int degree,
877 std::vector< Variable* > &max_variables,
878 Variable *& lb_var,
879 Variable *& ub_var )
880 {
881 std::vector< Variable* >::iterator var_it,
882 begin = max_variables.begin(),
883 end = max_variables.end();
884 std::set< Variable*> max_ignore;
885 if( max_variables.size() == 1 ) {
886 ub_var = lb_var = max_variables.front();
887 return;
888 } else
889 add_bounds->group_cache.find_maximum( max_variables, max_ignore );
890
891 if( lb_vars.find( degree ) == lb_vars.end() ) {
892 std::stringstream lb_varname, ub_varname;
893 lb_varname << "lower_bound_" << degree;
894 ub_varname << "upper_bound_" << degree;
895 lb_var = lb_vars[degree] = add_bounds->add_variable( lb_varname.str(), type_float_bound );
896 ub_var = ub_vars[degree] = add_bounds->add_variable( ub_varname.str(), type_float_bound );
897 add_stmt_toplevel( new AST::VariableDeclaration( lb_var ) );
898 add_stmt_toplevel( new AST::VariableDeclaration( ub_var ) );
899 } else {
900 lb_var = lb_vars[degree];
901 ub_var = ub_vars[degree];
902 }
903
904
905 bool first = true;
906 for( ; begin != end; ++begin ) {
907 Variable *max_var = *begin;
908 AST::Expression *id_max_var = new AST::IdentifierExpression( max_var );
909 AST::Expression *id_lb_var = new AST::IdentifierExpression( lb_var );
910 AST::Expression *id_ub_var = new AST::IdentifierExpression( ub_var );
911 if( first ) {
912 add_stmt( make_assign_stmt( lb_var, id_max_var ) );
913 add_stmt( make_assign_stmt( ub_var, id_max_var ) );
914 first = false;
915 } else {
916 AST::Expression *cond_max_gt_ub =
917 new AST::BinaryExpression(
918 id_max_var,
919 id_ub_var,
920 AST::BinaryExpression::GR
921 );
922 AST::Expression *cond_max_lt_lb =
923 new AST::BinaryExpression(
924 id_max_var,
925 id_lb_var,
926 AST::BinaryExpression::LE
927 );
928
929 bool ub_ignore = max_ignore.find( max_var ) != max_ignore.end();
930 add_stmt(
931 new AST::ConditionalStatement(
932 cond_max_lt_lb,
933 make_assign_stmt( lb_var, id_max_var ),
934 ub_ignore ? nullptr
935 : new AST::ConditionalStatement(
936 cond_max_gt_ub,
937 make_assign_stmt( ub_var, id_max_var ) )
938 )
939 );
940 }
941 }
942 }
943
944 AST::Expression*
make_max_term(Group_algebra::Group_item * item)945 Rewrite_float_comparisons::make_max_term( Group_algebra::Group_item *item ) {
946 Group_algebra::Leaf_item *leaf = dynamic_cast<Group_algebra::Leaf_item*>(item);
947 if( leaf != nullptr ) {
948 Group_cache::iterator it = add_bounds->group_cache.find( leaf->variables );
949 assert( it != add_bounds->group_cache.end() );
950 return new AST::IdentifierExpression( it->second );
951 }
952 Group_algebra::Array_item *array = dynamic_cast<Group_algebra::Array_item*>(item);
953 bool is_sum = dynamic_cast<Group_algebra:: Sum_item*>(item) != nullptr;
954 argused(is_sum);
955 bool is_prod = dynamic_cast<Group_algebra::Product_item*>(item) != nullptr;
956 assert( is_sum || is_prod );
957 assert( array->items.size() >= 2 );
958 std::vector< Group_algebra::Group_item* >::iterator it = array->items.begin();
959 AST::Expression *result = make_max_term( *it++ );
960 do {
961 AST::Expression *e2 = make_max_term( *it++ );
962 if( is_prod ) result = new AST::BinaryExpression( result, e2, AST::BinaryExpression::MUL );
963 else result = AST::make_funcall( fun_std_max, result, e2 );
964 } while( it != array->items.end() );
965 return result;
966 }
967
968 // -----------------------------------
969
970 void
visit(AST::FunctionDefinition * fundef)971 Rewrite_float_comparisons::visit( AST::FunctionDefinition * fundef ) {
972 function_parameters.clear();
973 std::copy( fundef->type->parameters.begin(), fundef->type->parameters.end(),
974 std::inserter( function_parameters, function_parameters.begin() ) );
975 Transformation_visitor::visit( fundef );
976 }
977
978 void
visit(AST::UnaryFunction * uf)979 Rewrite_float_comparisons::visit( AST::UnaryFunction *uf ) {
980 Transformation_visitor::transform<AST::Expression>( uf->e );
981
982 if( uf->kind == AST::UnaryFunction::XSIGN && is_float(uf->e->getType()) ) {
983 Abstract_value *absval_sfe = add_bounds->absint_sfe->get_analysis_result( uf->e );
984 Static_filter_error *sfe = dynamic_cast< Static_filter_error* >( absval_sfe );
985 assert( sfe != nullptr );
986
987 Abstract_value *absval_giv = add_bounds->absint_giv->get_analysis_result( uf->e );
988 Group_index_value *giv = dynamic_cast< Group_index_value* >( absval_giv );
989 assert( giv != nullptr );
990 assert( giv->group_item != nullptr );
991
992 Variable *tmp_result_var = add_bounds->tmp_result_variable( uf );
993 Variable *tmp_arg_var = nullptr;
994 if( add_bounds->has_tmp_result_variable( uf->e ) ) {
995 tmp_arg_var = add_bounds->tmp_result_variable( uf->e );
996 add_stmt( make_assign_stmt( tmp_arg_var, uf->e ) );
997 } else {
998 AST::IdentifierExpression *idexp = dynamic_cast<AST::IdentifierExpression*>(uf->e);
999 assert( idexp != nullptr );
1000 tmp_arg_var = idexp->var;
1001 }
1002 assert( tmp_arg_var != nullptr );
1003 assert( tmp_result_var != nullptr );
1004 //assert( add_bounds->max_result_variables.size() > 0 );
1005 // correction due to the eps computation. for each multiplication, we need to add 'error*ulp'
1006 unsigned int degree = giv->group_item->degree();
1007 assert( degree > 0 );
1008 CGAL::FPU_CW_t fpu_backup = CGAL::FPU_get_and_set_cw(CGAL_FE_UPWARD);
1009 double epsilon = sfe->error().error() +
1010 sfe->error().error() * CGAL::Static_filter_error::ulp() * (degree-1);
1011 double min_input = std::pow( std::numeric_limits<double>::min() / epsilon,
1012 1.0 / degree );
1013 double check_underflow = min_input;
1014 for( unsigned int i = 1; i < degree; ++i )
1015 check_underflow *= min_input;
1016 CGAL::FPU_set_cw(fpu_backup);
1017 assert( check_underflow > std::numeric_limits<double>::min() );
1018 //std::cout << "epsilon: " << epsilon << std::endl;
1019 AST::Expression *eps = new AST::LiteralExpression( epsilon );
1020
1021 eps = new AST::BinaryExpression( eps, make_max_term( giv->group_item ), AST::BinaryExpression::MUL );
1022 //giv->dump(std::cout);
1023 //uf->e->dump(0);
1024 AST::Expression *cond_underflow = nullptr, /* *cond_zero = nullptr, */ *cond_overflow = nullptr;
1025 make_max_groups( giv, min_input, cond_underflow, /*cond_zero, */cond_overflow );
1026
1027 static AST::Expression *plus_one = new AST::LiteralExpression( +1);
1028 static AST::Expression *minus_one = new AST::LiteralExpression( -1);
1029
1030 AST::Expression *cond_det_gt_eps =
1031 new AST::BinaryExpression(
1032 new AST::IdentifierExpression( tmp_arg_var ),
1033 new AST::IdentifierExpression( add_bounds->epsilon_tmp_variable ),
1034 AST::BinaryExpression::GR
1035 );
1036 AST::Expression *cond_det_lt_minus_eps =
1037 new AST::BinaryExpression(
1038 new AST::IdentifierExpression( tmp_arg_var ),
1039 new AST::UnaryExpression(
1040 new AST::IdentifierExpression( add_bounds->epsilon_tmp_variable ),
1041 AST::UnaryExpression::NEG
1042 ),
1043 AST::BinaryExpression::LE
1044 );
1045
1046 // *** prepare for later use:
1047 AST::StatementList *compare_with_eps = new AST::StatementList;
1048 // check for possible overflow in computation of uf->e, and just return if unsure
1049 if( !add_bounds->use_aposteriori_check ) {
1050 compare_with_eps->add(
1051 new AST::ConditionalStatement(
1052 cond_overflow,
1053 new AST::Return( AST::uncertain_return_value )
1054 )
1055 );
1056 }
1057
1058 // compute eps
1059 compare_with_eps->add( make_assign_stmt( add_bounds->epsilon_tmp_variable, eps ) );
1060
1061 // compare +/- eps with uf->e, returning if unsure
1062 compare_with_eps->add(
1063 new AST::ConditionalStatement(
1064 cond_det_gt_eps,
1065 make_assign_stmt( tmp_result_var, plus_one ),
1066 new AST::ConditionalStatement(
1067 cond_det_lt_minus_eps,
1068 make_assign_stmt( tmp_result_var, minus_one ),
1069 new AST::Return( AST::uncertain_return_value )
1070 )
1071 )
1072 );
1073
1074
1075 if( add_bounds->use_aposteriori_check ) {
1076 compare_with_eps->add(
1077 new AST::ConditionalStatement(
1078 make_fe_condition(),
1079 make_fe_clear_and_fail()
1080 )
1081 );
1082 add_stmt( compare_with_eps );
1083 } else {
1084 // check for underflow/exact zero:
1085 add_stmt(
1086 new AST::ConditionalStatement(
1087 cond_underflow,
1088 //new AST::ConditionalStatement(
1089 // cond_zero,
1090 // make_assign_stmt( tmp_result_var, new AST::LiteralExpression(0) ),
1091 new AST::Return( AST::uncertain_return_value )
1092 //)
1093 ,
1094 // else perform steps described above (see ***)
1095 compare_with_eps
1096 )
1097 );
1098 }
1099
1100 Transformation_visitor::push( new AST::IdentifierExpression( tmp_result_var ) );
1101 } else
1102 Transformation_visitor::push( uf );
1103 }
1104
1105 void
reset()1106 Rewrite_float_comparisons::reset() {
1107 max_var_cover.clear();
1108 lb_vars.clear();
1109 ub_vars.clear();
1110 }
1111
1112
1113