Skip to content

Conversation

@Zeroto521
Copy link
Contributor

@Zeroto521 Zeroto521 commented Jan 22, 2026

_is_number(Expr) always return False. Because Expr doesn't have __float__ method and it isn't a number type.

In [1]: from pyscipopt import Model, Expr

In [2]: from pyscipopt.scip import CONST

In [3]: e = Expr({CONST: -1.0})

In [4]: float(e)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 float(e)

TypeError: float() argument must be a string or a real number, not 'pyscipopt.scip.Expr'

In [5]: float(e+1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 float(e+1)

TypeError: float() argument must be a string or a real number, not 'pyscipopt.scip.Expr'

Copilot AI review requested due to automatic review settings January 22, 2026 06:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR removes dead code from the Expr class by eliminating checks for _is_number(self) which always return False since Expr instances cannot be converted to float.

Changes:

  • Removed unreachable code branches in __add__, __mul__, and __rtruediv__ methods that checked if self is a number
  • Simplified __rtruediv__ implementation by removing the always-false conditional check

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Joao-Dionisio Joao-Dionisio marked this pull request as draft January 22, 2026 10:08
@Zeroto521
Copy link
Contributor Author

This pr is ready.
CI fails due to performance jitter. Especially, the traceline mark is set to True.

=========================== short test summary info ============================
FAILED tests/test_matrix_variable.py::test_matrix_dot_performance[50] - assert False
 +  where False = isGT(2.9845094680786133, 3.222688674926758)
 +    where isGT = <pyscipopt.scip.Model object at 0x7f039845b440>.isGT
FAILED tests/test_matrix_variable.py::test_matrix_dot_performance[100] - assert False
 +  where False = isGT(25.479017972946167, 25.84245491027832)
 +    where isGT = <pyscipopt.scip.Model object at 0x7f0364f4b5c0>.isGT
= 2 failed, 408 passed, 104 skipped, 11 xfailed, 4 warnings in 157.89s (0:02:37) =
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/site-packages/coverage/control.py:958: CoverageWarning: No data was collected. (no-data-collected); see https://coverage.readthedocs.io/en/7.13.1/messages.html#warning-no-data-collected
  self._warn("No data was collected.", slug="no-data-collected")

@Joao-Dionisio
Copy link
Member

isGT(2.9845094680786133, 3.222688674926758) the difference here seems quite significant, no?

@Joao-Dionisio Joao-Dionisio marked this pull request as ready for review January 22, 2026 16:04
@Joao-Dionisio
Copy link
Member

Same failures. Can you please try with and without your changes locally and report back, please?

Replaces manual timing with the timeit module for more accurate performance measurement in matrix operation tests. Updates assertions to require the optimized implementation to be at least 25% faster, and reduces test parameterization to n=100 for consistency.
@Zeroto521 Zeroto521 force-pushed the dep/_is_number(self) branch from 5d66cba to 1d0e6f5 Compare January 23, 2026 02:17
Replaces random matrix generation with a stacked matrix of zeros and ones in test_matrix_dot_performance to provide more controlled test data.
@Zeroto521
Copy link
Contributor Author

Zeroto521 commented Jan 23, 2026

GitHub and local test as below for 532dee4
pytest is the core problem that causes CI to fail. And trace and pytest-xdist also slow it down.

from time import time

import numpy as np

from pyscipopt import Model

n = 50

model = Model()
x = model.addMatrixVar((n, n))
a = np.random.rand(n, n)
env TRACE test method n a @ x.view(np.ndarray) a @ x
github 1 pytest -n auto tests/test_matrix_variable.py::test_matrix_dot_performance 50 2.9845s 3.2226s
github 1 pytest -n auto tests/test_matrix_variable.py::test_matrix_dot_performance 100 25.4790s 25.8424s
local 0 python test.py 50 0.0898s 0.0752s
local 0 python test.py 100 1.3043s 0.9023s
local 0 pytest tests/test_matrix_variable.py::test_matrix_dot_performance -s 50 0.0936s 0.0984s
local 0 pytest tests/test_matrix_variable.py::test_matrix_dot_performance -s 100 0.9914s 0.7366s
local 1 python test.py 50 0.0957s 0.0762s
local 1 python test.py 100 1.5692s 1.0288s
local 1 pytest tests/test_matrix_variable.py::test_matrix_dot_performance -s 50 0.0911s 0.0837s
local 1 pytest tests/test_matrix_variable.py::test_matrix_dot_performance -s 100 1.0898s 0.9659s
conda env
# packages in environment at D:\Users\Zero\AppData\Local\miniforge3\envs\cy310:
#
# Name                            Version             Build                  Channel
bzip2                             1.0.8               h0ad9c76_8             conda-forge
ca-certificates                   2025.11.12          h4c7d964_0             conda-forge
certifi                           2025.11.12          pypi_0                 pypi
charset-normalizer                3.4.4               pypi_0                 pypi
colorama                          0.4.6               pyhd8ed1ab_1           conda-forge
cython                            3.2.3               py310h23e71ea_0        conda-forge
exceptiongroup                    1.3.1               pyhd8ed1ab_0           conda-forge
execnet                           2.1.2               pyhd8ed1ab_0           conda-forge
idna                              3.11                pypi_0                 pypi
iniconfig                         2.3.0               pyhd8ed1ab_0           conda-forge
libblas                           3.9.0               35_h5709861_mkl        conda-forge
libcblas                          3.9.0               35_h2a3cdd5_mkl        conda-forge
libexpat                          2.7.3               hac47afa_0             conda-forge
libffi                            3.5.2               h52bdfb6_0             conda-forge
libhwloc                          2.11.2              default_hc8275d1_1000  conda-forge
libiconv                          1.18                hc1393d2_2             conda-forge
liblapack                         3.9.0               35_hf9ab0e9_mkl        conda-forge
liblzma                           5.8.1               h2466b09_2             conda-forge
libpython                         0.2                 pypi_0                 pypi
libpython-static                  3.10.19             hac47afa_2_cpython     conda-forge
libsqlite                         3.51.1              hf5d6505_1             conda-forge
libxml2                           2.13.9              h741aa76_0             conda-forge
libzlib                           1.3.1               h2466b09_2             conda-forge
llvm-openmp                       21.1.8              h4fa8253_0             conda-forge
m2w64-binutils                    2.25.1              5                      conda-forge
m2w64-bzip2                       1.0.6               6                      conda-forge
m2w64-crt-git                     5.0.0.4636.2595836  2                      conda-forge
m2w64-gcc                         5.3.0               6                      conda-forge
m2w64-gcc-ada                     5.3.0               6                      conda-forge
m2w64-gcc-fortran                 5.3.0               6                      conda-forge
m2w64-gcc-libgfortran             5.3.0               6                      conda-forge
m2w64-gcc-libs                    5.3.0               7                      conda-forge
m2w64-gcc-libs-core               5.3.0               7                      conda-forge
m2w64-gcc-objc                    5.3.0               6                      conda-forge
m2w64-gmp                         6.1.0               2                      conda-forge
m2w64-headers-git                 5.0.0.4636.c0ad18a  2                      conda-forge
m2w64-isl                         0.16.1              2                      conda-forge
m2w64-libiconv                    1.14                6                      conda-forge
m2w64-libmangle-git               5.0.0.4509.2e5a9a2  2                      conda-forge
m2w64-libwinpthread-git           5.0.0.4634.697f757  2                      conda-forge
m2w64-make                        4.1.2351.a80a8b8    2                      conda-forge
m2w64-mpc                         1.0.3               3                      conda-forge
m2w64-mpfr                        3.1.4               4                      conda-forge
m2w64-pkg-config                  0.29.1              2                      conda-forge
m2w64-toolchain                   5.3.0               7                      conda-forge
m2w64-tools-git                   5.0.0.4592.90b8472  2                      conda-forge
m2w64-windows-default-manifest    6.4                 3                      conda-forge
m2w64-winpthreads-git             5.0.0.4634.697f757  2                      conda-forge
m2w64-zlib                        1.2.8               10                     conda-forge
mkl                               2024.2.2            h57928b3_16            conda-forge
msys2-conda-epoch                 20160418            1                      conda-forge
numpy                             2.2.6               py310h4987827_0        conda-forge
openssl                           3.6.0               h725018a_0             conda-forge
packaging                         25.0                pyh29332c3_1           conda-forge
pip                               25.3                pyh8b19718_0           conda-forge
pluggy                            1.6.0               pyhf9edf01_1           conda-forge
pthreads-win32                    2.9.1               h2466b09_4             conda-forge
pygments                          2.19.2              pyhd8ed1ab_0           conda-forge
pytest                            9.0.2               pyhcf101f3_0           conda-forge
pytest-xdist                      3.8.0               pyhd8ed1ab_0           conda-forge
python                            3.10.19             hc20f281_2_cpython     conda-forge
python_abi                        3.10                8_cp310                conda-forge
requests                          2.32.5              pypi_0                 pypi
setuptools                        80.9.0              pyhff2d567_0           conda-forge
tbb                               2021.13.0           h62715c5_1             conda-forge
tk                                8.6.13              h2c6b04d_3             conda-forge
tomli                             2.3.0               pyhcf101f3_0           conda-forge
typing_extensions                 4.15.0              pyhcf101f3_0           conda-forge
tzdata                            2025c               h8577fbf_0             conda-forge
ucrt                              10.0.26100.0        h57928b3_0             conda-forge
urllib3                           2.6.2               pypi_0                 pypi
vc                                14.3                h2b53caa_33            conda-forge
vc14_runtime                      14.44.35208         h818238b_33            conda-forge
vcomp14                           14.44.35208         h818238b_33            conda-forge
wheel                             0.45.1              pyhd8ed1ab_1           conda-forge

assert np_res.shape == scip_res.shape


@pytest.mark.parametrize("n", [50, 100])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

A small data size will fail sometimes

start = time()
a @ x.view(np.ndarray)
orig = time() - start
a = np.vstack((np.zeros((n // 2, n)), np.ones((n // 2, n))))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use a fixed constant matrix (a half-zeroes and a half-ones) instead of a random matrix.

a @ x
matrix = time() - start
number = 5
matrix = timeit(lambda: a @ x, number=number) / number
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use timeit avoid pytest using cache

Copy link
Contributor Author

@Zeroto521 Zeroto521 Jan 23, 2026

Choose a reason for hiding this comment

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

But I have to say, performance test cases sometimes can't pass.
All of this (use timeit, isGE, and *1.25) is decreasing the possibility.
I tested 20 times for pytest -n auto tests/test_matrix_variable.py, and 1 time failed.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, there is some performance variability, but the goal of using matrices and a significant portion of your PRs is to increase performance over not using them. Agreed that it makes sense to reduce randomness in the performance tests.

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.

2 participants