Gecode / gecode

Generic Constraint Development Environment
https://www.gecode.org
Other
275 stars 76 forks source link

Unexpected OutOfLimits exception. #175

Open handsomePirate opened 1 year ago

handsomePirate commented 1 year ago

Describe the bug

Gecode throws an OutOfLimits exception on line 132 in post.cpp due to overflow(t, n, c) evaluating to true.

To Reproduce

Define a space:

class SimpleSpace : public Gecode::Space
{
public:
    Gecode::FloatVarArray mFloatVariables;
        // The float channel variables are channeled to the int variables and used in float expressions.
    Gecode::FloatVarArray mIntVariableChannels;
        // Int variables serve as discrete option selectors.
    Gecode::IntVarArray mIntVariables;

public:
    SimpleSpace(
        const size_t floatVariableCount,
        const size_t intVariableCount) noexcept
        :
        mFloatVariables(*this, floatVariableCount, 0.f, 10000.f),
        mIntVariableChannels(*this, intVariableCount, 0.f, 10.f),
        mIntVariables(*this, intVariableCount, 0, 10)
    {}

    SimpleSpace(SimpleSpace &other)
        :
        Space(other)
    {
        mFloatVariables.update(*this, other.mFloatVariables);
        mIntVariableChannels.update(*this, other.mIntVariableChannels);
        mIntVariables.update(*this, other.mIntVariables);
    }

    // Inherited via Space
    virtual Space *copy(void) override
    {
        return new SimpleSpace(*this);
    }
};

Have the following code in main:

// Initialize the space with 2 float variables and 1 int variable.
SimpleSpace home(2, 1);

// Bind the int variable to the float channel variable.
// The int variable is used like a bool variable in this context, but can be used to express more options.
Gecode::channel(home, home.mIntVariables[0], home.mIntVariableChannels[0]);
Gecode::dom(home, home.mIntVariableChannels[0], 0.f, 1.f);
Gecode::dom(home, home.mIntVariables[0], 0, 1);

// Declare temporary float variables.
// The limits and potentially other relations for the float variables are given,
// but I want the option to switch their values and constraints.
Gecode::FloatVarArray floatVariables(home, 2, 0.f, 10000.f);
Gecode::dom(home, floatVariables[0], 2.f, 2.f);
Gecode::dom(home, floatVariables[1], 3.f, 4.f);

// Limit domain of actual variables.
Gecode::dom(home, home.mFloatVariables[0], 2.f, 4.f);
Gecode::dom(home, home.mFloatVariables[1], 2.f, 4.f);

// Flip accordingly.
// I'm using two multivariate quadratic expressions here to determine the value of the actual variables.
Gecode::FloatVar flip = home.mIntVariableChannels[0];
const auto flipExpr = flip * (floatVariables[1] - floatVariables[0]);
// This relation goes through correctly. If I make the domain of floatVariables[0] not tight in this case,
// it will also throw the exception.
Gecode::rel(home, home.mFloatVariables[0] == floatVariables[0] + flipExpr);
// This one errors out as described earlier.
Gecode::rel(home, home.mFloatVariables[1] == floatVariables[1] - flipExpr); // EXCEPTION

// Flip to be determined later...

All variables seem to be well-bounded and the expressions themselves should in this case also be bounded, yet in the above-mentioned overflow function determines t[2].x.domain() on line 67 in post.cpp to be 0-float::max.

Gecode and Platform Configuration

I'm using Gecode 6.2.0 locally built from code on Windows using MSVC v19.36.32535.0. My current code is being built and run with the same setup.

I made one change to the CMakeLists.txt and that was to add:

set(CMAKE_DEBUG_POSTFIX "d" CACHE PATH "")

after the line:

project(GECODE)

The behavior can be observed both in Debug and Release builds.