The Actual Real-Interval Constraint

The actual real-interval constraint is represented by instances of the class RI. It stores the upper and lower bound, to approximate a real number. Apart from constructors and initialization functions a couple of general functions are defined.

class RI : public OZ_Ct {
private:
  ri_float _l_u;
 
public:
  RI(void) {}
  RI(ri_float lri_float u) : _l(l), _u(u) {}
 
  void init(OZ_Term t) { _l = _u = OZ_floatToC(t);  }
 
  ri_float getWidth(void) { return _u - _l; }
 
  static OZ_Ct * leastConstraint(void) {
    static RI ri(RI_FLOAT_MIN, RI_FLOAT_MAX);
    return &ri;
  }
 
  static OZ_Boolean isValidValue(OZ_Term f) {
    return OZ_isFloat(f);
  }
 
  OZ_Boolean isTouched(RIProfile rip) {
    return (rip._l < _l) || (rip._u > _u);
  }
  ...

The member functions leastConstraint() and isValidValue() are used by class RIDefinition and their definition is self-explanatory. Note that ri_float values have to be compatible with Oz float such that OZ_float() is used for testing compatibility.

Most of the definitions of virtual member functions and operators used for implementing constraint propagation are self-explanatory. Note that copy() uses the new operator provided by OZ_Ct and the constructor RI(ri_float,ri_float). The function isValue() assumes a global variable ri_float ri_precision; that holds the current precision.

  ...
  virtual char * toString(int);
  virtual size_t sizeOf(void);
 
  virtual OZ_Ct * copy(void) {
    RI * ri = new (sizeof(ri_float)) RI(_l, _u);
    return ri;
  }
 
  virtual OZ_Boolean isValue(void) {
    return (getWidth() < ri_precision);
  }
 
  virtual OZ_Term toValue(void) {
    double val = (_u + _l) / 2.0;
    return OZ_float(val);
  }
 
  virtual OZ_Boolean isValid(void) {
    return _l <= _u;
  }
  ...

The function getWakeUpDescriptor() computes from the current state of the constraint and a given constraint profile p a wake-up descriptor. Therefore, it creates an empty one and sets the appropriate events successively. Finally it returns the descriptor.

  ...
  virtual RIProfile * getProfile(void) {
    static RIProfile rip;
    rip.init(this);
    return &rip;
  }
 
  virtual  
  OZ_CtWakeUp getWakeUpDescriptor(OZ_CtProfile * p) {
    OZ_CtWakeUp d;
    d.init();
     
    RIProfile * rip = (RIProfile *) p;
    if (_l > rip->_l) d.setWakeUp(0);
    if (_u < rip->_u) d.setWakeUp(1);
 
    return d;
  }
  ...
 

The function isWeakerThan() simply compares the widths of two real-interval constraints to detect whether the constraint *this is subsumed by *r. This makes sense since *this represents never values not represented by *r which is ensured by the runtime system.

The unification routine for two real-interval constraints computes the intersection of the values approximated by *this and *r. The result is stored in a static variable and eventually a pointer to this variable is returned.

  ...
  virtual OZ_Boolean isWeakerThan(OZ_Ct * r) {
    RI * ri = (RI *) r;
    return (ri->getWidth() < getWidth());
  }
 
  virtual OZ_Ct * unify(OZ_Ct * r) {
    RI * x = this, * y = (RI *) r;
    static RI z;  
 
    z._l = max(x->_l, y->_l);
    z._u = min(x->_u, y->_u);
 
    return &z;
  }
 
  virtual OZ_Boolean unify(OZ_Term rvt) {
    if (isValidValue(rvt)) {
      double rv = OZ_floatToC(rvt);
       
      return (_l <= rv) && (rv <= _u);
    }  
    return 0;
  }
  ...

The unification routine of a real-interval constraint and a value checks if the value is compatible with float numbers and then, if the value is contained in the set of values represented by the constraint. Note that this function indicates only if a unification is successful and does not update the constraint.

The operators for constraint propagation are straight-forward. They return the width of the computed constraint. In case the width is less zero, the constraint is inconsistent and thus can be easily tested.

  ...
  ri_float operator <= (ri_float f) {
    _u = min(_u, f);
    return getWidth();
  }
   
  ri_float operator >= (ri_float f) {
    _l = max(_l, f);
    return getWidth();
  }
   
  ri_float lowerBound(void) { return _l; }
  ri_float upperBound(void) { return _u; }
  ...
}; // class RI
 

The functions lowerBound() and upperBound() provide access to the lower resp. upper bound of the constraint.


Tobias Müller
Version 1.4.0 (20080702)