PySCIPOpt 5.6.0__tar.gz → 5.7.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 (95) hide show
  1. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/PKG-INFO +1 -1
  2. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/PySCIPOpt.egg-info/PKG-INFO +1 -1
  3. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/PySCIPOpt.egg-info/SOURCES.txt +5 -0
  4. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/pyproject.toml +7 -7
  5. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/setup.py +32 -24
  6. pyscipopt-5.7.0/src/pyscipopt/__init__.py +58 -0
  7. pyscipopt-5.7.0/src/pyscipopt/_version.py +1 -0
  8. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/event.pxi +1 -1
  9. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/expr.pxi +60 -23
  10. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/lp.pxi +8 -4
  11. pyscipopt-5.7.0/src/pyscipopt/matrix.pxi +112 -0
  12. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/nodesel.pxi +6 -2
  13. pyscipopt-5.7.0/src/pyscipopt/recipes/__init__.py +0 -0
  14. pyscipopt-5.7.0/src/pyscipopt/recipes/getLocalConss.py +51 -0
  15. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/recipes/infeasibilities.py +1 -1
  16. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/recipes/nonlinear.py +1 -2
  17. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/scip.c +74243 -75947
  18. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/scip.pxd +34 -13
  19. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/scip.pxi +616 -71
  20. pyscipopt-5.7.0/src/pyscipopt/scip.pyi +1339 -0
  21. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_benders.py +0 -5
  22. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_cons.py +61 -0
  23. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_customizedbenders.py +0 -10
  24. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_expr.py +11 -0
  25. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_gomory.py +1 -1
  26. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_logical.py +1 -6
  27. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_matrix_variable.py +204 -8
  28. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_model.py +39 -4
  29. pyscipopt-5.7.0/tests/test_node_methods.py +183 -0
  30. pyscipopt-5.7.0/tests/test_recipe_getLocalConss.py +38 -0
  31. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_relax.py +2 -1
  32. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_tsp.py +1 -2
  33. pyscipopt-5.7.0/tests/test_vars.py +146 -0
  34. pyscipopt-5.6.0/src/pyscipopt/__init__.py +0 -56
  35. pyscipopt-5.6.0/src/pyscipopt/_version.py +0 -1
  36. pyscipopt-5.6.0/src/pyscipopt/matrix.pxi +0 -139
  37. pyscipopt-5.6.0/tests/test_vars.py +0 -67
  38. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/LICENSE +0 -0
  39. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/PySCIPOpt.egg-info/dependency_links.txt +0 -0
  40. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/PySCIPOpt.egg-info/requires.txt +0 -0
  41. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/PySCIPOpt.egg-info/top_level.txt +0 -0
  42. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/README.md +0 -0
  43. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/setup.cfg +0 -0
  44. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/Multidict.py +0 -0
  45. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/benders.pxi +0 -0
  46. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/benderscut.pxi +0 -0
  47. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/branchrule.pxi +0 -0
  48. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/conshdlr.pxi +0 -0
  49. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/cutsel.pxi +0 -0
  50. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/heuristic.pxi +0 -0
  51. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/presol.pxi +0 -0
  52. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/pricer.pxi +0 -0
  53. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/propagator.pxi +0 -0
  54. /pyscipopt-5.6.0/src/pyscipopt/recipes/__init__.py → /pyscipopt-5.7.0/src/pyscipopt/py.typed +0 -0
  55. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/reader.pxi +0 -0
  56. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/recipes/piecewise.py +0 -0
  57. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/recipes/primal_dual_evolution.py +0 -0
  58. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/relax.pxi +0 -0
  59. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/scip.pyx +0 -0
  60. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/src/pyscipopt/sepa.pxi +0 -0
  61. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_alldiff.py +0 -0
  62. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_bipartite.py +0 -0
  63. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_branch_mostinfeas.py +0 -0
  64. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_branch_probing_lp.py +0 -0
  65. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_conshdlr.py +0 -0
  66. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_copy.py +0 -0
  67. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_cutsel.py +0 -0
  68. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_event.py +0 -0
  69. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_heur.py +0 -0
  70. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_knapsack.py +0 -0
  71. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_linexpr.py +0 -0
  72. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_lp.py +0 -0
  73. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_memory.py +0 -0
  74. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_nlrow.py +0 -0
  75. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_node.py +0 -0
  76. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_nodesel.py +0 -0
  77. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_nogil.py +0 -0
  78. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_nonlinear.py +0 -0
  79. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_numerics.py +0 -0
  80. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_pricer.py +0 -0
  81. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_quadcons.py +0 -0
  82. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_quickprod.py +0 -0
  83. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_quicksum.py +0 -0
  84. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_reader.py +0 -0
  85. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_recipe_infeasibilities.py +0 -0
  86. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_recipe_nonlinear.py +0 -0
  87. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_recipe_piecewise.py +0 -0
  88. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_recipe_primal_dual_evolution.py +0 -0
  89. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_reopt.py +0 -0
  90. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_row_dual.py +0 -0
  91. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_short.py +0 -0
  92. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_solution.py +0 -0
  93. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_strong_branching.py +0 -0
  94. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_sub_sol.py +0 -0
  95. {pyscipopt-5.6.0 → pyscipopt-5.7.0}/tests/test_tree.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySCIPOpt
3
- Version: 5.6.0
3
+ Version: 5.7.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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySCIPOpt
3
- Version: 5.6.0
3
+ Version: 5.7.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
@@ -25,14 +25,17 @@ src/pyscipopt/nodesel.pxi
25
25
  src/pyscipopt/presol.pxi
26
26
  src/pyscipopt/pricer.pxi
27
27
  src/pyscipopt/propagator.pxi
28
+ src/pyscipopt/py.typed
28
29
  src/pyscipopt/reader.pxi
29
30
  src/pyscipopt/relax.pxi
30
31
  src/pyscipopt/scip.c
31
32
  src/pyscipopt/scip.pxd
32
33
  src/pyscipopt/scip.pxi
34
+ src/pyscipopt/scip.pyi
33
35
  src/pyscipopt/scip.pyx
34
36
  src/pyscipopt/sepa.pxi
35
37
  src/pyscipopt/recipes/__init__.py
38
+ src/pyscipopt/recipes/getLocalConss.py
36
39
  src/pyscipopt/recipes/infeasibilities.py
37
40
  src/pyscipopt/recipes/nonlinear.py
38
41
  src/pyscipopt/recipes/piecewise.py
@@ -60,6 +63,7 @@ tests/test_memory.py
60
63
  tests/test_model.py
61
64
  tests/test_nlrow.py
62
65
  tests/test_node.py
66
+ tests/test_node_methods.py
63
67
  tests/test_nodesel.py
64
68
  tests/test_nogil.py
65
69
  tests/test_nonlinear.py
@@ -69,6 +73,7 @@ tests/test_quadcons.py
69
73
  tests/test_quickprod.py
70
74
  tests/test_quicksum.py
71
75
  tests/test_reader.py
76
+ tests/test_recipe_getLocalConss.py
72
77
  tests/test_recipe_infeasibilities.py
73
78
  tests/test_recipe_nonlinear.py
74
79
  tests/test_recipe_piecewise.py
@@ -51,9 +51,9 @@ AARCH=$(uname -m)
51
51
  echo "------"
52
52
  echo $AARCH
53
53
  if [[ $AARCH == "aarch64" ]]; then
54
- wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.8.0/libscip-linux-arm.zip -O scip.zip
54
+ wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.9.0/libscip-linux-arm.zip -O scip.zip
55
55
  else
56
- wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.8.0/libscip-linux.zip -O scip.zip
56
+ wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.9.0/libscip-linux.zip -O scip.zip
57
57
  fi
58
58
  unzip scip.zip
59
59
  mv scip_install scip
@@ -67,11 +67,11 @@ before-all = '''
67
67
  #!/bin/bash
68
68
  brew install wget zlib gcc
69
69
  if [[ $CIBW_ARCHS == *"arm"* ]]; then
70
- wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.8.0/libscip-macos-arm.zip -O scip.zip
70
+ wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.9.0/libscip-macos-arm.zip -O scip.zip
71
71
  export MACOSX_DEPLOYMENT_TARGET=14.0
72
72
  else
73
- wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.8.0/libscip-macos-intel.zip -O scip.zip
74
- export MACOSX_DEPLOYMENT_TARGET=13.0
73
+ wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.9.0/libscip-macos-intel.zip -O scip.zip
74
+ export MACOSX_DEPLOYMENT_TARGET=14.0
75
75
  fi
76
76
  unzip scip.zip
77
77
  mv scip_install src/scip
@@ -84,7 +84,7 @@ repair-wheel-command = '''
84
84
  delocate-listdeps {wheel}
85
85
  delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}
86
86
  else
87
- export MACOSX_DEPLOYMENT_TARGET=13.0
87
+ export MACOSX_DEPLOYMENT_TARGET=14.0
88
88
  delocate-listdeps {wheel}
89
89
  delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}
90
90
  fi
