PySCIPOpt 5.2.1__tar.gz → 5.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/PKG-INFO +4 -2
  2. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/PySCIPOpt.egg-info/PKG-INFO +4 -2
  3. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/PySCIPOpt.egg-info/SOURCES.txt +4 -0
  4. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/pyproject.toml +4 -4
  5. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/setup.py +1 -1
  6. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/__init__.py +1 -0
  7. pyscipopt-5.3.0/src/pyscipopt/_version.py +1 -0
  8. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/benders.pxi +2 -2
  9. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/conshdlr.pxi +32 -16
  10. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/cutsel.pxi +3 -2
  11. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/lp.pxi +64 -42
  12. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/reader.pxi +4 -2
  13. pyscipopt-5.3.0/src/pyscipopt/recipes/primal_dual_evolution.py +46 -0
  14. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/scip.c +36089 -31207
  15. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/scip.pxd +34 -1
  16. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/scip.pxi +483 -187
  17. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_cons.py +15 -5
  18. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_copy.py +2 -0
  19. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_event.py +1 -4
  20. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_heur.py +7 -2
  21. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_memory.py +5 -2
  22. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_model.py +43 -2
  23. pyscipopt-5.3.0/tests/test_nogil.py +23 -0
  24. pyscipopt-5.3.0/tests/test_recipe_primal_dual_evolution.py +28 -0
  25. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_solution.py +27 -1
  26. pyscipopt-5.3.0/tests/test_sub_sol.py +58 -0
  27. pyscipopt-5.2.1/src/pyscipopt/_version.py +0 -1
  28. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/LICENSE +0 -0
  29. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/PySCIPOpt.egg-info/dependency_links.txt +0 -0
  30. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/PySCIPOpt.egg-info/top_level.txt +0 -0
  31. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/README.md +0 -0
  32. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/setup.cfg +0 -0
  33. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/Multidict.py +0 -0
  34. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/benderscut.pxi +0 -0
  35. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/branchrule.pxi +0 -0
  36. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/event.pxi +0 -0
  37. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/expr.pxi +0 -0
  38. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/heuristic.pxi +0 -0
  39. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/nodesel.pxi +0 -0
  40. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/presol.pxi +0 -0
  41. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/pricer.pxi +0 -0
  42. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/propagator.pxi +0 -0
  43. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/recipes/__init__.py +0 -0
  44. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/recipes/infeasibilities.py +0 -0
  45. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/recipes/nonlinear.py +0 -0
  46. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/recipes/piecewise.py +0 -0
  47. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/relax.pxi +0 -0
  48. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/scip.pyx +0 -0
  49. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/src/pyscipopt/sepa.pxi +0 -0
  50. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_alldiff.py +0 -0
  51. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_benders.py +0 -0
  52. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_bipartite.py +0 -0
  53. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_branch_mostinfeas.py +0 -0
  54. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_branch_probing_lp.py +0 -0
  55. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_conshdlr.py +0 -0
  56. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_customizedbenders.py +0 -0
  57. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_cutsel.py +0 -0
  58. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_expr.py +0 -0
  59. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_gomory.py +0 -0
  60. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_knapsack.py +0 -0
  61. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_linexpr.py +0 -0
  62. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_logical.py +0 -0
  63. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_lp.py +0 -0
  64. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_nlrow.py +0 -0
  65. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_nodesel.py +0 -0
  66. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_nonlinear.py +0 -0
  67. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_pricer.py +0 -0
  68. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_quadcons.py +0 -0
  69. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_quickprod.py +0 -0
  70. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_quicksum.py +0 -0
  71. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_reader.py +0 -0
  72. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_recipe_infeasibilities.py +0 -0
  73. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_recipe_nonlinear.py +0 -0
  74. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_recipe_piecewise.py +0 -0
  75. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_relax.py +0 -0
  76. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_reopt.py +0 -0
  77. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_short.py +0 -0
  78. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_strong_branching.py +0 -0
  79. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_tree.py +0 -0
  80. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_tsp.py +0 -0
  81. {pyscipopt-5.2.1 → pyscipopt-5.3.0}/tests/test_vars.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: PySCIPOpt
3
- Version: 5.2.1
3
+ Version: 5.3.0
4
4
  Summary: Python interface and modeling environment for SCIP
5
5
  Home-page: https://github.com/SCIP-Interfaces/PySCIPOpt
6
6
  Author: Zuse Institute Berlin
@@ -17,6 +17,8 @@ Classifier: Topic :: Scientific/Engineering :: Mathematics
17
17
  Requires-Python: >=3.8
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Dynamic: author
21
+ Dynamic: home-page
20
22
 
21
23
  PySCIPOpt
