Skip to content

BUG: _VarArray can't handle MatrixVar #1044

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 26 commits into from
Aug 19, 2025
Merged

Conversation

Zeroto521
Copy link
Contributor

fix #1043

Zeroto521 added 10 commits July 31, 2025 17:00
Simplifies and clarifies the logic for initializing _VarArray by restructuring type checks and error handling. Now uses f-strings for error messages and ensures consistent handling of empty lists and invalid types.
Updated the _VarArray class constructor to handle MatrixVariable inputs in addition to Variable, list, and tuple. Refactored pointer allocation logic into a helper function for improved code clarity and maintainability.
Introduces a new test to verify that addConsIndicator works correctly when the binary variable is a matrix variable, addressing issue scipopt#1043.
To fix "Storing unsafe C derivative of temporary Python reference"
The create_ptr function in _VarArray.__cinit__ no longer takes a separate size argument and instead uses len(vars) directly. This simplifies the function signature and reduces redundancy.
Inlined the pointer creation logic in _VarArray's __cinit__ method, removing the inner create_ptr function. This simplifies the code and improves readability while maintaining the same functionality.
The test now checks addConsIndicator with both activeone=True and activeone=False, and updates the objective to use binvar.sum().
Copy link

codecov bot commented Aug 3, 2025

Codecov Report

❌ Patch coverage is 90.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 54.32%. Comparing base (6452ea6) to head (3b64e79).
⚠️ Report is 20 commits behind head on master.

Files with missing lines Patch % Lines
src/pyscipopt/scip.pxi 90.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1044      +/-   ##
==========================================
+ Coverage   54.13%   54.32%   +0.19%     
==========================================
  Files          22       23       +1     
  Lines        5045     5257     +212     
==========================================
+ Hits         2731     2856     +125     
- Misses       2314     2401      +87     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Joao-Dionisio
Copy link
Member

Sorry, what's the status of this?

@DominikKamp
Copy link
Contributor

DominikKamp commented Aug 16, 2025

Waiting for your opinion on #1044 (comment) whether a matrix is a list and an explanation on which feature this aims at. Currently, I do not see a method which intends to apply _VarArray on a matrix variable. So there is no bug yet because _VarArray is only an internal class.

Comment on lines 2509 to 2514
self.size = len(vars)
self.ptr = <SCIP_VAR**> malloc(self.size * sizeof(SCIP_VAR*)) if self.size else NULL
for i, var in enumerate(vars):
if not isinstance(var, Variable):
raise TypeError(f"Expected Variable, got {type(var)}.")
self.ptr[i] = (<Variable>var).scip_var
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
self.size = len(vars)
self.ptr = <SCIP_VAR**> malloc(self.size * sizeof(SCIP_VAR*)) if self.size else NULL
for i, var in enumerate(vars):
if not isinstance(var, Variable):
raise TypeError(f"Expected Variable, got {type(var)}.")
self.ptr[i] = (<Variable>var).scip_var
if vars:
self.size = len(vars)
self.ptr = <SCIP_VAR**> malloc(self.size * sizeof(SCIP_VAR*))
for i, var in enumerate(vars):
if not isinstance(var, Variable):
raise TypeError(f"Expected Variable, got {type(var)}.")
self.ptr[i] = (<Variable>var).scip_var

Together with https://github.com/scipopt/PySCIPOpt/pull/1044/files#r2281629510.

Copy link
Contributor Author

@Zeroto521 Zeroto521 Aug 20, 2025

Choose a reason for hiding this comment

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

I forgot that this line has a problem. @DominikKamp
numpy.ndarray will raise an error if the size is larger than 2.

        if vars:

In my local model, it raised an error with the head of the commit building package.

from pyscipopt import Model

model = Model()
vars = model.addMatrixVar(3, vtype="B")
model.addConsKnapsack(vars, [1, 2, 3], 5)
model.setObjective(vars.sum(), "maximize")
model.optimize()
# Traceback (most recent call last):
#   line 5, in <module>
#     model.addConsKnapsack(vars, [1, 2, 3], 5)
#   File "src/pyscipopt/scip.pxi", line 6463, in pyscipopt. scip.Model.addConsKnapsack
#   File "src/pyscipopt/scip.pxi", line 2512, in pyscipopt.scip._VarArray.__cinit__
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

It should be kept original, in my mind. Since self.size and self.ptr are both initiated at the top.

        self.size = len(vars)
        self.ptr = <SCIP_VAR**> malloc(self.size * sizeof(SCIP_VAR*)) if self.size else NULL
        for i, var in enumerate(vars):
            if not isinstance(var, Variable):
                raise TypeError(f"Expected Variable, got {type(var)}.")
            self.ptr[i] = (<Variable>var).scip_var

Copy link
Contributor

Choose a reason for hiding this comment

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

So a matrix variable is an ndarray and not a list. I would suggest pulling the initialization of self.size by len(vars) down here and update the condition to self.size. We do not need to enumerate an empty something.

Copy link
Contributor

@DominikKamp DominikKamp left a comment

Choose a reason for hiding this comment

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

Otherwise, this is fine.

Ensures _VarArray initializes ptr and size to NULL and 0, respectively, before processing input. Prevents allocation and assignment errors when an empty or invalid input is provided.
Co-authored-by: DominikKamp <130753997+DominikKamp@users.noreply.github.com>
@Joao-Dionisio
Copy link
Member

@DominikKamp anything else or can I merge?

@DominikKamp
Copy link
Contributor

Merge as to be continued with logged change.

@Joao-Dionisio Joao-Dionisio merged commit c681f94 into scipopt:master Aug 19, 2025
1 check passed
@Joao-Dionisio
Copy link
Member

Thank you @Zeroto521 !

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BUG: _VarArray can't handle MatrixVar
3 participants