Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SAS API interface #729

Merged
merged 14 commits into from
Nov 1, 2024
65 changes: 31 additions & 34 deletions pulp/apis/sas_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,6 @@ def available(self):
"""True if SAS94 is available."""
return False

def sasAvailable(self):
return False

def actualSolve(self, lp, callback=None):
"""Solves a well-formulated lp problem."""
raise PulpSolverError("SAS94 : Not Available")
Expand Down Expand Up @@ -227,24 +224,21 @@ def __init__(
**solverParams,
)

# Connect to saspy
# Try to connect to saspy, if this fails, don't throw the error here.
# Instead we return False on available() to be consistent with
# other interfaces.
self.sas = None
try:
self.sas = saspy.SASsession(**self._saspy_options)
bolyu marked this conversation as resolved.
Show resolved Hide resolved
except:
raise PulpSolverError(
"SAS94: Cannot connect to a SAS session. Try using using the cfgfile option."
)
except Exception:
pass

def __del__(self):
if self.sas:
self.sas.endsas()

def available(self):
"""True if SAS94 is available."""
return True

def sasAvailable(self):
if self.sas:
return True
else:
Expand All @@ -254,8 +248,11 @@ def actualSolve(self, lp):
"""Solve a well formulated lp problem"""
log.debug("Running SAS")

if not self.sasAvailable():
raise PulpSolverError("SAS94: SAS session might have timed out.")
if not self.sas:
raise PulpSolverError(
"SAS94: Cannot connect to a SAS session. Try the cfgfile option or adjust options in that file."
)

sas = self.sas
if len(lp.sos1) or len(lp.sos2):
raise PulpSolverError(
Expand Down Expand Up @@ -494,9 +491,6 @@ def available(self):
"""True if SASCAS is available."""
return False

def sasAvailable(self):
return False

def actualSolve(self, lp, callback=None):
"""Solves a well-formulated lp problem."""
raise PulpSolverError("SASCAS : Not Available")
Expand All @@ -519,6 +513,7 @@ def __init__(
:param bool warmStart: if False, no warmstart or initial primal solution provided
:param solverParams: SAS proc OPTMILP or OPTLP parameters
"""
self.cas = None

# Extract cas_options connection options
self._cas_options = {}
Expand All @@ -528,9 +523,9 @@ def __init__(
self._cas_options[option] = value

if self._cas_options == {}:
self._cas_options["hostname"] = os.environ["CAS_SERVER"]
self._cas_options["port"] = os.environ["CAS_PORT"]
self._cas_options["authinfo"] = os.environ["CAS_AUTHINFO"]
self._cas_options["hostname"] = os.getenv("CAS_SERVER")
self._cas_options["port"] = os.getenv("CAS_PORT")
self._cas_options["authinfo"] = os.getenv("CAS_AUTHINFO")

SASsolver.__init__(
self,
Expand All @@ -542,33 +537,33 @@ def __init__(
**solverParams,
)

self.cas = swat.CAS(**self._cas_options)
# Try to connect to SWAT, if this fails, don't throw the error here.
# Instead we return False on available() to be consistent with
# other interfaces.
try:
self.cas = swat.CAS(**self._cas_options)
except Exception:
pass

def __del__(self):
if self.cas:
self.cas.close()

def available(self):
return True

def sasAvailable(self):
try:
if not self.cas:
return False

with redirect_stdout(SASLogWriter(self.msg)) as self._log_writer:
# Load the optimization action set
self.cas.loadactionset("optimization")
return True
except:
if not self.cas:
return False
else:
return True

def actualSolve(self, lp):
"""Solve a well formulated lp problem"""
log.debug("Running SAS")

if not self.sasAvailable():
raise PulpSolverError("""SASCAS: Cannot connect to a CAS session.""")
if not self.cas:
raise PulpSolverError(
"SAS94: Cannot connect to a SAS session. Try the cfgfile option or adjust options in that file."
bolyu marked this conversation as resolved.
Show resolved Hide resolved
)

s = self.cas
if len(lp.sos1) or len(lp.sos2):
raise PulpSolverError(
Expand Down Expand Up @@ -603,6 +598,8 @@ def actualSolve(self, lp):

status = None
with redirect_stdout(SASLogWriter(self.msg)) as self._log_writer:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this part has many indentations and ifs. Can it be refactored so that it's easier to read? for example breaking it into other methods. re-using the code with different arguments, etc.

# Load the optimization action set
s.loadactionset("optimization")

# Used for naming the data structure in SAS.
postfix = uuid4().hex[:16]
Expand Down