Skip to content

Commit a4a5f70

Browse files
Merge branch 'master' into 243-fix-write-methods-dont-work-after-redirectoutput
2 parents ec5a346 + cfbd832 commit a4a5f70

File tree

5 files changed

+129
-41
lines changed

5 files changed

+129
-41
lines changed

.github/workflows/integration-test.yml

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: Integration test
22

33
env:
4-
version: 9.1.0
4+
version: 9.2.0
55

66
# runs on branches and pull requests; doesn't run on tags.
77
on:
@@ -57,7 +57,7 @@ jobs:
5757

5858
- name: Download dependencies (SCIPOptSuite)
5959
shell: powershell
60-
run: wget https://github.com/scipopt/scip/releases/download/$(echo "v${{env.version}}" | tr -d '.')/SCIPOptSuite-${{ env.version }}-win64-VS15.exe -outfile scipopt-installer.exe
60+
run: wget https://github.com/scipopt/scip/releases/download/$(echo "v${{env.version}}" | tr -d '.')/SCIPOptSuite-${{ env.version }}-win64.exe -outfile scipopt-installer.exe
6161

6262
- name: Install dependencies (SCIPOptSuite)
6363
shell: cmd
@@ -93,33 +93,13 @@ jobs:
9393
steps:
9494
- uses: actions/checkout@v3
9595

96-
- name: Cache dependencies (SCIPOptSuite)
97-
id: cache-scip
98-
uses: actions/cache@v2
99-
with:
100-
path: |
101-
${{ runner.workspace }}/scipoptsuite
102-
~/Library/Caches/Homebrew/tbb--*
103-
/usr/local/opt/tbb*
104-
~/Library/Caches/Homebrew/downloads/*--tbb-*
105-
~/Library/Caches/Homebrew/boost--*
106-
/usr/local/opt/boost*
107-
~/Library/Caches/Homebrew/downloads/*--boost-*
108-
key: ${{ runner.os }}-scipopt-${{ env.version }}-${{ hashFiles('**/lockfiles') }}
109-
restore-keys: |
110-
${{ runner.os }}-scipopt-${{ env.version }}-
111-
11296
- name: Install dependencies (SCIPOptSuite)
113-
if: steps.cache-scip.outputs.cache-hit != 'true'
11497
run: |
11598
brew install tbb boost bison
116-
wget --quiet --no-check-certificate https://github.com/scipopt/scip/releases/download/$(echo "v${{env.version}}" | tr -d '.')/scipoptsuite-${{ env.version }}.tgz
117-
tar xfz scipoptsuite-${{ env.version }}.tgz
118-
cd scipoptsuite-${{ env.version }}
119-
mkdir build
120-
cd build
121-
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${{ runner.workspace }}/scipoptsuite -DIPOPT=off -DSYM=none -DTPI=tny -DREADLINE=off
122-
make install -j
99+
wget --quiet --no-check-certificate https://github.com/scipopt/scip/releases/download/$(echo "v${{env.version}}" | tr -d '.')/SCIPOptSuite-${{ env.version }}-Darwin.sh
100+
chmod +x SCIPOptSuite-${{ env.version }}-Darwin.sh
101+
./SCIPOptSuite-${{ env.version }}-Darwin.sh --skip-license --include-subdir
102+
mv SCIPOptSuite-${{ env.version }}-Darwin ${{ runner.workspace }}/scipoptsuite
123103
124104
- name: Setup python ${{ matrix.python-version }}
125105
uses: actions/setup-python@v4

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
## Unreleased
44
### Added
5+
- Added categorical data example
6+
- Added printProblem to print problem to stdout
57
- Added stage checks to presolve, freereoptsolve, freetransform
68
- Added primal_dual_evolution recipe and a plot recipe
79
### Fixed
810
- Only redirect stdout and stderr in redirectOutput() so that file output still works afterwards
911
### Changed
12+
- GitHub actions using Mac now use precompiled SCIP from latest release
1013
### Removed
1114

