Skip to content

Commit

Permalink
add pyscipopt as source
Browse files Browse the repository at this point in the history
  • Loading branch information
jurgen-lentz committed Jul 6, 2024
1 parent 03d2add commit 7cef83f
Show file tree
Hide file tree
Showing 31 changed files with 281,066 additions and 12 deletions.
7 changes: 0 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@ before-all = [
"unzip gcg.zip",
"mv scip_install gcg"
]
before-build = [
"pip install cython",
"wget https://github.com/scipopt/pyscipopt/archive/refs/tags/v5.1.1.zip -O pyscipopt.zip",
"unzip pyscipopt.zip",
"cd PySCIPOpt-5.1.1",
"python setup.py install"
]
environment = { SCIPOPTDIR="$(pwd)/gcg", GCGOPTDIR="$(pwd)/gcg", LD_LIBRARY_PATH="$(pwd)/gcg/lib:$LD_LIBRARY_PATH", DYLD_LIBRARY_PATH="$(pwd)/gcg/lib:$DYLD_LIBRARY_PATH", PATH="$(pwd)/gcg/bin:$PATH", PKG_CONFIG_PATH="$(pwd)/gcg/lib/pkgconfig:$PKG_CONFIG_PATH", RELEASE="true"}


Expand Down
22 changes: 17 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@

use_cython = True

packagedir = os.path.join('src', 'pygcgopt')
packagedirscip = os.path.join('src', 'pyscipopt')
packagedirgcg = os.path.join('src', 'pygcgopt')

with open(os.path.join(packagedir, '__init__.py'), 'r') as initfile:
with open(os.path.join(packagedirgcg, '__init__.py'), 'r') as initfile:
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
initfile.read(), re.MULTILINE).group(1)

Expand All @@ -80,14 +81,25 @@
quit(1)
use_cython = False

if not os.path.exists(os.path.join(packagedir, 'gcg.pyx')):
if not os.path.exists(os.path.join(packagedirgcg, 'gcg.pyx')):
use_cython = False

ext = '.pyx' if use_cython else '.cpp'

extra_compile_args.append("-std=c++11")