22
24
  =========
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: PySCIPOpt
3
- Version: 5.2.1
3
+ Version: 5.3.0
4
4
  Summary: Python interface and modeling environment for SCIP
5
5
  Home-page: https://github.com/SCIP-Interfaces/PySCIPOpt
6
6
  Author: Zuse Institute Berlin
@@ -17,6 +17,8 @@ Classifier: Topic :: Scientific/Engineering :: Mathematics
17
17
  Requires-Python: >=3.8
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Dynamic: author
21
+ Dynamic: home-page
20
22
 
21
23
  PySCIPOpt
22
24
  =========
@@ -34,6 +34,7 @@ src/pyscipopt/recipes/__init__.py
34
34
  src/pyscipopt/recipes/infeasibilities.py
35
35
  src/pyscipopt/recipes/nonlinear.py
36
36
  src/pyscipopt/recipes/piecewise.py
37
+ src/pyscipopt/recipes/primal_dual_evolution.py
37
38
  tests/test_alldiff.py
38
39
  tests/test_benders.py
39
40
  tests/test_bipartite.py
@@ -56,6 +57,7 @@ tests/test_memory.py
56
57
  tests/test_model.py
57
58
  tests/test_nlrow.py
58
59
  tests/test_nodesel.py
60
+ tests/test_nogil.py
59
61
  tests/test_nonlinear.py
60
62
  tests/test_pricer.py
61
63
  tests/test_quadcons.py
@@ -65,11 +67,13 @@ tests/test_reader.py
65
67
  tests/test_recipe_infeasibilities.py
66
68
  tests/test_recipe_nonlinear.py
67
69
  tests/test_recipe_piecewise.py
70
+ tests/test_recipe_primal_dual_evolution.py
68
71
  tests/test_relax.py
69
72
  tests/test_reopt.py
70
73
  tests/test_short.py
71
74
  tests/test_solution.py
72
75
  tests/test_strong_branching.py
76
+ tests/test_sub_sol.py
73
77
  tests/test_tree.py
74
78
  tests/test_tsp.py
75
79
  tests/test_vars.py
@@ -45,7 +45,7 @@ manylinux-x86_64-image = "manylinux_2_28"
45
45
  skip="pp* cp36* cp37* *musllinux*"
46
46
  before-all = [
47
47
  "(apt-get update && apt-get install --yes wget) || yum install -y wget zlib libgfortran || brew install wget",
48
- "wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.5.0/libscip-linux.zip -O scip.zip",
48
+ "wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.7.0/libscip-linux.zip -O scip.zip",
49
49
  "unzip scip.zip",
50
50
  "mv scip_install scip"
51
51
  ]
@@ -58,10 +58,10 @@ before-all = '''
58
58
  #!/bin/bash
59
59
  brew install wget zlib gcc
60
60
  if [[ $CIBW_ARCHS == *"arm"* ]]; then
61
- wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.5.0/libscip-macos-arm.zip -O scip.zip
61
+ wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.7.0/libscip-macos-arm.zip -O scip.zip
62
62
  export MACOSX_DEPLOYMENT_TARGET=14.0
63
63
  else
64
- wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.5.0/libscip-macos.zip -O scip.zip
64
+ wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.7.0/libscip-macos-intel.zip -O scip.zip
65
65
  export MACOSX_DEPLOYMENT_TARGET=13.0
66
66
  fi
67
67
  unzip scip.zip
@@ -87,7 +87,7 @@ repair-wheel-command = '''
87
87
  skip="pp* cp36* cp37*"
