Skip to content

Save end_is_none flag in Cumulative and NoOverlap#830

Merged
tias merged 21 commits intomasterfrom
cumulative_subexpr
Apr 27, 2026
Merged

Save end_is_none flag in Cumulative and NoOverlap#830
tias merged 21 commits intomasterfrom
cumulative_subexpr

Conversation

@IgnaceBleukx
Copy link
Copy Markdown
Collaborator

Fixes #828; not sure if this is the best way to do it, but seems like the most obvious for now.

@IgnaceBleukx IgnaceBleukx marked this pull request as ready for review January 21, 2026 02:10
@IgnaceBleukx IgnaceBleukx requested a review from ThomSerg January 26, 2026 08:24
@tias tias marked this pull request as draft February 4, 2026 21:05
@tias
Copy link
Copy Markdown
Collaborator

tias commented Feb 4, 2026

It doesn't feel the right way, but haven't further looked into it.

@IgnaceBleukx
Copy link
Copy Markdown
Collaborator Author

Now that I think about it, probably the right way of doing this, is to let the expressions decide which arguments should recusively be transformed.
E.g., each expression would get a get_expr_args and update_expr_args function, which returns the arguments that could be an expression. This will have a few advantages: for e.g., Table, we won't ever recurse into the table, even if the array contains subexpression (and thus has_subexpr will be True).
For Cumulative, we could just return [start,dur,height,capacity] if the end variable is None.

@tias
Copy link
Copy Markdown
Collaborator

tias commented Feb 22, 2026

Since doing the type hinting, I'm starting to be convinced that the Expression object should be a simple container and args can contain anything... so then also the transformation functions should be able to either copy or skip things that are not subexpressions...

You now do this for 'None'... it adds an additional test to the already often called/slowing down is flat var; I've pushed it up one level.

I'm OK with this fix.

But more generally, in DirectConstraint I added something like that, a 'self.novar' which is a list of indices at which there are guaranteed not to be any subexpressions/variables. This could be extended to all expressions... then expression (including DirectConstraint) can indeed have Expression.args be a Tuple[Any, ...]?

@tias
Copy link
Copy Markdown
Collaborator

tias commented Mar 19, 2026

so no, after more playing with Typing, the realisation is now:

  • Expression subclasses are perfectly OK to store their own non-expression data in their subclass; no need to feed data to the superclass args
  • so, Cumulative (and nooverlap), should store a end_is_none flag in their subclass instead of passing a 'None' to superclass args, and the code should be updated to check that...

then transformations remain untouched as intended, and you don need novar things.

@IgnaceBleukx
Copy link
Copy Markdown
Collaborator Author

IgnaceBleukx commented Mar 23, 2026

Updated this PR to indeed have a end_is_none flag saved on the expression object. Whenever end is None, it's simply not passed to the superclass.

Keeping it as draft for now, as there will some merge issues with #676, so leaving it unmerged until that one is in master.

TODO:

@IgnaceBleukx IgnaceBleukx changed the title Update transformations to check for None value Save end_is_none flag in Cumulative and NoOverlap Mar 23, 2026
@IgnaceBleukx IgnaceBleukx marked this pull request as ready for review April 24, 2026 13:10
Copy link
Copy Markdown
Collaborator

@tias tias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great, and we should do that indeed.

I just had one simplication realisation: we don't need the flag, we can just check len(args)... this would be simpler/cleaner I think...

Would you be OK changing it to that, or do you prefer it this way?

(also smth ortools specific)

Comment thread cpmpy/expressions/globalconstraints.py Outdated
Comment thread cpmpy/expressions/globalconstraints.py Outdated
Comment thread cpmpy/solvers/choco.py Outdated
Comment thread cpmpy/solvers/ortools.py Outdated
assert isinstance(cpm_expr, Cumulative) # ensure hasattr end_is_none
if cpm_expr.end_is_none:
start, dur, demand, cap = cpm_expr.args
end = [intvar(*get_bounds(s+d)) for s,d in zip(start, dur)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ortools also has an new_fixed_size_interval_var()

I'm a bit confused, I can't find the docs I'm used to... the docs I do find are all messy, and they use underscore based names; while we use CamelBack names? e.g. NewIntervalVar() vs new_interval_var()?
https://or-tools.github.io/docs/pdoc/ortools/sat/python/cp_model.html

so, my original point is: this should just be about first creating the right kind of interval var, then posting the constraint. In case end_is_none and demand is constant, the better thing to do is to create a new_fixed_size_interval_var() rather then a new_interval_var()

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, OR-Tools refactored their API to snake_case, acually not sure how long the camelCase is still supported. We should find out which version introduced the snake case, update our API and bump the min requirements. I think I read somewhere there should be a sed file to automatically replace all occurences.

For the issue here: I'll use the fixed intervals indeed if duration is constant.

@IgnaceBleukx IgnaceBleukx requested a review from tias April 27, 2026 11:27
@tias tias merged commit ff4433b into master Apr 27, 2026
11 checks passed
@tias tias deleted the cumulative_subexpr branch April 27, 2026 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

None argument in Cumulative (demand) not allowed by safening

2 participants