PPL  1.2
linearize.hh
Go to the documentation of this file.
1 /* Linearization function implementation.
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #ifndef PPL_linearize_hh
25 #define PPL_linearize_hh 1
26 
28 #include "Float_defs.hh"
29 #include "Linear_Form_defs.hh"
30 #include "Box_defs.hh"
31 #include <map>
32 
33 namespace Parma_Polyhedra_Library {
34 
108 template <typename Target, typename FP_Interval_Type>
109 static bool
113  lf_store,
115  PPL_ASSERT(bop_expr.binary_operator() == Binary_Operator<Target>::ADD);
116 
117  typedef Linear_Form<FP_Interval_Type> FP_Linear_Form;
118 
119  if (!linearize(*(bop_expr.left_hand_side()), oracle, lf_store, result)) {
120  return false;
121  }
122 
123  Floating_Point_Format analyzed_format =
124  bop_expr.type().floating_point_format();
125  FP_Linear_Form rel_error;
126  result.relative_error(analyzed_format, rel_error);
127  result += rel_error;
128  FP_Linear_Form linearized_second_operand;
129  if (!linearize(*(bop_expr.right_hand_side()), oracle, lf_store,
130  linearized_second_operand)) {
131  return false;
132  }
133 
134  result += linearized_second_operand;
135  linearized_second_operand.relative_error(analyzed_format, rel_error);
136  result += rel_error;
137  FP_Interval_Type absolute_error =
138  compute_absolute_error<FP_Interval_Type>(analyzed_format);
139  result += absolute_error;
140  return !result.overflows();
141 }
142 
222 template <typename Target, typename FP_Interval_Type>
223 static bool
226  const std::map<dimension_type, Linear_Form<FP_Interval_Type> >& lf_store,
228  PPL_ASSERT(bop_expr.binary_operator() == Binary_Operator<Target>::SUB);
229 
230  typedef Linear_Form<FP_Interval_Type> FP_Linear_Form;
231 
232  if (!linearize(*(bop_expr.left_hand_side()), oracle, lf_store, result)) {
233  return false;
234  }
235 
236  Floating_Point_Format analyzed_format =
237  bop_expr.type().floating_point_format();
238  FP_Linear_Form rel_error;
239  result.relative_error(analyzed_format, rel_error);
240  result += rel_error;
241  FP_Linear_Form linearized_second_operand;
242  if (!linearize(*(bop_expr.right_hand_side()), oracle, lf_store,
243  linearized_second_operand)) {
244  return false;
245  }
246 
247  result -= linearized_second_operand;
248  linearized_second_operand.relative_error(analyzed_format, rel_error);
249  result += rel_error;
250  FP_Interval_Type absolute_error =
251  compute_absolute_error<FP_Interval_Type>(analyzed_format);
252  result += absolute_error;
253  return !result.overflows();
254 }
255 
364 template <typename Target, typename FP_Interval_Type>
365 static bool
368  const std::map<dimension_type, Linear_Form<FP_Interval_Type> >& lf_store,
370  PPL_ASSERT(bop_expr.binary_operator() == Binary_Operator<Target>::MUL);
371 
372  typedef typename FP_Interval_Type::boundary_type analyzer_format;
373  typedef Linear_Form<FP_Interval_Type> FP_Linear_Form;
374 
375  /*
376  FIXME: We currently adopt the "Interval-Size Local" strategy in order to
377  decide which of the two linear forms must be intervalized, as described
378  in Section 6.2.4 ("Multiplication Strategies") of Antoine Mine's Ph.D.
379  thesis "Weakly Relational Numerical Abstract Domains".
380  In this Section are also described other multiplication strategies, such
381  as All-Cases, Relative-Size Local, Simplification-Driven Global and
382  Homogeneity Global.
383  */
384 
385  // Here we choose which of the two linear forms must be intervalized.
386 
387  // true if we intervalize the first form, false if we intervalize the second.
388  bool intervalize_first;
389  FP_Linear_Form linearized_first_operand;
390  if (!linearize(*(bop_expr.left_hand_side()), oracle, lf_store,
391  linearized_first_operand)) {
392  return false;
393  }
394  FP_Interval_Type intervalized_first_operand;
395  if (!linearized_first_operand.intervalize(oracle,
396  intervalized_first_operand)) {
397  return false;
398  }
399  FP_Linear_Form linearized_second_operand;
400  if (!linearize(*(bop_expr.right_hand_side()), oracle, lf_store,
401  linearized_second_operand)) {
402  return false;
403  }
404  FP_Interval_Type intervalized_second_operand;
405  if (!linearized_second_operand.intervalize(oracle,
406  intervalized_second_operand)) {
407  return false;
408  }
409 
410  // FIXME: we are not sure that what we do here is policy-proof.
411  if (intervalized_first_operand.is_bounded()) {
412  if (intervalized_second_operand.is_bounded()) {
413  analyzer_format first_interval_size
414  = intervalized_first_operand.upper()
415  - intervalized_first_operand.lower();
416  analyzer_format second_interval_size
417  = intervalized_second_operand.upper()
418  - intervalized_second_operand.lower();
419  if (first_interval_size <= second_interval_size) {
420  intervalize_first = true;
421  }
422  else {
423  intervalize_first = false;
424  }
425  }
426  else {
427  intervalize_first = true;
428  }
429  }
430  else {
431  if (intervalized_second_operand.is_bounded()) {
432  intervalize_first = false;
433  }
434  else {
435  return false;
436  }
437  }
438 
439  // Here we do the actual computation.
440  // For optimizing, we store the relative error directly into result.
441  Floating_Point_Format analyzed_format =
442  bop_expr.type().floating_point_format();
443  if (intervalize_first) {
444  linearized_second_operand.relative_error(analyzed_format, result);
445  linearized_second_operand *= intervalized_first_operand;
446  result *= intervalized_first_operand;
447  result += linearized_second_operand;
448  }
449  else {
450  linearized_first_operand.relative_error(analyzed_format, result);
451  linearized_first_operand *= intervalized_second_operand;
452  result *= intervalized_second_operand;
453  result += linearized_first_operand;
454  }
455 
456  FP_Interval_Type absolute_error =
457  compute_absolute_error<FP_Interval_Type>(analyzed_format);
458  result += absolute_error;
459  return !result.overflows();
460 }
461 
558 template <typename Target, typename FP_Interval_Type>
559 static bool
562  const std::map<dimension_type, Linear_Form<FP_Interval_Type> >& lf_store,
564  PPL_ASSERT(bop_expr.binary_operator() == Binary_Operator<Target>::DIV);
565 
566  typedef Linear_Form<FP_Interval_Type> FP_Linear_Form;
567 
568  FP_Linear_Form linearized_second_operand;
569  if (!linearize(*(bop_expr.right_hand_side()), oracle, lf_store,
570  linearized_second_operand)) {
571  return false;
572  }
573  FP_Interval_Type intervalized_second_operand;
574  if (!linearized_second_operand.intervalize(oracle,
575  intervalized_second_operand)) {
576  return false;
577  }
578  // Check if we may divide by zero.
579  if ((intervalized_second_operand.lower_is_boundary_infinity()
580  || intervalized_second_operand.lower() <= 0) &&
581  (intervalized_second_operand.upper_is_boundary_infinity()
582  || intervalized_second_operand.upper() >= 0)) {
583  return false;
584  }
585  if (!linearize(*(bop_expr.left_hand_side()), oracle, lf_store, result)) {
586  return false;
587  }
588 
589  Floating_Point_Format analyzed_format =
590  bop_expr.type().floating_point_format();
591  FP_Linear_Form rel_error;
592  result.relative_error(analyzed_format, rel_error);
593  result /= intervalized_second_operand;
594  rel_error /= intervalized_second_operand;
595  result += rel_error;
596  FP_Interval_Type absolute_error =
597  compute_absolute_error<FP_Interval_Type>(analyzed_format);
598  result += absolute_error;
599  return !result.overflows();
600 }
601 
633 template <typename Target, typename FP_Interval_Type>
634 static bool
637  const std::map<dimension_type, Linear_Form<FP_Interval_Type> >& lf_store,
639  typedef typename FP_Interval_Type::boundary_type analyzer_format;
640  typedef Linear_Form<FP_Interval_Type> FP_Linear_Form;
641 
642  Floating_Point_Format analyzed_format =
643  cast_expr.type().floating_point_format();
644  const Concrete_Expression<Target>* cast_arg = cast_expr.argument();
645  if (cast_arg->type().is_floating_point()) {
646  if (!linearize(*cast_arg, oracle, lf_store, result)) {
647  return false;
648  }
649  if (!is_less_precise_than(analyzed_format,
650  cast_arg->type().floating_point_format())
651  || result == FP_Linear_Form(FP_Interval_Type(0))
652  || result == FP_Linear_Form(FP_Interval_Type(1))) {
653  /*
654  FIXME: find a general way to check if the casted constant
655  is exactly representable in the less precise format.
656  */
657  /*
658  We are casting to a more precise format or casting
659  a definitely safe value: do not add errors.
660  */
661  return true;
662  }
663  }
664  else {
665  FP_Interval_Type expr_value;
666  if (!oracle.get_integer_expr_value(*cast_arg, expr_value))
667  return false;
668  result = FP_Linear_Form(expr_value);
670  || result == FP_Linear_Form(FP_Interval_Type(0))
671  || result == FP_Linear_Form(FP_Interval_Type(1))) {
672  /*
673  FIXME: find a general way to check if the casted constant
674  is exactly representable in the less precise format.
675  */
676  /*
677  We are casting to a more precise format or casting
678  a definitely safe value: do not add errors.
679  */
680  return true;
681  }
682  }
683 
684  FP_Linear_Form rel_error;
685  result.relative_error(analyzed_format, rel_error);
686  result += rel_error;
687  FP_Interval_Type absolute_error =
688  compute_absolute_error<FP_Interval_Type>(analyzed_format);
689  result += absolute_error;
690  return !result.overflows();
691 }
692 
694 
727 template <typename Target, typename FP_Interval_Type>
728 bool
731  const std::map<dimension_type, Linear_Form<FP_Interval_Type> >& lf_store,
733  typedef typename FP_Interval_Type::boundary_type analyzer_format;
734  typedef Linear_Form<FP_Interval_Type> FP_Linear_Form;
735  typedef std::map<dimension_type, FP_Linear_Form>
736  FP_Linear_Form_Abstract_Store;
737 
738  PPL_ASSERT(expr.type().is_floating_point());
739  // Check that analyzer_format is a floating point type.
740  PPL_COMPILE_TIME_CHECK(!std::numeric_limits<analyzer_format>::is_exact,
741  "linearize<Target, FP_Interval_Type>:"
742  " FP_Interval_Type is not the type of an interval with floating point boundaries.");
743 
744  switch(expr.kind()) {
746  PPL_UNREACHABLE;
747  break;
749  {
750  const Floating_Point_Constant<Target>* fpc_expr =
751  expr.template as<Floating_Point_Constant>();
752  FP_Interval_Type constant_value;
753  if (!oracle.get_fp_constant_value(*fpc_expr, constant_value)) {
754  return false;
755  }
756  result = FP_Linear_Form(constant_value);
757  return true;
758  }
760  {
761  const Unary_Operator<Target>* uop_expr =
762  expr.template as<Unary_Operator>();
763  switch (uop_expr->unary_operator()) {
765  return linearize(*(uop_expr->argument()), oracle, lf_store, result);
767  if (!linearize(*(uop_expr->argument()), oracle, lf_store, result)) {
768  return false;
769  }
770 
771  result.negate();
772  return true;
774  throw std::runtime_error("PPL internal error: unimplemented");
775  break;
776  default:
777  PPL_UNREACHABLE;
778  break;
779  }
780  break;
781  }
783  {
784  const Binary_Operator<Target>* bop_expr =
785  expr.template as<Binary_Operator>();
786  switch (bop_expr->binary_operator()) {
788  return add_linearize(*bop_expr, oracle, lf_store, result);
790  return sub_linearize(*bop_expr, oracle, lf_store, result);
792  return mul_linearize(*bop_expr, oracle, lf_store, result);
794  return div_linearize(*bop_expr, oracle, lf_store, result);
801  // FIXME: can we do better?
802  return false;
803  default:
804  PPL_UNREACHABLE;
805  return false;
806  }
807  break;
808  }
810  {
811  const Approximable_Reference<Target>* ref_expr =
812  expr.template as<Approximable_Reference>();
813  std::set<dimension_type> associated_dimensions;
814  if (!oracle.get_associated_dimensions(*ref_expr, associated_dimensions)
815  || associated_dimensions.empty()) {
816  /*
817  We were unable to find any associated space dimension:
818  linearization fails.
819  */
820  return false;
821  }
822 
823  if (associated_dimensions.size() == 1) {
824  /* If a linear form associated to the only referenced
825  space dimension exists in lf_store, return that form.
826  Otherwise, return the simplest linear form. */
827  dimension_type variable_index = *associated_dimensions.begin();
828  PPL_ASSERT(variable_index != not_a_dimension());
829 
830  typename FP_Linear_Form_Abstract_Store::const_iterator
831  variable_value = lf_store.find(variable_index);
832  if (variable_value == lf_store.end()) {
833  result = FP_Linear_Form(Variable(variable_index));
834  return true;
835  }
836 
837  result = FP_Linear_Form(variable_value->second);
838  /* FIXME: do we really need to contemplate the possibility
839  that an unbounded linear form was saved into lf_store? */
840  return !result.overflows();
841  }
842 
843  /*
844  Here associated_dimensions.size() > 1. Try to return the LUB
845  of all intervals associated to each space dimension.
846  */
847  PPL_ASSERT(associated_dimensions.size() > 1);
848  std::set<dimension_type>::const_iterator i
849  = associated_dimensions.begin();
850  std::set<dimension_type>::const_iterator i_end
851  = associated_dimensions.end();
852  FP_Interval_Type lub(EMPTY);
853  for (; i != i_end; ++i) {
854  FP_Interval_Type curr_int;
855  PPL_ASSERT(*i != not_a_dimension());
856  if (!oracle.get_interval(*i, curr_int)) {
857  return false;
858  }
859 
860  lub.join_assign(curr_int);
861  }
862 
863  result = FP_Linear_Form(lub);
864  return !result.overflows();
865  }
867  {
868  const Cast_Operator<Target>* cast_expr =
869  expr.template as<Cast_Operator>();
870  return cast_linearize(*cast_expr, oracle, lf_store, result);
871  }
872  default:
873  PPL_UNREACHABLE;
874  break;
875  }
876 
877  PPL_UNREACHABLE;
878  return false;
879 }
880 
881 } // namespace Parma_Polyhedra_Library
882 
883 #endif // !defined(PPL_linearize_hh)
A cast operator converting one concrete expression to some type.
The empty element, i.e., the empty set.
virtual bool get_interval(dimension_type dim, FP_Interval_Type &result) const =0
Asks the external analyzer for an interval that correctly approximates the floating point entity refe...
virtual bool get_fp_constant_value(const Floating_Point_Constant< Target > &expr, FP_Interval_Type &result) const =0
Asks the external analyzer for an interval that correctly approximates the value of floating point co...
An abstract class to be implemented by an external analyzer such as ECLAIR in order to provide to the...
Definition: Float_defs.hh:399
size_t dimension_type
An unsigned integral type for representing space dimensions.
void negate()
Negates all the coefficients of *this.
bool overflows() const
Verifies if the linear form overflows.
static bool cast_linearize(const Cast_Operator< Target > &cast_expr, const FP_Oracle< Target, FP_Interval_Type > &oracle, const std::map< dimension_type, Linear_Form< FP_Interval_Type > > &lf_store, Linear_Form< FP_Interval_Type > &result)
Definition: linearize.hh:635
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
static bool sub_linearize(const Binary_Operator< Target > &bop_expr, const FP_Oracle< Target, FP_Interval_Type > &oracle, const std::map< dimension_type, Linear_Form< FP_Interval_Type > > &lf_store, Linear_Form< FP_Interval_Type > &result)
Definition: linearize.hh:224
An integer constant concrete expression.
A binary operator applied to two concrete expressions.
A dimension of the vector space.
A unary operator applied to one concrete expression.
void relative_error(Floating_Point_Format analyzed_format, Linear_Form &result) const
Computes the relative error associated to floating point computations that operate on a quantity that...
#define PPL_COMPILE_TIME_CHECK(e, msg)
Produces a compilation error if the compile-time constant e does not evaluate to true ...
bool is_less_precise_than(Floating_Point_Format f1, Floating_Point_Format f2)
A concrete expression representing a reference to some approximable.
A linear form with interval coefficients.
virtual bool get_associated_dimensions(const Approximable_Reference< Target > &expr, std::set< dimension_type > &result) const =0
Asks the external analyzer for the possible space dimensions that are associated to the approximable ...
static bool add_linearize(const Binary_Operator< Target > &bop_expr, const FP_Oracle< Target, FP_Interval_Type > &oracle, const std::map< dimension_type, Linear_Form< FP_Interval_Type > > &lf_store, Linear_Form< FP_Interval_Type > &result)
Definition: linearize.hh:110
bool linearize(const Concrete_Expression< Target > &expr, const FP_Oracle< Target, FP_Interval_Type > &oracle, const std::map< dimension_type, Linear_Form< FP_Interval_Type > > &lf_store, Linear_Form< FP_Interval_Type > &result)
Linearizes a floating point expression.
Definition: linearize.hh:729
The base class of all concrete expressions.
virtual bool get_integer_expr_value(const Concrete_Expression< Target > &expr, FP_Interval_Type &result) const =0
Asks the external analyzer for an interval that correctly approximates the value of expr...
The entire library is confined to this namespace.
Definition: version.hh:61
A floating-point constant concrete expression.
static bool mul_linearize(const Binary_Operator< Target > &bop_expr, const FP_Oracle< Target, FP_Interval_Type > &oracle, const std::map< dimension_type, Linear_Form< FP_Interval_Type > > &lf_store, Linear_Form< FP_Interval_Type > &result)
Definition: linearize.hh:366
static bool div_linearize(const Binary_Operator< Target > &bop_expr, const FP_Oracle< Target, FP_Interval_Type > &oracle, const std::map< dimension_type, Linear_Form< FP_Interval_Type > > &lf_store, Linear_Form< FP_Interval_Type > &result)
Definition: linearize.hh:560