88
88
  before-all = [
89
89
  "choco install 7zip wget",
90
- "wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.5.0/libscip-windows.zip -O scip.zip",
90
+ "wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.7.0/libscip-windows.zip -O scip.zip",
91
91
  "\"C:\\Program Files\\7-Zip\\7z.exe\" x \"scip.zip\" -o\"scip-test\"",
92
92
  "mv .\\scip-test\\scip_install .\\test",
93
93
  "mv .\\test .\\scip"
@@ -109,7 +109,7 @@ with open("README.md") as f:
109
109
 
110
110
  setup(
111
111
  name="PySCIPOpt",
112
- version="5.2.1",
112
+ version="5.3.0",
113
113
  description="Python interface and modeling environment for SCIP",
114
114
  long_description=long_description,
115
115
  long_description_content_type="text/markdown",
@@ -46,3 +46,4 @@ from pyscipopt.scip import PY_SCIP_LPSOLSTAT as SCIP_LPSOLSTAT
46
46
  from pyscipopt.scip import PY_SCIP_BRANCHDIR as SCIP_BRANCHDIR
47
47
  from pyscipopt.scip import PY_SCIP_BENDERSENFOTYPE as SCIP_BENDERSENFOTYPE
48
48
  from pyscipopt.scip import PY_SCIP_ROWORIGINTYPE as SCIP_ROWORIGINTYPE
49
+ from pyscipopt.scip import PY_SCIP_SOLORIGIN as SCIP_SOLORIGIN
@@ -0,0 +1 @@
1
+ __version__ = '5.3.0'
@@ -175,8 +175,8 @@ cdef SCIP_RETCODE PyBendersSolvesub (SCIP* scip, SCIP_BENDERS* benders, SCIP_SOL
175
175
  cdef SCIP_RETCODE PyBendersPostsolve (SCIP* scip, SCIP_BENDERS* benders, SCIP_SOL* sol,
176
176
  SCIP_BENDERSENFOTYPE type, int* mergecands, int npriomergecands, int nmergecands, SCIP_Bool checkint,
177
177
  SCIP_Bool infeasible, SCIP_Bool* merged) noexcept with gil:
178
- cdef SCIP_BENDERSDATA* bendersdata
179
- bendersdata = SCIPbendersGetData(benders)
178
+ cdef SCIP_BENDERSDATA* bendersdata = SCIPbendersGetData(benders)
179
+ cdef int i
180
180
  PyBenders = <Benders>bendersdata
181
181
  if sol == NULL:
182
182
  solution = None
@@ -168,48 +168,54 @@ cdef SCIP_RETCODE PyConsFree (SCIP* scip, SCIP_CONSHDLR* conshdlr) noexcept with
168
168
  return SCIP_OKAY
169
169
 
170
170
  cdef SCIP_RETCODE PyConsInit (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss) noexcept with gil:
171
+ cdef int i
171
172
  PyConshdlr = getPyConshdlr(conshdlr)
172
- cdef constraints = []
173
+ constraints = []
173
174
  for i in range(nconss):
174
175
  constraints.append(getPyCons(conss[i]))
175
176
  PyConshdlr.consinit(constraints)
176
177
  return SCIP_OKAY
177
178
 
178
179
  cdef SCIP_RETCODE PyConsExit (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss) noexcept with gil:
180
+ cdef int i
179
181
  PyConshdlr = getPyConshdlr(conshdlr)
180
- cdef constraints = []
182
+ constraints = []
181
183
  for i in range(nconss):
182
184
  constraints.append(getPyCons(conss[i]))
183
185
  PyConshdlr.consexit(constraints)
184
186
  return SCIP_OKAY
185
187
 
186
188
  cdef SCIP_RETCODE PyConsInitpre (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss) noexcept with gil:
189
+ cdef int i
187
190
  PyConshdlr = getPyConshdlr(conshdlr)
188
- cdef constraints = []
191
+ constraints = []
189
192
  for i in range(nconss):
190
193
  constraints.append(getPyCons(conss[i]))
191
194
  PyConshdlr.consinitpre(constraints)
192
195
  return SCIP_OKAY
193
196
 
194
197
  cdef SCIP_RETCODE PyConsExitpre (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss) noexcept with gil:
198
+ cdef int i
195
199
  PyConshdlr = getPyConshdlr(conshdlr)
196
- cdef constraints = []
200
+ constraints = []
197
201
  for i in range(nconss):
198
202
  constraints.append(getPyCons(conss[i]))
199
203
  PyConshdlr.consexitpre(constraints)
200
204
  return SCIP_OKAY
201
205
 
202
206
  cdef SCIP_RETCODE PyConsInitsol (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss) noexcept with gil:
207
+ cdef int i
203
208
  PyConshdlr = getPyConshdlr(conshdlr)
204
- cdef constraints = []
209
+ constraints = []
205
210
  for i in range(nconss):
206
211
  constraints.append(getPyCons(conss[i]))
207
212
  PyConshdlr.consinitsol(constraints)
208
213
  return SCIP_OKAY
209
214
 
210
215
  cdef SCIP_RETCODE PyConsExitsol (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, SCIP_Bool restart) noexcept with gil:
216
+ cdef int i
211
217
  PyConshdlr = getPyConshdlr(conshdlr)
212
- cdef constraints = []
218
+ constraints = []
213
219
  for i in range(nconss):
214
220
  constraints.append(getPyCons(conss[i]))
215
221
  PyConshdlr.consexitsol(constraints, restart)
@@ -244,8 +250,9 @@ cdef SCIP_RETCODE PyConsTrans (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS* s
244
250
  return SCIP_OKAY
245
251
 
246
252
  cdef SCIP_RETCODE PyConsInitlp (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, SCIP_Bool* infeasible) noexcept with gil:
253
+ cdef int i
247
254
  PyConshdlr = getPyConshdlr(conshdlr)
248
- cdef constraints = []
255
+ constraints = []
249
256
  for i in range(nconss):
250
257
  constraints.append(getPyCons(conss[i]))
251
258
  result_dict = PyConshdlr.consinitlp(constraints)
@@ -253,8 +260,9 @@ cdef SCIP_RETCODE PyConsInitlp (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS**
253
260
  return SCIP_OKAY
254
261
 
255
262
  cdef SCIP_RETCODE PyConsSepalp (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, int nusefulconss, SCIP_RESULT* result) noexcept with gil:
263
+ cdef int i
256
264
  PyConshdlr = getPyConshdlr(conshdlr)
257
- cdef constraints = []
265
+ constraints = []
258
266
  for i in range(nconss):
259
267
  constraints.append(getPyCons(conss[i]))
260
268
  result_dict = PyConshdlr.conssepalp(constraints, nusefulconss)
@@ -263,8 +271,9 @@ cdef SCIP_RETCODE PyConsSepalp (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS**
263
271
 
264
272
  cdef SCIP_RETCODE PyConsSepasol (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, int nusefulconss,
265
273
  SCIP_SOL* sol, SCIP_RESULT* result) noexcept with gil:
274
+ cdef int i
266
275
  PyConshdlr = getPyConshdlr(conshdlr)
267
- cdef constraints = []
276
+ constraints = []
268
277
  for i in range(nconss):
269
278
  constraints.append(getPyCons(conss[i]))
270
279
  solution = Solution.create(scip, sol)
@@ -274,8 +283,9 @@ cdef SCIP_RETCODE PyConsSepasol (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS*
274
283
 
275
284
  cdef SCIP_RETCODE PyConsEnfolp (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, int nusefulconss,
276
285
  SCIP_Bool solinfeasible, SCIP_RESULT* result) noexcept with gil:
286
+ cdef int i
277
287
  PyConshdlr = getPyConshdlr(conshdlr)
278
- cdef constraints = []
288
+ constraints = []
279
289
  for i in range(nconss):
280
290
  constraints.append(getPyCons(conss[i]))
281
291
  result_dict = PyConshdlr.consenfolp(constraints, nusefulconss, solinfeasible)
@@ -283,8 +293,9 @@ cdef SCIP_RETCODE PyConsEnfolp (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS**
283
293
  return SCIP_OKAY
284
294
 
285
295
  cdef SCIP_RETCODE PyConsEnforelax (SCIP* scip, SCIP_SOL* sol, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, int nusefulconss, SCIP_Bool solinfeasible, SCIP_RESULT* result) noexcept with gil:
296
+ cdef int i
286
297
  PyConshdlr = getPyConshdlr(conshdlr)
287
- cdef constraints = []
298
+ constraints = []
288
299
  for i in range(nconss):
289
300
  constraints.append(getPyCons(conss[i]))
290
301
  solution = Solution.create(scip, sol)
@@ -294,8 +305,9 @@ cdef SCIP_RETCODE PyConsEnforelax (SCIP* scip, SCIP_SOL* sol, SCIP_CONSHDLR* con
294
305
 
295
306
  cdef SCIP_RETCODE PyConsEnfops (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, int nusefulconss,
296
307
  SCIP_Bool solinfeasible, SCIP_Bool objinfeasible, SCIP_RESULT* result) noexcept with gil:
308
+ cdef int i
297
309
  PyConshdlr = getPyConshdlr(conshdlr)
298
- cdef constraints = []
310
+ constraints = []
299
311
  for i in range(nconss):
300
312
  constraints.append(getPyCons(conss[i]))
301
313
  result_dict = PyConshdlr.consenfops(constraints, nusefulconss, solinfeasible, objinfeasible)
@@ -304,8 +316,9 @@ cdef SCIP_RETCODE PyConsEnfops (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS**
304
316
 
305
317
  cdef SCIP_RETCODE PyConsCheck (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, SCIP_SOL* sol, SCIP_Bool checkintegrality,
306
318
  SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool completely, SCIP_RESULT* result) noexcept with gil:
319
+ cdef int i
307
320
  PyConshdlr = getPyConshdlr(conshdlr)
308
- cdef constraints = []
321
+ constraints = []
309
322
  for i in range(nconss):
310
323
  constraints.append(getPyCons(conss[i]))
311
324
  solution = Solution.create(scip, sol)
@@ -315,8 +328,9 @@ cdef SCIP_RETCODE PyConsCheck (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS**
315
328
 
316
329
  cdef SCIP_RETCODE PyConsProp (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss, int nusefulconss, int nmarkedconss,
317
330
  SCIP_PROPTIMING proptiming, SCIP_RESULT* result) noexcept with gil:
331
+ cdef int i
318
332
  PyConshdlr = getPyConshdlr(conshdlr)
319
- cdef constraints = []
333
+ constraints = []
320
334
  for i in range(nconss):
321
335
  constraints.append(getPyCons(conss[i]))
322
336
  result_dict = PyConshdlr.consprop(constraints, nusefulconss, nmarkedconss, proptiming)
@@ -328,8 +342,9 @@ cdef SCIP_RETCODE PyConsPresol (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS**
328
342
  int nnewdelconss, int nnewaddconss, int nnewupgdconss, int nnewchgcoefs, int nnewchgsides,
329
343
  int* nfixedvars, int* naggrvars, int* nchgvartypes, int* nchgbds, int* naddholes,
330
344
  int* ndelconss, int* naddconss, int* nupgdconss, int* nchgcoefs, int* nchgsides, SCIP_RESULT* result) noexcept with gil:
345
+ cdef int i
331
346
  PyConshdlr = getPyConshdlr(conshdlr)
332
- cdef constraints = []
347
+ constraints = []
333
348
  for i in range(nconss):
334
349
  constraints.append(getPyCons(conss[i]))
335
350
  # dictionary for input/output parameters
@@ -401,8 +416,9 @@ cdef SCIP_RETCODE PyConsDisable (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS*
401
416
  return SCIP_OKAY
402
417
 
403
418
  cdef SCIP_RETCODE PyConsDelvars (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss) noexcept with gil:
419
+ cdef int i
404
420
  PyConshdlr = getPyConshdlr(conshdlr)
405
- cdef constraints = []
421
+ constraints = []
406
422
  for i in range(nconss):
407
423
  constraints.append(getPyCons(conss[i]))
408
424
  PyConshdlr.consdelvars(constraints)
@@ -72,9 +72,10 @@ cdef SCIP_RETCODE PyCutselExitsol (SCIP* scip, SCIP_CUTSEL* cutsel) noexcept wit
72
72
  cdef SCIP_RETCODE PyCutselSelect (SCIP* scip, SCIP_CUTSEL* cutsel, SCIP_ROW** cuts, int ncuts,
73
73
  SCIP_ROW** forcedcuts, int nforcedcuts, SCIP_Bool root, int maxnselectedcuts,
74
74
  int* nselectedcuts, SCIP_RESULT* result) noexcept with gil:
75
- cdef SCIP_CUTSELDATA* cutseldata
75
+ cdef SCIP_CUTSELDATA* cutseldata = SCIPcutselGetData(cutsel)
76
76
  cdef SCIP_ROW* scip_row
77
- cutseldata = SCIPcutselGetData(cutsel)
77
+ cdef int i
78
+
78
79
  PyCutsel = <Cutsel>cutseldata
79
80
 
80
81
  # translate cuts to python
@@ -63,19 +63,14 @@ cdef class LP:
63
63
  lb -- lower bound (default 0.0)
64
64
  ub -- upper bound (default infinity)
65
65
  """
66
- nnonz = len(entries)
67
-
66
+ cdef int nnonz = len(entries)
68
67
  cdef SCIP_Real* c_coefs = <SCIP_Real*> malloc(nnonz * sizeof(SCIP_Real))
69
68
  cdef int* c_inds = <int*>malloc(nnonz * sizeof(int))
70
- cdef SCIP_Real c_obj
71
- cdef SCIP_Real c_lb
72
- cdef SCIP_Real c_ub
73
- cdef int c_beg
74
-
75
- c_obj = obj
76
- c_lb = lb
77
- c_ub = ub if ub != None else self.infinity()
78
- c_beg = 0
69
+ cdef SCIP_Real c_obj = obj
70
+ cdef SCIP_Real c_lb = lb
71
+ cdef SCIP_Real c_ub = ub if ub != None else self.infinity()
72
+ cdef int c_beg = 0
73
+ cdef int i
79
74
 
80
75
  for i,entry in enumerate(entries):
81
76
  c_inds[i] = entry[0]
@@ -95,17 +90,15 @@ cdef class LP:
95
90
  lbs -- lower bounds (default 0.0)
96
91
  ubs -- upper bounds (default infinity)
97
92
  """
98
-
99
- ncols = len(entrieslist)
100
- nnonz = sum(len(entries) for entries in entrieslist)
101
-
93
+ cdef int ncols = len(entrieslist)
102
94
  cdef SCIP_Real* c_objs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
103
95
  cdef SCIP_Real* c_lbs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
104
96
  cdef SCIP_Real* c_ubs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
105
97
  cdef SCIP_Real* c_coefs
106
98
  cdef int* c_inds
107
99
  cdef int* c_beg
108
-
100
+ cdef int nnonz = sum(len(entries) for entries in entrieslist)
101
+ cdef int i
109
102
 
110
103
  if nnonz > 0:
111
104
  c_coefs = <SCIP_Real*> malloc(nnonz * sizeof(SCIP_Real))
@@ -158,18 +151,13 @@ cdef class LP:
158
151
  lhs -- left-hand side of the row (default 0.0)
159
152
  rhs -- right-hand side of the row (default infinity)
160
153
  """
161
- beg = 0
162
- nnonz = len(entries)
163
-
154
+ cdef int nnonz = len(entries)
164
155
  cdef SCIP_Real* c_coefs = <SCIP_Real*> malloc(nnonz * sizeof(SCIP_Real))
165
156
  cdef int* c_inds = <int*>malloc(nnonz * sizeof(int))
166
- cdef SCIP_Real c_lhs
167
- cdef SCIP_Real c_rhs
168
- cdef int c_beg
169
-
170
- c_lhs = lhs
171
- c_rhs = rhs if rhs != None else self.infinity()
172
- c_beg = 0
157
+ cdef SCIP_Real c_lhs = lhs
158
+ cdef SCIP_Real c_rhs = rhs if rhs != None else self.infinity()
159
+ cdef int c_beg = 0
160
+ cdef int i
173
161
 
174
162
  for i,entry in enumerate(entries):
175
163
  c_inds[i] = entry[0]
@@ -188,16 +176,16 @@ cdef class LP:
188
176
  lhss -- left-hand side of the row (default 0.0)
189
177
  rhss -- right-hand side of the row (default infinity)
190
178
  """
191
- nrows = len(entrieslist)
192
- nnonz = sum(len(entries) for entries in entrieslist)
193
-
179
+ cdef int nrows = len(entrieslist)
194
180
  cdef SCIP_Real* c_lhss = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
195
181
  cdef SCIP_Real* c_rhss = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
182
+ cdef int* c_beg = <int*>malloc(nrows * sizeof(int))
183
+ cdef int nnonz = sum(len(entries) for entries in entrieslist)
196
184
  cdef SCIP_Real* c_coefs = <SCIP_Real*> malloc(nnonz * sizeof(SCIP_Real))
197
185
  cdef int* c_inds = <int*>malloc(nnonz * sizeof(int))
198
- cdef int* c_beg = <int*>malloc(nrows * sizeof(int))
186
+ cdef int tmp = 0
187
+ cdef int i
199
188
 
200
- tmp = 0
201
189
  for i,entries in enumerate(entrieslist):
202
190
  c_lhss[i] = lhss[i] if lhss != None else 0.0
203
191
  c_rhss[i] = rhss[i] if rhss != None else self.infinity()
@@ -232,6 +220,8 @@ cdef class LP:
232
220
  firstcol -- first column (default 0)
233
221
  lastcol -- last column (default ncols - 1)
234
222
  """
223
+ cdef int i
224
+
235
225
  lastcol = lastcol if lastcol != None else self.ncols() - 1
236
226
 
237
227
  if firstcol > lastcol:
@@ -261,6 +251,8 @@ cdef class LP:
261
251
  firstrow -- first row (default 0)
262
252
  lastrow -- last row (default nrows - 1)
263
253
  """
254
+ cdef int i
255
+
264
256
  lastrow = lastrow if lastrow != None else self.nrows() - 1
265
257
 
266
258
  if firstrow > lastrow:
@@ -290,8 +282,9 @@ cdef class LP:
290
282
  col -- column to change
291
283
  obj -- new objective coefficient
292
284
  """
293
- cdef int c_col = col
294
285
  cdef SCIP_Real c_obj = obj
286
+ cdef int c_col = col
287
+
295
288
  PY_SCIP_CALL(SCIPlpiChgObj(self.lpi, 1, &c_col, &c_obj))
296
289
 
297
290
  def chgCoef(self, row, col, newval):
@@ -312,9 +305,10 @@ cdef class LP:
312
305
  lb -- new lower bound
313
306
  ub -- new upper bound
314
307
  """
315
- cdef int c_col = col
316
308
  cdef SCIP_Real c_lb = lb
317
309
  cdef SCIP_Real c_ub = ub
310
+ cdef int c_col = col
311
+
318
312
  PY_SCIP_CALL(SCIPlpiChgBounds(self.lpi, 1, &c_col, &c_lb, &c_ub))
319
313
 
320
314
  def chgSide(self, row, lhs, rhs):
@@ -325,9 +319,10 @@ cdef class LP:
325
319
  lhs -- new left-hand side
326
320
  rhs -- new right-hand side
327
321
  """
328
- cdef int c_row = row
329
322
  cdef SCIP_Real c_lhs = lhs
330
323
  cdef SCIP_Real c_rhs = rhs
324
+ cdef int c_row = row
325
+
331
326
  PY_SCIP_CALL(SCIPlpiChgSides(self.lpi, 1, &c_row, &c_lhs, &c_rhs))
332
327
 
333
328
  def clear(self):
@@ -337,13 +332,17 @@ cdef class LP:
337
332
  def nrows(self):
338
333
  """Returns the number of rows."""
339
334
  cdef int nrows
335
+
340
336
  PY_SCIP_CALL(SCIPlpiGetNRows(self.lpi, &nrows))
337
+
341
338
  return nrows
342
339
 
343
340
  def ncols(self):
344
341
  """Returns the number of columns."""
345
342
  cdef int ncols
343
+
346
344
  PY_SCIP_CALL(SCIPlpiGetNCols(self.lpi, &ncols))
345
+
347
346
  return ncols
348
347
 
349
348
  def solve(self, dual=True):
@@ -359,12 +358,15 @@ cdef class LP:
359
358
 
360
359
  cdef SCIP_Real objval
361
360
  PY_SCIP_CALL(SCIPlpiGetObjval(self.lpi, &objval))
361
+
362
362
  return objval
363
363
 
364
364
  def getPrimal(self):
365
365
  """Returns the primal solution of the last LP solve."""
366
- ncols = self.ncols()
366
+ cdef int ncols = self.ncols()
367
367
  cdef SCIP_Real* c_primalsol = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
368
+ cdef int i
369
+
368
370
  PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, c_primalsol, NULL, NULL, NULL))
369
371
  primalsol = [0.0] * ncols
370
372
  for i in range(ncols):
@@ -379,8 +381,10 @@ cdef class LP:
379
381
 
380
382
  def getDual(self):
381
383
  """Returns the dual solution of the last LP solve."""
382
- nrows = self.nrows()
384
+ cdef int nrows = self.nrows()
383
385
  cdef SCIP_Real* c_dualsol = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
386
+ cdef int i
387
+
384
388
  PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, NULL, c_dualsol, NULL, NULL))
385
389
  dualsol = [0.0] * nrows
386
390
  for i in range(nrows):
@@ -395,10 +399,16 @@ cdef class LP:
395
399
 
396
400
  def getPrimalRay(self):
397
401
  """Returns a primal ray if possible, None otherwise."""
402
+ cdef int ncols
403
+ cdef SCIP_Real* c_ray
404
+ cdef int i
405
+
398
406
  if not SCIPlpiHasPrimalRay(self.lpi):
399
407
  return None
408
+
400
409
  ncols = self.ncols()
401
- cdef SCIP_Real* c_ray = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
410
+ c_ray = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
411
+
402
412
  PY_SCIP_CALL(SCIPlpiGetPrimalRay(self.lpi, c_ray))
403
413
  ray = [0.0] * ncols
404
414
  for i in range(ncols):
@@ -409,10 +419,16 @@ cdef class LP:
409
419
 
410
420
  def getDualRay(self):
411
421
  """Returns a dual ray if possible, None otherwise."""
422
+ cdef int nrows
423
+ cdef SCIP_Real* c_ray
424
+ cdef int i
425
+
412
426
  if not SCIPlpiHasDualRay(self.lpi):
413
427
  return None
428
+
414
429
  nrows = self.nrows()
415
- cdef SCIP_Real* c_ray = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
430
+ c_ray = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
431
+
416
432
  PY_SCIP_CALL(SCIPlpiGetDualfarkas(self.lpi, c_ray))
417
433
  ray = [0.0] * nrows
418
434
  for i in range(nrows):
@@ -424,14 +440,17 @@ cdef class LP:
424
440
  def getNIterations(self):
425
441
  """Returns the number of LP iterations of the last LP solve."""
426
442
  cdef int niters
443
+
427
444
  PY_SCIP_CALL(SCIPlpiGetIterations(self.lpi, &niters))
445
+
428
446
  return niters
429
447
 
430
448
  def getRedcost(self):
431
449
  """Returns the reduced cost vector of the last LP solve."""
432
- ncols = self.ncols()
433
-
450
+ cdef int ncols = self.ncols()
434
451
  cdef SCIP_Real* c_redcost = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
452
+ cdef int i
453
+
435
454
  PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, NULL, NULL, NULL, c_redcost))
436
455
 
437
456
  redcost = []
@@ -439,12 +458,14 @@ cdef class LP:
439
458
  redcost[i].append(c_redcost[i])
440
459
 
441
460
  free(c_redcost)
461
+
442
462
  return redcost
443
463
 
444
464
  def getBasisInds(self):
445
465
  """Returns the indices of the basic columns and rows; index i >= 0 corresponds to column i, index i < 0 to row -i-1"""
446
- nrows = self.nrows()
447
- cdef int* c_binds = <int*> malloc(nrows * sizeof(int))
466
+ cdef int nrows = self.nrows()
467
+ cdef int* c_binds = <int*> malloc(nrows * sizeof(int))
468
+ cdef int i
448
469
 
449
470
  PY_SCIP_CALL(SCIPlpiGetBasisInd(self.lpi, c_binds))
450
471
 
@@ -453,4 +474,5 @@ cdef class LP:
453
474
  binds.append(c_binds[i])
454
475
 
455
476
  free(c_binds)
477
+
456
478
  return binds
@@ -45,9 +45,10 @@ cdef SCIP_RETCODE PyReaderWrite (SCIP* scip, SCIP_READER* reader, FILE* file,
45
45
  SCIP_VAR** fixedvars, int nfixedvars, int startnvars,
46
46
  SCIP_CONS** conss, int nconss, int maxnconss, int startnconss,
47
47
  SCIP_Bool genericnames, SCIP_RESULT* result) noexcept with gil:
48
- cdef SCIP_READERDATA* readerdata
49
- readerdata = SCIPreaderGetData(reader)
48
+ cdef SCIP_READERDATA* readerdata = SCIPreaderGetData(reader)
50
49
  cdef int fd = fileno(file)
50
+ cdef int i
51
+
51
52
  PyFile = os.fdopen(fd, "w", closefd=False)
52
53
  PyName = name.decode('utf-8')
53
54
  PyBinVars = [Variable.create(vars[i]) for i in range(nbinvars)]
@@ -61,4 +62,5 @@ cdef SCIP_RETCODE PyReaderWrite (SCIP* scip, SCIP_READER* reader, FILE* file,
61
62
  PyBinVars, PyIntVars, PyImplVars, PyContVars, PyFixedVars, startnvars,
62
63
  PyConss, maxnconss, startnconss, genericnames)
63
64
  result[0] = result_dict.get("result", <SCIP_RESULT>result[0])
65
+
64
66
  return SCIP_OKAY
@@ -0,0 +1,46 @@
1
+ from pyscipopt import Model, Eventhdlr, SCIP_EVENTTYPE, Eventhdlr
2
+
3
+ def attach_primal_dual_evolution_eventhdlr(model: Model):
4
+ """
5
+ Attaches an event handler to a given SCIP model that collects primal and dual solutions,
6
+ along with the solving time when they were found.
7
+ The data is saved in model.data["primal_log"] and model.data["dual_log"]. They consist of
8
+ a list of tuples, each tuple containing the solving time and the corresponding solution.
9
+
10
+ A usage example can be found in examples/finished/plot_primal_dual_evolution.py. The
11
+ example takes the information provided by this recipe and uses it to plot the evolution
12
+ of the dual and primal bounds over time.
13
+ """
14
+ class GapEventhdlr(Eventhdlr):
15
+
16
+ def eventinit(self): # we want to collect best primal solutions and best dual solutions
17
+ self.model.catchEvent(SCIP_EVENTTYPE.BESTSOLFOUND, self)
18
+ self.model.catchEvent(SCIP_EVENTTYPE.LPSOLVED, self)
19
+ self.model.catchEvent(SCIP_EVENTTYPE.NODESOLVED, self)
20
+
21
+
22
+ def eventexec(self, event):
23
+ # if a new best primal solution was found, we save when it was found and also its objective
24
+ if event.getType() == SCIP_EVENTTYPE.BESTSOLFOUND:
25
+ self.model.data["primal_log"].append([self.model.getSolvingTime(), self.model.getPrimalbound()])
26
+
27
+ if not self.model.data["dual_log"]:
28
+ self.model.data["dual_log"].append([self.model.getSolvingTime(), self.model.getDualbound()])
29
+
30
+ if self.model.getObjectiveSense() == "minimize":
31
+ if self.model.isGT(self.model.getDualbound(), self.model.data["dual_log"][-1][1]):
32
+ self.model.data["dual_log"].append([self.model.getSolvingTime(), self.model.getDualbound()])
33
+ else:
34
+ if self.model.isLT(self.model.getDualbound(), self.model.data["dual_log"][-1][1]):
35
+ self.model.data["dual_log"].append([self.model.getSolvingTime(), self.model.getDualbound()])
36
+
37
+
38
+ if not hasattr(model, "data") or model.data==None:
39
+ model.data = {}
40
+
41
+ model.data["primal_log"] = []
42
+ model.data["dual_log"] = []
43
+ hdlr = GapEventhdlr()
44
+ model.includeEventhdlr(hdlr, "gapEventHandler", "Event handler which collects primal and dual solution evolution")
45
+
46
+ return model