@@ -96,7 +96,7 @@ repair-wheel-command = '''
96
96
  skip="pp* cp36* cp37*"
97
97
  before-all = [
98
98
  "choco install 7zip wget",
99
- "wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.8.0/libscip-windows.zip -O scip.zip",
99
+ "wget https://github.com/scipopt/scipoptsuite-deploy/releases/download/v0.9.0/libscip-windows.zip -O scip.zip",
100
100
  "\"C:\\Program Files\\7-Zip\\7z.exe\" x \"scip.zip\" -o\"scip-test\"",
101
101
  "mv .\\scip-test\\scip_install .\\test",
102
102
  "mv .\\test .\\scip"
@@ -7,54 +7,63 @@ scipoptdir = os.environ.get("SCIPOPTDIR", "").strip('"')
7
7
  extra_compile_args = []
8
8
  extra_link_args = []
9
9
 
10
- # if SCIPOPTDIR is not set, we assume that SCIP is installed globally
10
+ # if SCIPOPTDIR is not set, try to detect conda environment, otherwise assume global installation
11
11
  if not scipoptdir:
12
- if platform.system() == "Darwin":
13
- includedir = "/usr/local/include"
14
- libdir = "/usr/local/lib"
12
+ # check if we're in a conda environment
13
+ conda_prefix = os.environ.get("CONDA_PREFIX", "").strip('"')
14
+
15
+ if conda_prefix and os.path.exists(os.path.join(conda_prefix, "include")):
16
+ includedir = os.path.join(conda_prefix, "include")
17
+ libdir = os.path.join(conda_prefix, "lib")
18
+ libname = "libscip" if platform.system() == "Windows" else "scip"
19
+ print(f"Detected conda environment at {conda_prefix}.")
20
+ print(f"Using include path {includedir}.")
21
+ print(f"Using library directory {libdir}.\n")
15
22
  else:
16
- includedir = "."
17
- libdir = "."
18
- libname = "libscip" if platform.system() in ["Windows"] else "scip"
19
- print("Assuming that SCIP is installed globally, because SCIPOPTDIR is undefined.\n")
23
+ # fall back to global installation
24
+ if platform.system() == "Darwin":
25
+ includedirs = ["/usr/local/include"]
26
+ libdir = "/usr/local/lib"
27
+ else:
28
+ includedirs = ["."]
29
+ libdir = "."
30
+ libname = "libscip" if platform.system() == "Windows" else "scip"
31
+ print("Assuming that SCIP is installed globally, because SCIPOPTDIR is undefined.\n")
20
32
 
21
33
  else:
22
34
 
23
35
  # check whether SCIP is installed in the given directory
24
36
  if os.path.exists(os.path.join(scipoptdir, "include")):
25
- includedir = os.path.abspath(os.path.join(scipoptdir, "include"))
37
+ includedirs = [os.path.abspath(os.path.join(scipoptdir, "include"))]
26
38
  else:
27
- print(f"SCIPOPTDIR={scipoptdir} does not contain an include directory; searching for include files in src or ../src directory.")
39
+ print("SCIPOPTDIR=%s does not contain an include directory; searching for include files in src or ../src directory.\n" % scipoptdir)
28
40
 
29
41
  if os.path.exists(os.path.join(scipoptdir, "src")):
30
42
  # SCIP seems to be installed in-place; check whether it was built using make or cmake
31
43
  if os.path.exists(os.path.join(scipoptdir, "src", "scip")):
32
44
  # assume that SCIPOPTDIR pointed to the main source directory (make)
33
- includedir = os.path.abspath(os.path.join(scipoptdir, "src"))
45
+ includedirs = [os.path.abspath(os.path.join(scipoptdir, "src")), os.path.abspath(os.path.join(scipoptdir, "lib/shared/include"))]
34
46
  else:
35
47
  # assume that SCIPOPTDIR pointed to a cmake build directory; try one level up (this is just a heuristic)
36
48
  if os.path.exists(os.path.join(scipoptdir, "..", "src", "scip")):
37
- includedir = os.path.abspath(os.path.join(scipoptdir, "..", "src"))
49
+ includedirs = [os.path.abspath(os.path.join(scipoptdir, "..", "src"))]
38
50
  else:
39
- sys.exit(f"Could neither find src/scip nor ../src/scip directory in SCIPOPTDIR={scipoptdir}. Consider installing SCIP in a separate directory.")
51
+ sys.exit("Could neither find src/scip nor ../src/scip directory in SCIPOPTDIR=%s. Consider installing SCIP in a separate directory." % scipoptdir)
40
52
  else:
41
- sys.exit(f"Could not find a src directory in SCIPOPTDIR={scipoptdir}; maybe it points to a wrong directory.")
53
+ sys.exit("Could not find a src directory in SCIPOPTDIR=%s; maybe it points to a wrong directory." % scipoptdir)
42
54
 
43
55
  # determine library
44
56
  if os.path.exists(os.path.join(scipoptdir, "lib", "shared", "libscip.so")):
45
57
  # SCIP seems to be created with make
46
58
  libdir = os.path.abspath(os.path.join(scipoptdir, "lib", "shared"))
47
59
  libname = "scip"
48
- extra_compile_args.append("-DNO_CONFIG_HEADER")
49
- # the following is a temporary hack to make it compile with SCIP/make:
50
- extra_compile_args.append("-DTPI_NONE") # if other TPIs are used, please modify
51
60
  else:
52
61
  # assume that SCIP is installed on the system
53
62
  libdir = os.path.abspath(os.path.join(scipoptdir, "lib"))
54
- libname = "libscip" if platform.system() in ["Windows"] else "scip"
63
+ libname = "libscip" if platform.system() == "Windows" else "scip"
55
64
 
56
- print(f"Using include path {includedir}.")
57
- print(f"Using SCIP library {libname} at {libdir}.\n")
65
+ print("Using include path %s." % includedirs)
66
+ print("Using SCIP library %s at %s.\n" % (libname, libdir))
58
67
 
59
68
  # set runtime libraries
60
69
  if platform.system() in ["Linux", "Darwin"]:
@@ -84,7 +93,6 @@ if not os.path.exists(os.path.join(packagedir, "scip.pyx")):
84
93
 
85
94
  ext = ".pyx" if use_cython else ".c"
86
95
 
87
-
88
96
  on_github_actions = os.getenv('GITHUB_ACTIONS') == 'true'
89
97
  release_mode = os.getenv('RELEASE') == 'true'
90
98
  compile_with_line_tracing = on_github_actions and not release_mode
@@ -92,8 +100,8 @@ compile_with_line_tracing = on_github_actions and not release_mode
92
100
  extensions = [
93
101
  Extension(
94
102
  "pyscipopt.scip",
95
- [os.path.join(packagedir, f"scip{ext}")],
96
- include_dirs=[includedir],
103
+ [os.path.join(packagedir, "scip%s" % ext)],
104
+ include_dirs=includedirs,
97
105
  library_dirs=[libdir],
98
106
  libraries=[libname],
99
107
  extra_compile_args=extra_compile_args,
@@ -110,7 +118,7 @@ with open("README.md") as f:
110
118
 
111
119
  setup(
112
120
  name="PySCIPOpt",
113
- version="5.6.0",
121
+ version="5.7.0",
114
122
  description="Python interface and modeling environment for SCIP",
115
123
  long_description=long_description,
116
124
  long_description_content_type="text/markdown",
@@ -0,0 +1,58 @@
1
+ from ._version import __version__
2
+
3
+ # required for Python 3.8 on Windows
4
+ import os
5
+ if hasattr(os, 'add_dll_directory'):
6
+ if os.getenv('SCIPOPTDIR'):
7
+ os.add_dll_directory(os.path.join(os.getenv('SCIPOPTDIR').strip('"'), 'bin'))
8
+
9
+ # export user-relevant objects:
10
+ from pyscipopt.Multidict import multidict as multidict
11
+ from pyscipopt.scip import Model as Model
12
+ from pyscipopt.scip import Variable as Variable
13
+ from pyscipopt.scip import MatrixVariable as MatrixVariable
14
+ from pyscipopt.scip import Constraint as Constraint
15
+ from pyscipopt.scip import MatrixConstraint as MatrixConstraint
16
+ from pyscipopt.scip import Benders as Benders
17
+ from pyscipopt.scip import Benderscut as Benderscut
18
+ from pyscipopt.scip import Branchrule as Branchrule
19
+ from pyscipopt.scip import Nodesel as Nodesel
20
+ from pyscipopt.scip import Conshdlr as Conshdlr
21
+ from pyscipopt.scip import Eventhdlr as Eventhdlr
22
+ from pyscipopt.scip import Heur as Heur
23
+ from pyscipopt.scip import Presol as Presol
24
+ from pyscipopt.scip import Pricer as Pricer
25
+ from pyscipopt.scip import Prop as Prop
26
+ from pyscipopt.scip import Reader as Reader
27
+ from pyscipopt.scip import Sepa as Sepa
28
+ from pyscipopt.scip import LP as LP
29
+ from pyscipopt.scip import PY_SCIP_LPPARAM as SCIP_LPPARAM
30
+ from pyscipopt.scip import readStatistics as readStatistics
31
+ from pyscipopt.scip import Expr as Expr
32
+ from pyscipopt.scip import MatrixExpr as MatrixExpr
33
+ from pyscipopt.scip import MatrixExprCons as MatrixExprCons
34
+ from pyscipopt.scip import ExprCons as ExprCons
35
+ from pyscipopt.scip import quicksum as quicksum
36
+ from pyscipopt.scip import quickprod as quickprod
37
+ from pyscipopt.scip import exp as exp
38
+ from pyscipopt.scip import log as log
39
+ from pyscipopt.scip import sqrt as sqrt
40
+ from pyscipopt.scip import sin as sin
41
+ from pyscipopt.scip import cos as cos
42
+ from pyscipopt.scip import PY_SCIP_RESULT as SCIP_RESULT
43
+ from pyscipopt.scip import PY_SCIP_PARAMSETTING as SCIP_PARAMSETTING
44
+ from pyscipopt.scip import PY_SCIP_PARAMEMPHASIS as SCIP_PARAMEMPHASIS
45
+ from pyscipopt.scip import PY_SCIP_STATUS as SCIP_STATUS
46
+ from pyscipopt.scip import PY_SCIP_STAGE as SCIP_STAGE
47
+ from pyscipopt.scip import PY_SCIP_NODETYPE as SCIP_NODETYPE
48
+ from pyscipopt.scip import PY_SCIP_PROPTIMING as SCIP_PROPTIMING
49
+ from pyscipopt.scip import PY_SCIP_PRESOLTIMING as SCIP_PRESOLTIMING
50
+ from pyscipopt.scip import PY_SCIP_HEURTIMING as SCIP_HEURTIMING
51
+ from pyscipopt.scip import PY_SCIP_EVENTTYPE as SCIP_EVENTTYPE
52
+ from pyscipopt.scip import PY_SCIP_LOCKTYPE as SCIP_LOCKTYPE
53
+ from pyscipopt.scip import PY_SCIP_LPSOLSTAT as SCIP_LPSOLSTAT
54
+ from pyscipopt.scip import PY_SCIP_BRANCHDIR as SCIP_BRANCHDIR
55
+ from pyscipopt.scip import PY_SCIP_BENDERSENFOTYPE as SCIP_BENDERSENFOTYPE
56
+ from pyscipopt.scip import PY_SCIP_ROWORIGINTYPE as SCIP_ROWORIGINTYPE
57
+ from pyscipopt.scip import PY_SCIP_SOLORIGIN as SCIP_SOLORIGIN
58
+ from pyscipopt.scip import PY_SCIP_NODETYPE as SCIP_NODETYPE
@@ -0,0 +1 @@
1
+ __version__: str = '5.7.0'
@@ -39,7 +39,7 @@ cdef class Eventhdlr:
39
39
 
40
40
 
41
41
  # local helper functions for the interface
42
- cdef Eventhdlr getPyEventhdlr(SCIP_EVENTHDLR* eventhdlr) noexcept with gil:
42
+ cdef Eventhdlr getPyEventhdlr(SCIP_EVENTHDLR* eventhdlr):
43
43
  cdef SCIP_EVENTHDLRDATA* eventhdlrdata
44
44
  eventhdlrdata = SCIPeventhdlrGetData(eventhdlr)
45
45
  return <Eventhdlr>eventhdlrdata
@@ -44,6 +44,7 @@
44
44
  # Modifying the expression directly would be a bug, given that the expression might be re-used by the user. </pre>
45
45
  include "matrix.pxi"
46
46
 
47
+
47
48
  def _is_number(e):
48
49
  try:
49
50
  f = float(e)
@@ -52,7 +53,8 @@ def _is_number(e):
52
53
  return False
53
54
  except TypeError: # for other types (Variable, Expr)
54
55
  return False
55
-
56
+
57
+
56
58
  def _expr_richcmp(self, other, op):
57
59
  if op == 1: # <=
58
60
  if isinstance(other, Expr) or isinstance(other, GenExpr):
@@ -62,7 +64,7 @@ def _expr_richcmp(self, other, op):
62
64
  elif isinstance(other, MatrixExpr):
63
65
  return _expr_richcmp(other, self, 5)
64
66
  else:
65
- raise NotImplementedError
67
+ raise TypeError(f"Unsupported type {type(other)}")
66
68
  elif op == 5: # >=
67
69
  if isinstance(other, Expr) or isinstance(other, GenExpr):
68
70
  return (self - other) >= 0.0
@@ -71,7 +73,7 @@ def _expr_richcmp(self, other, op):
71
73
  elif isinstance(other, MatrixExpr):
72
74
  return _expr_richcmp(other, self, 1)
73
75
  else:
74
- raise NotImplementedError
76
+ raise TypeError(f"Unsupported type {type(other)}")
75
77
  elif op == 2: # ==
76
78
  if isinstance(other, Expr) or isinstance(other, GenExpr):
77
79
  return (self - other) == 0.0
@@ -80,7 +82,7 @@ def _expr_richcmp(self, other, op):
80
82
  elif isinstance(other, MatrixExpr):
81
83
  return _expr_richcmp(other, self, 2)
82
84
  else:
83
- raise NotImplementedError
85
+ raise TypeError(f"Unsupported type {type(other)}")
84
86
  else:
85
87
  raise NotImplementedError("Can only support constraints with '<=', '>=', or '=='.")
86
88
 
@@ -146,7 +148,7 @@ def buildGenExprObj(expr):
146
148
  GenExprs = np.empty(expr.shape, dtype=object)
147
149
  for idx in np.ndindex(expr.shape):
148
150
  GenExprs[idx] = buildGenExprObj(expr[idx])
149
- return GenExprs
151
+ return GenExprs.view(MatrixExpr)
150
152
 
151
153
  else:
152
154
  assert isinstance(expr, GenExpr)
@@ -201,7 +203,7 @@ cdef class Expr:
201
203
  elif isinstance(right, MatrixExpr):
202
204
  return right + left
203
205
  else:
204
- raise NotImplementedError
206
+ raise TypeError(f"Unsupported type {type(right)}")
205
207
 
206
208
  return Expr(terms)
207
209
 
@@ -218,11 +220,14 @@ cdef class Expr:
218
220
  # TypeError: Cannot convert pyscipopt.scip.SumExpr to pyscipopt.scip.Expr
219
221
  return buildGenExprObj(self) + other
220
222
  else:
221
- raise NotImplementedError
223
+ raise TypeError(f"Unsupported type {type(other)}")
222
224
 
223
225
  return self
224
226
 
225
227
  def __mul__(self, other):
228
+ if isinstance(other, MatrixExpr):
229
+ return other * self
230
+
226
231
  if _is_number(other):
227
232
  f = float(other)
228
233
  return Expr({v:f*c for v,c in self.terms.items()})
@@ -267,6 +272,19 @@ cdef class Expr:
267
272
  res *= self
268
273
  return res
269
274
 
275
+ def __rpow__(self, other):
276
+ """
277
+ Implements base**x as scip.exp(x * scip.log(base)).
278
+ Note: base must be positive.
279
+ """
280
+ if _is_number(other):
281
+ base = float(other)
282
+ if base <= 0.0:
283
+ raise ValueError("Base of a**x must be positive, as expression is reformulated to scip.exp(x * scip.log(a)); got %g" % base)
284
+ return exp(self * log(base))
285
+ else:
286
+ raise TypeError(f"Unsupported base type {type(other)} for exponentiation.")
287
+
270
288
  def __neg__(self):
271
289
  return Expr({v:-c for v,c in self.terms.items()})
272
290
 
@@ -334,31 +352,31 @@ cdef class ExprCons:
334
352
  def __richcmp__(self, other, op):
335
353
  '''turn it into a constraint'''
336
354
  if op == 1: # <=
337
- if not self._rhs is None:
338
- raise TypeError('ExprCons already has upper bound')
339
- assert not self._lhs is None
355
+ if not self._rhs is None:
356
+ raise TypeError('ExprCons already has upper bound')
357
+ assert not self._lhs is None
340
358
 
341
- if not _is_number(other):
342
- raise TypeError('Ranged ExprCons is not well defined!')
359
+ if not _is_number(other):
360
+ raise TypeError('Ranged ExprCons is not well defined!')
343
361
 
344
- return ExprCons(self.expr, lhs=self._lhs, rhs=float(other))
362
+ return ExprCons(self.expr, lhs=self._lhs, rhs=float(other))
345
363
  elif op == 5: # >=
346
- if not self._lhs is None:
347
- raise TypeError('ExprCons already has lower bound')
348
- assert self._lhs is None
349
- assert not self._rhs is None
364
+ if not self._lhs is None:
365
+ raise TypeError('ExprCons already has lower bound')
366
+ assert self._lhs is None
367
+ assert not self._rhs is None
350
368
 
351
- if not _is_number(other):
352
- raise TypeError('Ranged ExprCons is not well defined!')
369
+ if not _is_number(other):
370
+ raise TypeError('Ranged ExprCons is not well defined!')
353
371
 
354
- return ExprCons(self.expr, lhs=float(other), rhs=self._rhs)
372
+ return ExprCons(self.expr, lhs=float(other), rhs=self._rhs)
355
373
  else:
356
- raise TypeError
374
+ raise NotImplementedError("Ranged ExprCons can only support with '<=' or '>='.")
357
375
 
358
376
  def __repr__(self):
359
377
  return 'ExprCons(%s, %s, %s)' % (self.expr, self._lhs, self._rhs)
360
378
 
361
- def __nonzero__(self):
379
+ def __bool__(self):
362
380
  '''Make sure that equality of expressions is not asserted with =='''
363
381
 
364
382
  msg = """Can't evaluate constraints as booleans.
@@ -420,6 +438,9 @@ cdef class GenExpr:
420
438
  return UnaryExpr(Operator.fabs, self)
421
439
 
422
440
  def __add__(self, other):
441
+ if isinstance(other, MatrixExpr):
442
+ return other + self
443
+
423
444
  left = buildGenExprObj(self)
424
445
  right = buildGenExprObj(other)
425
446
  ans = SumExpr()
@@ -475,6 +496,9 @@ cdef class GenExpr:
475
496
  # return self
476
497
 
477
498
  def __mul__(self, other):
499
+ if isinstance(other, MatrixExpr):
500
+ return other * self
501
+
478
502
  left = buildGenExprObj(self)
479
503
  right = buildGenExprObj(other)
480
504
  ans = ProdExpr()
@@ -533,11 +557,24 @@ cdef class GenExpr:
533
557
 
534
558
  return ans
535
559
 
560
+ def __rpow__(self, other):
561
+ """
562
+ Implements base**x as scip.exp(x * scip.log(base)).
563
+ Note: base must be positive.
564
+ """
565
+ if _is_number(other):
566
+ base = float(other)
567
+ if base <= 0.0:
568
+ raise ValueError("Base of a**x must be positive, as expression is reformulated to scip.exp(x * scip.log(a)); got %g" % base)
569
+ return exp(self * log(base))
570
+ else:
571
+ raise TypeError(f"Unsupported base type {type(other)} for exponentiation.")
572
+
536
573
  #TODO: ipow, idiv, etc
537
574
  def __truediv__(self,other):
538
575
  divisor = buildGenExprObj(other)
539
576
  # we can't divide by 0
540
- if divisor.getOp() == Operator.const and divisor.number == 0.0:
577
+ if isinstance(divisor, GenExpr) and divisor.getOp() == Operator.const and divisor.number == 0.0:
541
578
  raise ZeroDivisionError("cannot divide by 0")
542
579
  return self * divisor**(-1)
543
580
 
@@ -58,7 +58,8 @@ cdef class LP:
58
58
  """Adds a single column to the LP.
59
59
 
60
60
  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.
62
63
  obj -- objective coefficient (default 0.0)
63
64
  lb -- lower bound (default 0.0)
64
65
  ub -- upper bound (default infinity)
@@ -85,7 +86,8 @@ cdef class LP:
85
86
  """Adds multiple columns to the LP.
86
87
 
87
88
  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.
89
91
  objs -- objective coefficient (default 0.0)
90
92
  lbs -- lower bounds (default 0.0)
91
93
  ubs -- upper bounds (default infinity)
@@ -147,7 +149,8 @@ cdef class LP:
147
149
  """Adds a single row to the LP.
148
150
 
149
151
  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.
151
154
  lhs -- left-hand side of the row (default 0.0)
152
155
  rhs -- right-hand side of the row (default infinity)
153
156
  """
@@ -172,7 +175,8 @@ cdef class LP:
172
175
  """Adds multiple rows to the LP.
173
176
 
174
177
  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.
176
180
  lhss -- left-hand side of the row (default 0.0)
177
181
  rhss -- right-hand side of the row (default infinity)
178
182
  """
@@ -0,0 +1,112 @@
1
+ """
2
+ # TODO Cythonize things. Improve performance.
3
+ # TODO Add tests
4
+ """
5
+
6
+ import numpy as np
7
+ from typing import Union
8
+
9
+
10
+ def _is_number(e):
11
+ try:
12
+ f = float(e)
13
+ return True
14
+ except ValueError: # for malformed strings
15
+ return False
16
+ except TypeError: # for other types (Variable, Expr)
17
+ return False
18
+
19
+
20
+ def _matrixexpr_richcmp(self, other, op):
21
+ def _richcmp(self, other, op):
22
+ if op == 1: # <=
23
+ return self.__le__(other)
24
+ elif op == 5: # >=
25
+ return self.__ge__(other)
26
+ elif op == 2: # ==
27
+ return self.__eq__(other)
28
+ else:
29
+ raise NotImplementedError("Can only support constraints with '<=', '>=', or '=='.")
30
+
31
+ if _is_number(other) or isinstance(other, Expr):
32
+ res = np.empty(self.shape, dtype=object)
33
+ res.flat = [_richcmp(i, other, op) for i in self.flat]
34
+
35
+ elif isinstance(other, np.ndarray):
36
+ out = np.broadcast(self, other)
37
+ res = np.empty(out.shape, dtype=object)
38
+ res.flat = [_richcmp(i, j, op) for i, j in out]
39
+
40
+ else:
41
+ raise TypeError(f"Unsupported type {type(other)}")
42
+
43
+ return res.view(MatrixExprCons)
44
+
45
+
46
+ class MatrixExpr(np.ndarray):
47
+ def sum(self, **kwargs):
48
+ """
49
+ Based on `numpy.ndarray.sum`, but returns a scalar if `axis=None`.
50
+ This is useful for matrix expressions to compare with a matrix or a scalar.
51
+ """
52
+
53
+ if kwargs.get("axis") is None:
54
+ # Speed up `.sum()` #1070
55
+ return quicksum(self.flat)
56
+ return super().sum(**kwargs)
57
+
58
+ def __le__(self, other: Union[float, int, "Expr", np.ndarray, "MatrixExpr"]) -> MatrixExprCons:
59
+ return _matrixexpr_richcmp(self, other, 1)
60
+
61
+ def __ge__(self, other: Union[float, int, "Expr", np.ndarray, "MatrixExpr"]) -> MatrixExprCons:
62
+ return _matrixexpr_richcmp(self, other, 5)
63
+
64
+ def __eq__(self, other: Union[float, int, "Expr", np.ndarray, "MatrixExpr"]) -> MatrixExprCons:
65
+ return _matrixexpr_richcmp(self, other, 2)
66
+
67
+ def __add__(self, other):
68
+ return super().__add__(other).view(MatrixExpr)
69
+
70
+ def __iadd__(self, other):
71
+ return super().__iadd__(other).view(MatrixExpr)
72
+
73
+ def __mul__(self, other):
74
+ return super().__mul__(other).view(MatrixExpr)
75
+
76
+ def __truediv__(self, other):
77
+ return super().__truediv__(other).view(MatrixExpr)
78
+
79
+ def __rtruediv__(self, other):
80
+ return super().__rtruediv__(other).view(MatrixExpr)
81
+
82
+ def __pow__(self, other):
83
+ return super().__pow__(other).view(MatrixExpr)
84
+
85
+ def __sub__(self, other):
86
+ return super().__sub__(other).view(MatrixExpr)
87
+
88
+ def __radd__(self, other):
89
+ return super().__radd__(other).view(MatrixExpr)
90
+
91
+ def __rmul__(self, other):
92
+ return super().__rmul__(other).view(MatrixExpr)
93
+
94
+ def __rsub__(self, other):
95
+ return super().__rsub__(other).view(MatrixExpr)
96
+
97
+ def __matmul__(self, other):
98
+ return super().__matmul__(other).view(MatrixExpr)
99
+
100
+ class MatrixGenExpr(MatrixExpr):
101
+ pass
102
+
103
+ class MatrixExprCons(np.ndarray):
104
+
105
+ def __le__(self, other: Union[float, int, np.ndarray]) -> MatrixExprCons:
106
+ return _matrixexpr_richcmp(self, other, 1)
107
+
108
+ def __ge__(self, other: Union[float, int, np.ndarray]) -> MatrixExprCons:
109
+ return _matrixexpr_richcmp(self, other, 5)
110
+
111
+ def __eq__(self, other):
112
+ raise NotImplementedError("Cannot compare MatrixExprCons with '=='.")
@@ -87,8 +87,12 @@ cdef SCIP_RETCODE PyNodeselSelect (SCIP* scip, SCIP_NODESEL* nodesel, SCIP_NODE*
87
87
  nodeseldata = SCIPnodeselGetData(nodesel)
88
88
  PyNodesel = <Nodesel>nodeseldata
89
89
  result_dict = PyNodesel.nodeselect()
90
- selected_node = <Node>(result_dict.get("selnode", None))
91
- selnode[0] = selected_node.scip_node
90
+ selected_node = <Node>result_dict.get("selnode", None)
91
+ if selected_node == None:
92
+ selnode[0] = NULL
93
+ else:
94
+ selnode[0] = selected_node.scip_node
95
+
92
96
  return SCIP_OKAY
93
97
 
94
98
  cdef int PyNodeselComp (SCIP* scip, SCIP_NODESEL* nodesel, SCIP_NODE* node1, SCIP_NODE* node2) noexcept with gil:
File without changes