1215
## 5.2.1 - 2024.10.29
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
This example shows how one can optimize a model with categorical data by converting it into integers.
3+
4+
There are three employees (Alice, Bob, Charlie) and three shifts. Each shift is assigned an integer:
5+
6+
Morning - 0
7+
Afternoon - 1
8+
Night - 2
9+
10+
The employees have availabilities (e.g. Alice can only work in the Morning and Afternoon), and different
11+
salary demands. These constraints, and an additional one stipulating that every shift must be covered,
12+
allows us to model a MIP with the objective of minimizing the money spent on salary.
13+
"""
14+
15+
from pyscipopt import Model
16+
17+
# Define categorical data
18+
shift_to_int = {"Morning": 0, "Afternoon": 1, "Night": 2}
19+
employees = ["Alice", "Bob", "Charlie"]
20+
21+
# Employee availability
22+
availability = {
23+
"Alice": ["Morning", "Afternoon"],
24+
"Bob": ["Afternoon", "Night"],
25+
"Charlie": ["Morning", "Night"]
26+
}
27+
28+
# Transform availability into integer values
29+
availability_int = {}
30+
for emp, available_shifts in availability.items():
31+
availability_int[emp] = [shift_to_int[shift] for shift in available_shifts]
32+
33+
34+
# Employees have different salary demands
35+
cost = {
36+
"Alice": [2,4,1],
37+
"Bob": [3,2,7],
38+
"Charlie": [3,3,3]
39+
}
40+
41+
# Create the model
42+
model = Model("Shift Assignment")
43+
44+
# x[e, s] = 1 if employee e is assigned to shift s
45+
x = {}
46+
for e in employees:
47+
for s in shift_to_int.values():
48+
x[e, s] = model.addVar(vtype="B", name=f"x({e},{s})")
49+
50+
# Each shift must be assigned to exactly one employee
51+
for s in shift_to_int.values():
52+
model.addCons(sum(x[e, s] for e in employees) == 1)
53+
54+
# Employees can only work shifts they are available for
55+
for e in employees:
56+
for s in shift_to_int.values():
57+
if s not in availability_int[e]:
58+
model.addCons(x[e, s] == 0)
59+
60+
# Minimize shift assignment cost
61+
model.setObjective(
62+
sum(cost[e][s]*x[e, s] for e in employees for s in shift_to_int.values()), "minimize"
63+
)
64+
65+
# Solve the problem
66+
model.optimize()
67+
68+
# Display the results
69+
print("\nOptimal Shift Assignment:")
70+
for e in employees:
71+
for s, s_id in shift_to_int.items():
72+
if model.getVal(x[e, s_id]) > 0.5:
73+
print("%s is assigned to %s" % (e, s))

src/pyscipopt/scip.pxi

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2901,6 +2901,32 @@ cdef class Model:
29012901
if not onlyroot:
29022902
self.setIntParam("propagating/maxrounds", 0)
29032903

2904+
def printProblem(self, ext='.cip', trans=False, genericnames=False):
2905+
"""
2906+
Write current model/problem to standard output.
2907+
2908+
Parameters
2909+
----------
2910+
ext : str, optional
2911+
the extension to be used (Default value = '.cip').
2912+
Should have an extension corresponding to one of the readable file formats,
2913+
described in https://www.scipopt.org/doc/html/group__FILEREADERS.php.
2914+
trans : bool, optional
2915+
indicates whether the transformed problem is written to file (Default value = False)
2916+
genericnames : bool, optional
2917+
indicates whether the problem should be written with generic variable
2918+
and constraint names (Default value = False)
2919+
"""
2920+
user_locale = locale.getlocale(category=locale.LC_NUMERIC)
2921+
locale.setlocale(locale.LC_NUMERIC, "C")
2922+
2923+
if trans:
2924+
PY_SCIP_CALL(SCIPwriteTransProblem(self._scip, NULL, str_conversion(ext)[1:], genericnames))
2925+
else:
2926+
PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, NULL, str_conversion(ext)[1:], genericnames))
2927+
2928+
locale.setlocale(locale.LC_NUMERIC,user_locale)
2929+
29042930
def writeProblem(self, filename='model.cip', trans=False, genericnames=False, verbose=True):
29052931
"""
29062932
Write current model/problem to a file.
@@ -2923,22 +2949,27 @@ cdef class Model:
29232949
user_locale = locale.getlocale(category=locale.LC_NUMERIC)
29242950
locale.setlocale(locale.LC_NUMERIC, "C")
29252951

2926-
str_absfile = abspath(filename)
2927-
absfile = str_conversion(str_absfile)
2928-
fn, ext = splitext(absfile)
2929-
2930-
if len(ext) == 0:
2931-
ext = str_conversion('.cip')
2932-
fn = fn + ext
2933-
ext = ext[1:]
2934-
2935-
if trans:
2936-
PY_SCIP_CALL(SCIPwriteTransProblem(self._scip, fn, ext, genericnames))
2952+
if filename:
2953+
str_absfile = abspath(filename)
2954+
absfile = str_conversion(str_absfile)
2955+
fn, ext = splitext(absfile)
2956+
if len(ext) == 0:
2957+
ext = str_conversion('.cip')
2958+
fn = fn + ext
2959+
ext = ext[1:]
2960+
2961+
if trans:
2962+
PY_SCIP_CALL(SCIPwriteTransProblem(self._scip, fn, ext, genericnames))
2963+
else:
2964+
PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, fn, ext, genericnames))
2965+
2966+
if verbose:
2967+
print('wrote problem to file ' + str_absfile)
29372968
else:
2938-
PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, fn, ext, genericnames))
2939-
2940-
if verbose:
2941-
print('wrote problem to file ' + str_absfile)
2969+
if trans:
2970+
PY_SCIP_CALL(SCIPwriteTransProblem(self._scip, NULL, str_conversion('.cip')[1:], genericnames))
2971+
else:
2972+
PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, NULL, str_conversion('.cip')[1:], genericnames))
29422973

29432974
locale.setlocale(locale.LC_NUMERIC,user_locale)
29442975

tests/test_model.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def test_model():
6868

6969
s.writeProblem('model')
7070
s.writeProblem('model.lp')
71+
s.printProblem()
7172

7273
s.freeProb()
7374
s = Model()

0 commit comments

Comments
 (0)