Skip to content

Commit 573a829

Browse files
Merge branch 'master' into SCIPvarMarkRelaxationOnly
2 parents bbd7e5d + 3544861 commit 573a829

6 files changed

Lines changed: 53 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
### Fixed
1212
- Raised an error when an expression is used when a variable is required
1313
### Changed
14+
- MatrixExpr.sum() now supports axis arguments and can return either a scalar or MatrixExpr depending on the result dimensions
1415
### Removed
1516

1617
## 5.5.0 - 2025.05.06

INSTALL.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ If installing SCIP from source or using PyPI with a python and operating system
2626
you need to specify the install location using the environment variable
2727
`SCIPOPTDIR`:
2828

29-
- on Linux and OS X:\
29+
- on Linux and MacOS:\
3030
`export SCIPOPTDIR=<path_to_install_dir>`
3131
- on Windows:\
3232
`set SCIPOPTDIR=<path_to_install_dir>` (**cmd**, **Cmder**, **WSL**)\
@@ -45,8 +45,9 @@ contains the corresponding header files:
4545
> nlpi
4646
> ...
4747

48-
Please note that some Mac configurations require adding the library installation path to `DYLD_LIBRARY_PATH` when using a locally installed version of SCIP.
48+
On MacOS, to ensure that the SCIP dynamic library can be located at runtime by PySCIPOpt, you should add your SCIP installation path to the ``DYLD_LIBRARY_PATH`` environment variable by running:
4949

50+
`export DYLD_LIBRARY_PATH="<path_to_install_dir>/lib:$DYLD_LIBRARY_PATH"`
5051

5152
When building SCIP from source using Windows it is highly recommended to use the [Anaconda Python
5253
Platform](https://www.anaconda.com/).
@@ -75,7 +76,7 @@ at runtime by adjusting your `PATH` environment variable:
7576

7677
- on Windows: `set PATH=%PATH%;%SCIPOPTDIR%\bin`
7778

78-
On Linux and OS X this is encoded in the generated PySCIPOpt library and
79+
On Linux and MacOS this is encoded in the generated PySCIPOpt library and
7980
therefore not necessary.
8081

8182
Building everything from source

docs/build.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ For Linux and MacOS systems set the variable with the following command:
100100
101101
export SCIPOPTDIR=<path_to_install_dir>
102102
103+
.. note::
104+
105+
For macOS users, to ensure that the SCIP dynamic library can be found at runtime by PySCIPOpt,
106+
you should add your SCIP installation path to the ``DYLD_LIBRARY_PATH`` environment variable by running:
107+
108+
.. code-block::
109+
110+
export DYLD_LIBRARY_PATH="<path_to_install_dir>/lib:$DYLD_LIBRARY_PATH"
111+
103112
For Windows use the following command:
104113

105114
.. code-block:: bash

src/pyscipopt/lp.pxi

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ cdef class LP:
5858
"""Adds a single column to the LP.
5959
6060
Keyword arguments:
61-
entries -- list of tuples, each tuple consists of a row index and a coefficient
61+
entries -- a list of tuples; if p is the index of the new column, then each tuple (i, k) indicates that
62+
A[i][p] = k, where A is the constraint matrix and k is a nonzero entry.
6263
obj -- objective coefficient (default 0.0)
6364
lb -- lower bound (default 0.0)
6465
ub -- upper bound (default infinity)
@@ -85,7 +86,8 @@ cdef class LP:
8586
"""Adds multiple columns to the LP.
8687
8788
Keyword arguments:
88-
entrieslist -- list containing lists of tuples, each tuple contains a coefficient and a row index
89+
entrieslist -- a list of lists, where the j-th inner list contains tuples (i, k) such that A[i][p] = k,
90+
where A is the constraint matrix, p is the index of the j-th new column, and k is a nonzero entry.
8991
objs -- objective coefficient (default 0.0)
9092
lbs -- lower bounds (default 0.0)
9193
ubs -- upper bounds (default infinity)
@@ -147,7 +149,8 @@ cdef class LP:
147149
"""Adds a single row to the LP.
148150
149151
Keyword arguments:
150-
entries -- list of tuples, each tuple contains a coefficient and a column index
152+
entries -- a list of tuples; if q is the index of the new row, then each tuple (j, k) indicates that
153+
A[q][j] = k, where A is the constraint matrix and k is a nonzero entry.
151154
lhs -- left-hand side of the row (default 0.0)
152155
rhs -- right-hand side of the row (default infinity)
153156
"""
@@ -172,7 +175,8 @@ cdef class LP:
172175
"""Adds multiple rows to the LP.
173176
174177
Keyword arguments:
175-
entrieslist -- list containing lists of tuples, each tuple contains a coefficient and a column index
178+
entrieslist -- a list of lists, where the i-th inner list contains tuples (j, k) such that A[q][j] = k,
179+
where A is the constraint matrix, q is the index of the i-th new row, and k is a nonzero entry.
176180
lhss -- left-hand side of the row (default 0.0)
177181
rhss -- right-hand side of the row (default infinity)
178182
"""

src/pyscipopt/matrix.pxi

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@ def _is_number(e):
1717

1818
class MatrixExpr(np.ndarray):
1919
def sum(self, **kwargs):
20-
return super().sum(**kwargs).item()
21-
20+
"""
21+
Based on `numpy.ndarray.sum`, but returns a scalar if the result is a single value.
22+
This is useful for matrix expressions where the sum might reduce to a single value.
23+
"""
24+
res = super().sum(**kwargs)
25+
return res if res.size > 1 else res.item()
26+
2227
def __le__(self, other: Union[float, int, Variable, np.ndarray, 'MatrixExpr']) -> np.ndarray:
2328

2429
expr_cons_matrix = np.empty(self.shape, dtype=object)

tests/test_matrix_variable.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,30 @@ def test_expr_from_matrix_vars():
164164
for term, coeff in expr_list:
165165
assert len(term) == 3
166166

167+
def test_matrix_sum_argument():
168+
m = Model()
169+
170+
# compare the result of summing 2d array to a scalar with a scalar
171+
x = m.addMatrixVar((2, 3), "x", "I", ub=4)
172+
m.addCons(x.sum() == 24)
173+
174+
# compare the result of summing 2d array to 1d array
175+
y = m.addMatrixVar((2, 4), "y", "I", ub=4)
176+
m.addMatrixCons(x.sum(axis=1) == y.sum(axis=1))
177+
178+
# compare the result of summing 3d array to a 2d array with a 2d array
179+
z = m.addMatrixVar((2, 3, 4), "z", "I", ub=4)
180+
m.addMatrixCons(z.sum(axis=2) == x)
181+
m.addMatrixCons(z.sum(axis=1) == y)
182+
183+
# to fix the element values
184+
m.addMatrixCons(z == np.ones((2, 3, 4)))
185+
186+
m.setObjective(x.sum() + y.sum() + z.sum(), "maximize")
187+
m.optimize()
188+
189+
assert (m.getVal(x) == np.full((2, 3), 4)).all().all()
190+
assert (m.getVal(y) == np.full((2, 4), 3)).all().all()
167191

168192
def test_add_cons_matrixVar():
169193
m = Model()

0 commit comments

Comments
 (0)