#### 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 l, ri_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.