`Square(x)` with a zero straddling range bypasses the `divide` zero denominator guard

Open
#554 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
68/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
cpp, python
Domain
backend

Research direction

Start at the Square range calculation and the divide denominator safety check, then trace the model-building path used by the Python example. Add a regression test for an integer range crossing zero and verify that dividing by Square(x) raises ValueError at model-build time rather than producing inf at runtime.

Written by the indexing model from the issue text.

Description

bug
Summary

When a decision variable x has a range that crosses zero (e.g. lower_bound=-3, upper_bound=2),
Square(x) incorrectly reports that its minimum value is positive.
This fools the divide operator's safety check into accepting it as a denominator,
even though Square(x) can actually be zero (when x = 0).
The model builds without error, but at runtime the division silently returns inf.


Expected behaviour
x = model.integer(lower_bound=-3, upper_bound=2)  # range includes 0
model.constant(10) / Square(x)
# Should raise ValueError — Square(x) can be 0

divide documents that it raises ValueError if the denominator can ever be zero.
Since x can be 0, Square(x) can be 0, so a ValueError should be raised at model-build time.


Actual behaviour

No error is raised at model-build time. When x = 0 during solving, the result is inf with no warning.

from dwave.optimization.model import Model
from dwave.optimization.symbols import Square

model = Model()
x = model.integer(lower_bound=-3, upper_bound=2)
sq = Square(x)
ratio = model.constant(10) / sq  # ← no error raised (should raise)

with model.lock():
    model.states.resize(1)
    x.set_state(0, 0)
    print(ratio.state(0))  # prints: [inf]  ← silent wrong result

Workaround

Avoid using Square(x) as a divisor when x can be zero.
Either constrain the variable to be strictly positive/negative before squaring,
or use safe_divide if zero-denominator should map to zero rather than inf.

# Option 1: restrict x away from zero first
x = model.integer(lower_bound=1, upper_bound=5)   # strictly positive
model.constant(10) / Square(x)                    # safe

# Option 2: use safe_divide (returns 0 on division by zero)
from dwave.optimization.mathematical import safe_divide
safe_divide(model.constant(10), Square(x))
Dominant language
C++
Stars
31
Forks
36
Avg merge
1d 9h
Merged PRs (30d)
4

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from dwavesystems/dwave-optimization

All issues in dwavesystems/dwave-optimization

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.