extensions = [Extension('pygcgopt.gcg', [os.path.join(packagedir, 'gcg'+ext)],
on_github_actions = os.getenv('GITHUB_ACTIONS') == 'true'
release_mode = os.getenv('RELEASE') == 'true'
compile_with_line_tracing = on_github_actions and not release_mode

extensions = [Extension("pyscipopt.scip", [os.path.join(packagedirscip, f"scip{ext}")],
include_dirs=includedirs,
library_dirs=[sciplibdir],
libraries=[sciplibname],
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
define_macros= [("CYTHON_TRACE_NOGIL", 1), ("CYTHON_TRACE", 1)] if compile_with_line_tracing else []),
Extension('pygcgopt.gcg', [os.path.join(packagedirgcg, 'gcg'+ext)],
include_dirs=includedirs,
library_dirs=list(set([sciplibdir, gcglibdir])),
libraries=[sciplibname, gcglibname],
Expand Down Expand Up @@ -126,6 +138,6 @@
'pyscipopt>=5.1.0'
],
packages=['pygcgopt'],
package_dir={'pygcgopt': packagedir},
package_dir={'pygcgopt': packagedirgcg},
package_data = {'pygcgopt': ['gcg.pyx', 'gcg.pxd', '*.pxi', 'gcg/lib/*']}
)
21 changes: 21 additions & 0 deletions src/pyscipopt/Multidict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
##@file Multidict.py
#@brief Implementation of Multidictionaries
def multidict(D):
'''creates a multidictionary'''
keys = list(D.keys())
if len(keys) == 0:
return [[]]
try:
N = len(D[keys[0]])
islist = True
except:
N = 1
islist = False
dlist = [dict() for d in range(N)]
for k in keys:
if islist:
for i in range(N):
dlist[i][k] = D[k][i]
else:
dlist[0][k] = D[k]
return [keys]+dlist
47 changes: 47 additions & 0 deletions src/pyscipopt/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from ._version import __version__

# required for Python 3.8 on Windows
import os
if hasattr(os, 'add_dll_directory'):
if os.getenv('SCIPOPTDIR'):
os.add_dll_directory(os.path.join(os.getenv('SCIPOPTDIR').strip('"'), 'bin'))

# export user-relevant objects:
from pyscipopt.Multidict import multidict
from pyscipopt.scip import Model
from pyscipopt.scip import Variable
from pyscipopt.scip import Constraint
from pyscipopt.scip import Benders
from pyscipopt.scip import Benderscut
from pyscipopt.scip import Branchrule
from pyscipopt.scip import Nodesel
from pyscipopt.scip import Conshdlr
from pyscipopt.scip import Eventhdlr
from pyscipopt.scip import Heur
from pyscipopt.scip import Presol
from pyscipopt.scip import Pricer
from pyscipopt.scip import Prop
from pyscipopt.scip import Reader
from pyscipopt.scip import Sepa
from pyscipopt.scip import LP
from pyscipopt.scip import Expr
from pyscipopt.scip import quicksum
from pyscipopt.scip import quickprod
from pyscipopt.scip import exp
from pyscipopt.scip import log
from pyscipopt.scip import sqrt
from pyscipopt.scip import sin
from pyscipopt.scip import cos
from pyscipopt.scip import PY_SCIP_RESULT as SCIP_RESULT
from pyscipopt.scip import PY_SCIP_PARAMSETTING as SCIP_PARAMSETTING
from pyscipopt.scip import PY_SCIP_PARAMEMPHASIS as SCIP_PARAMEMPHASIS
from pyscipopt.scip import PY_SCIP_STATUS as SCIP_STATUS
from pyscipopt.scip import PY_SCIP_STAGE as SCIP_STAGE
from pyscipopt.scip import PY_SCIP_PROPTIMING as SCIP_PROPTIMING
from pyscipopt.scip import PY_SCIP_PRESOLTIMING as SCIP_PRESOLTIMING
from pyscipopt.scip import PY_SCIP_HEURTIMING as SCIP_HEURTIMING
from pyscipopt.scip import PY_SCIP_EVENTTYPE as SCIP_EVENTTYPE
from pyscipopt.scip import PY_SCIP_LPSOLSTAT as SCIP_LPSOLSTAT
from pyscipopt.scip import PY_SCIP_BRANCHDIR as SCIP_BRANCHDIR
from pyscipopt.scip import PY_SCIP_BENDERSENFOTYPE as SCIP_BENDERSENFOTYPE
from pyscipopt.scip import PY_SCIP_ROWORIGINTYPE as SCIP_ROWORIGINTYPE
1 change: 1 addition & 0 deletions src/pyscipopt/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = '5.1.1'
212 changes: 212 additions & 0 deletions src/pyscipopt/benders.pxi
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
##@file benders.pxi
#@brief Base class of the Benders decomposition Plugin
cdef class Benders:
cdef public Model model
cdef public str name
cdef SCIP_BENDERS* _benders

def bendersfree(self):
'''calls destructor and frees memory of Benders decomposition '''
pass

def bendersinit(self):
'''initializes Benders deconposition'''
pass

def bendersexit(self):
'''calls exit method of Benders decomposition'''
pass

def bendersinitpre(self):
'''informs the Benders decomposition that the presolving process is being started '''
pass

def bendersexitpre(self):
'''informs the Benders decomposition that the presolving process has been completed'''
pass

def bendersinitsol(self):
'''informs Benders decomposition that the branch and bound process is being started '''
pass

def bendersexitsol(self):
'''informs Benders decomposition that the branch and bound process data is being freed'''
pass

def benderscreatesub(self, probnumber):
'''creates the subproblems and registers it with the Benders decomposition struct '''
print("python error in benderscreatesub: this method needs to be implemented")
return {}

def benderspresubsolve(self, solution, enfotype, checkint):
'''sets the pre subproblem solve callback of Benders decomposition '''
return {}

def benderssolvesubconvex(self, solution, probnumber, onlyconvex):
'''sets convex solve callback of Benders decomposition'''
return {}

def benderssolvesub(self, solution, probnumber):
'''sets solve callback of Benders decomposition '''
return {}

def benderspostsolve(self, solution, enfotype, mergecandidates, npriomergecands, checkint, infeasible):
'''sets post-solve callback of Benders decomposition '''
return {}

def bendersfreesub(self, probnumber):
'''frees the subproblems'''
pass

def bendersgetvar(self, variable, probnumber):
'''Returns the corresponding master or subproblem variable for the given variable. This provides a call back for the variable mapping between the master and subproblems. '''
print("python error in bendersgetvar: this method needs to be implemented")
return {}

# local helper functions for the interface
cdef Variable getPyVar(SCIP_VAR* var):
cdef SCIP_VARDATA* vardata
vardata = SCIPvarGetData(var)
return <Variable>vardata


cdef SCIP_RETCODE PyBendersCopy (SCIP* scip, SCIP_BENDERS* benders, SCIP_Bool threadsafe) noexcept with gil:
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersFree (SCIP* scip, SCIP_BENDERS* benders) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.bendersfree()
Py_DECREF(PyBenders)
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersInit (SCIP* scip, SCIP_BENDERS* benders) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.bendersinit()
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersExit (SCIP* scip, SCIP_BENDERS* benders) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.bendersexit()
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersInitpre (SCIP* scip, SCIP_BENDERS* benders) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.bendersinitpre()
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersExitpre (SCIP* scip, SCIP_BENDERS* benders) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.bendersexitpre()
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersInitsol (SCIP* scip, SCIP_BENDERS* benders) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.bendersinitsol()
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersExitsol (SCIP* scip, SCIP_BENDERS* benders) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.bendersexitsol()
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersCreatesub (SCIP* scip, SCIP_BENDERS* benders, int probnumber) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.benderscreatesub(probnumber)
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersPresubsolve (SCIP* scip, SCIP_BENDERS* benders, SCIP_SOL* sol, SCIP_BENDERSENFOTYPE type, SCIP_Bool checkint, SCIP_Bool* infeasible, SCIP_Bool* auxviol, SCIP_Bool* skipsolve, SCIP_RESULT* result) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
if sol == NULL:
solution = None
else:
solution = Solution.create(scip, sol)
enfotype = type
result_dict = PyBenders.benderspresubsolve(solution, enfotype, checkint)
infeasible[0] = result_dict.get("infeasible", False)
auxviol[0] = result_dict.get("auxviol", False)
skipsolve[0] = result_dict.get("skipsolve", False)
result[0] = result_dict.get("result", <SCIP_RESULT>result[0])
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersSolvesubconvex (SCIP* scip, SCIP_BENDERS* benders, SCIP_SOL* sol, int probnumber, SCIP_Bool onlyconvex, SCIP_Real* objective, SCIP_RESULT* result) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
if sol == NULL:
solution = None
else:
solution = Solution.create(scip, sol)
result_dict = PyBenders.benderssolvesubconvex(solution, probnumber, onlyconvex)
objective[0] = result_dict.get("objective", 1e+20)
result[0] = result_dict.get("result", <SCIP_RESULT>result[0])
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersSolvesub (SCIP* scip, SCIP_BENDERS* benders, SCIP_SOL* sol, int probnumber, SCIP_Real* objective, SCIP_RESULT* result) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
if sol == NULL:
solution = None
else:
solution = Solution.create(scip, sol)
result_dict = PyBenders.benderssolvesub(solution, probnumber)
objective[0] = result_dict.get("objective", 1e+20)
result[0] = result_dict.get("result", <SCIP_RESULT>result[0])
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersPostsolve (SCIP* scip, SCIP_BENDERS* benders, SCIP_SOL* sol,
SCIP_BENDERSENFOTYPE type, int* mergecands, int npriomergecands, int nmergecands, SCIP_Bool checkint,
SCIP_Bool infeasible, SCIP_Bool* merged) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
if sol == NULL:
solution = None
else:
solution = Solution.create(scip, sol)
enfotype = type
mergecandidates = []
for i in range(nmergecands):
mergecandidates.append(mergecands[i])
result_dict = PyBenders.benderspostsolve(solution, enfotype, mergecandidates, npriomergecands, checkint, infeasible)
merged[0] = result_dict.get("merged", False)
return SCIP_OKAY

cdef SCIP_RETCODE PyBendersFreesub (SCIP* scip, SCIP_BENDERS* benders, int probnumber) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyBenders.bendersfreesub(probnumber)
return SCIP_OKAY

#TODO: Really need to ask about the passing and returning of variables
cdef SCIP_RETCODE PyBendersGetvar (SCIP* scip, SCIP_BENDERS* benders, SCIP_VAR* var, SCIP_VAR** mappedvar, int probnumber) noexcept with gil:
cdef SCIP_BENDERSDATA* bendersdata
bendersdata = SCIPbendersGetData(benders)
PyBenders = <Benders>bendersdata
PyVar = getPyVar(var)
result_dict = PyBenders.bendersgetvar(PyVar, probnumber)
mappedvariable = <Variable>(result_dict.get("mappedvar", None))
if mappedvariable is None:
mappedvar[0] = NULL
else:
mappedvar[0] = mappedvariable.scip_var
return SCIP_OKAY
Loading

0 comments on commit 7cef83f

Please sign in to comment.