如何在IR中表示数学域

How to represent a mathematical domain in IR?

本文关键字:表示 IR      更新时间:2023-10-16

我想从约束列表中定义一个表示数学领域的对象,但我不清楚如何做到这一点。

例如,我从IR开始,我有以下约束:

  • x> 0
  • x不在[3,5]
  • x不在[7,12][

,我的域是0,3]U] 5、7 (U (12 + oo。

我如何在c++结构中很好地存储它?你以前做过吗?此外,我希望能够轻松检查域是否为空。

除非你想使用评论中提到的"第三方"工具,否则你必须编写自己的Interval类。要做到这一点,您可以这样做:

class Interval{
  struct Range{
     bool leftInclusive, rightInclusive;
     double left, right;
     bool operator<(Range other){return left<other.left;}
  }
  std::Set<Range> trueRanges;
  void addTrueRange(Range r){
    //check for overlaps
    //merge if overlapping
    //otherwise add to trueRanges
  }
  bool trueAt(double at){
   //find the range with the highest left-bound lower than at
   auto candidate = truethRanges.upper_bound(at); 
   if(candidate == trueRanged.end()) return false; // no range found
   //on-point checking here
   if(at <= candidate->left) return false;
   if(at >= candidate->right) return false;
   return true;
 }
}

这里省略了点检查,因为您不能简单地说doubleOne == doubleTwo,因为这可能会导致假阴性。所以是ABS(doubleOne-doubleTwo) < tinyValue

你可以看看这个来查找重叠

回答我自己的问题

实际上,我遵循了sbabbi的想法,使用来自boost/numeric/interval的间隔列表,表示间隔的并集。

下面是一个例子:

typedef boost::numeric::interval_lib::rounded_math<double> RoundedPolicy;
typedef boost::numeric::interval_lib::checking_base<double> CheckingPolicy;
typedef boost::numeric::interval_lib::policies<RoundedPolicy,CheckingPolicy> IntervalPolicies;
typedef boost::numeric::interval<double,IntervalPolicies> interval;
//...
bool is_interval_empty(const interval& inter)
{
  return boost::numeric::empty(inter);
}
void restrict(interval& domain, const interval& inter)
{
  for(std::list<interval>::iterator it = domain.begin(); it != domain.end(); ++it)
    *it = boost::numeric::intersect(*it, inter);
  domain.remove_if(is_interval_empty);
}
void restrict(interval& domain, const interval& inter1, const interval& inter2)
{
  for(std::list<interval>::iterator it = domain.begin(); it != domain.end(); ++it)
  {
    domain.push_front(boost::numeric::intersect(*it, inter1));
    *it = boost::numeric::intersect(*it, inter2);
  }
  domain.remove_if(is_interval_empty);
}
//...
std::list<interval> domain;
for(unsigned long int i = 0; i < constraints.size(); ++i)
{
  if(constraints[i].is_lower_bound())
  {
    interval restriction(constraints[i].get_lower_bound(), std::numeric_limits<double>::infinity());
    restrict(domain, restriction);
  }
  else if(constraints[i].is_upper_bound())
  {
    interval restriction(-std::numeric_limits<double>::infinity(), constraints[i].get_upper_bound());
    restrict(domain, restriction);
  }
  else if(constraints[i].is_forbidden_range())
  {
    interval restriction1(-std::numeric_limits<double>::infinity(), constraints[i].get_lower_bound());
    interval restriction2(constraints[i].get_upper_bound(), std::numeric_limits<double>::infinity());
    restrict(domain, restriction1, restriction2);
  }
}
if(domain.size() == 0)
  std::cout << "empty domain" << std::endl;
else
  std::cout << "the domain exists" << std::endl;