Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ipet/Key.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class SolverStatusCodes:

- found the optimal solution
- found, that the problem was infeasible
- found a locally optimal solution or a locally infeasible point (no proof of global optimality or infeasibility)
- hit a limit of memory, time or nodes,

or it could have simply been cancelled by the user
Expand All @@ -110,6 +111,8 @@ class SolverStatusCodes:
MemoryLimit = 3
NodeLimit = 4
GapLimit = 5
LocallyOptimal = 6
LocallyInfeasible = 7
Unbounded = 110
InfOrUnbounded = 120
Interrupted = 1000
Expand Down Expand Up @@ -173,6 +176,8 @@ def getWorstStatus(*args):
SolverStatusCodes.Crashed : ProblemStatusCodes.FailAbort,
SolverStatusCodes.Infeasible : ProblemStatusCodes.Ok,
SolverStatusCodes.Optimal : ProblemStatusCodes.Ok,
SolverStatusCodes.LocallyOptimal : ProblemStatusCodes.Ok,
SolverStatusCodes.LocallyInfeasible : ProblemStatusCodes.Ok,
SolverStatusCodes.Unbounded : ProblemStatusCodes.Ok,
SolverStatusCodes.InfOrUnbounded : ProblemStatusCodes.Ok,
SolverStatusCodes.TimeLimit : ProblemStatusCodes.TimeLimit,
Expand Down
6 changes: 4 additions & 2 deletions ipet/parsing/ReaderManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
from ipet.concepts.Manager import Manager
from ipet.concepts.IPETNode import IpetNode
from ipet.parsing.Solver import SCIPSolver, CbcSolver, XpressSolver, GurobiSolver, \
CplexSolver, FiberSCIPSolver, MatlabSolver, MosekSolver, MipclSolver, NuoptSolver, SasSolver
CplexSolver, FiberSCIPSolver, MatlabSolver, MosekSolver, MipclSolver, NuoptSolver, SasSolver, \
ConoptSolver
from ipet.misc import misc
# CbcSolver, CouenneSolver, \
# XpressSolver, GurobiSolver, CplexSolver
Expand Down Expand Up @@ -79,7 +80,8 @@ def addSolvers(self):
MosekSolver(),
MipclSolver(),
NuoptSolver(),
SasSolver()
SasSolver(),
ConoptSolver()
]:
self.addSolver(s)

Expand Down
92 changes: 91 additions & 1 deletion ipet/parsing/Solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class Solver():
codes_nobound = set(
[Key.SolverStatusCodes.Crashed,
Key.SolverStatusCodes.Readerror,
Key.SolverStatusCodes.Infeasible]
Key.SolverStatusCodes.Infeasible,
Key.SolverStatusCodes.LocallyInfeasible]
)

def __init__(self,
Expand Down Expand Up @@ -1097,3 +1098,92 @@ class SasSolver(Solver):

def __init__(self, **kw):
super(SasSolver, self).__init__(**kw)

class ConoptSolver(Solver):
'''Solver class for CONOPT

Data is read from the "Solving Statistics" block(s). If a log contains
several solves, status and objective are taken from the last block,
iterations and time are summed and memory is the maximum over all blocks.
'''

solverId = "CONOPT"
recognition_expr = re.compile(r"^\s*C O N O P T\s+version")
version_expr = re.compile(r"^\s*C O N O P T\s+version (\S+)")
primalbound_expr = re.compile(r"^ Objective Value\s+(\S+)")

statistics_expr = re.compile(r"^ Solving Statistics")
modelstatus_expr = re.compile(r"^ Model Status\s+(\d+)")
solverstatus_expr = re.compile(r"^ Solver Status\s+(\d+)")
iterations_expr = re.compile(r"^ Iteration Count\s+(\d+)")
time_expr = re.compile(r"^ CONOPT time Total\s+(\S+) seconds")
memmaxused_expr = re.compile(r"^ Memory: Max used =\s+(\S+) Mbytes")
memallocated_expr = re.compile(r"^ Total Allocated =\s+(\S+) Mbytes")

# GAMS model status codes (used if the solver status is 1, NORMAL COMPLETION)
modelstatusmap = {1 : Key.SolverStatusCodes.Optimal, # OPTIMAL
2 : Key.SolverStatusCodes.LocallyOptimal, # LOCALLY OPTIMAL
15 : Key.SolverStatusCodes.Optimal, # SOLVED UNIQUE
16 : Key.SolverStatusCodes.Optimal, # SOLVED
3 : Key.SolverStatusCodes.Unbounded, # UNBOUNDED
18 : Key.SolverStatusCodes.Unbounded, # UNBOUNDED - NO SOLUTION
4 : Key.SolverStatusCodes.Infeasible, # INFEASIBLE
5 : Key.SolverStatusCodes.LocallyInfeasible, # LOCALLY INFEASIBLE
19 : Key.SolverStatusCodes.Infeasible # INFEASIBLE - NO SOLUTION
}

# GAMS solver status codes, all others are treated as crashes
solverstatuscodemap = {2 : Key.SolverStatusCodes.NodeLimit, # ITERATION INTERRUPT
3 : Key.SolverStatusCodes.TimeLimit, # RESOURCE INTERRUPT
8 : Key.SolverStatusCodes.Interrupted # USER INTERRUPT
}

def __init__(self, **kw):
super(ConoptSolver, self).__init__(**kw)

def reset(self):
Solver.reset(self)
self.inStatistics = False
self.modelstatus = None

def readLine(self, line : str):
if self.statistics_expr.match(line):
self.inStatistics = True
elif self.recognition_expr.match(line):
self.inStatistics = False
self.extractVersion(line)
elif self.inStatistics:
Solver.readLine(self, line)

def extractStatus(self, line : str):
m = self.modelstatus_expr.match(line)
if m:
self.modelstatus = int(m.group(1))
return

m = self.solverstatus_expr.match(line)
if m:
solverstatus = int(m.group(1))
if solverstatus == 1:
status = self.modelstatusmap.get(self.modelstatus, Key.SolverStatusCodes.Crashed)
else:
status = self.solverstatuscodemap.get(solverstatus, Key.SolverStatusCodes.Crashed)
self.addData(Key.SolverStatus, status)

def addSum(self, line : str, expr, key : str, datatype : type = float):
m = expr.match(line)
if m:
self.addData(key, (self.getData(key) or 0) + datatype(m.group(1)))

def addMax(self, line : str, expr, key : str):
m = expr.match(line)
if m:
value = float(m.group(1))
previous = self.getData(key)
self.addData(key, value if previous is None else max(previous, value))

def extractOptionalInformation(self, line : str):
self.addSum(line, self.iterations_expr, "Iterations", int)
self.addSum(line, self.time_expr, Key.SolvingTime)
self.addMax(line, self.memmaxused_expr, "MemoryMaxUsed")
self.addMax(line, self.memallocated_expr, "MemoryAllocated")
69 changes: 68 additions & 1 deletion test/SolverTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
'''
import unittest
import os
from ipet.parsing.Solver import SCIPSolver, GurobiSolver, CplexSolver, CbcSolver, XpressSolver, MipclSolver
from ipet.parsing.Solver import SCIPSolver, GurobiSolver, CplexSolver, CbcSolver, XpressSolver, MipclSolver, \
ConoptSolver
from ipet import Key

DATADIR = os.path.join(os.path.dirname(__file__), "data")
Expand Down Expand Up @@ -604,6 +605,71 @@ class SolverTest(unittest.TestCase):
Key.SolverStatus: Key.SolverStatusCodes.MemoryLimit }, {
Key.PrimalBound: 1e+20,
Key.DualBound: 13.0} ],
"conopt439-tutorial" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
"Iterations": 5,
Key.SolverStatus: Key.SolverStatusCodes.LocallyOptimal }, {
Key.PrimalBound: 0.572942971858,
Key.SolvingTime: 0.001,
"MemoryMaxUsed": 0.02} ],
"conopt439-const01" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
"Iterations": 1,
Key.SolverStatus: Key.SolverStatusCodes.Optimal }, {
Key.PrimalBound: 15.0,
Key.SolvingTime: 0.001,
"MemoryMaxUsed": 0.02} ],
"conopt439-const12" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
"Iterations": 0,
Key.SolverStatus: Key.SolverStatusCodes.Infeasible }, {
Key.PrimalBound: 8.0,
Key.SolvingTime: 0.0,
"MemoryMaxUsed": 0.01} ],
# const12 with the model status changed to LOCALLY INFEASIBLE (no sample log reports it)
"conopt439-const12-localinf" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
"Iterations": 0,
Key.SolverStatus: Key.SolverStatusCodes.LocallyInfeasible }, {
Key.PrimalBound: 8.0,
Key.SolvingTime: 0.0,
"MemoryMaxUsed": 0.01} ],
"conopt439-largeres1" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
"Iterations": 0,
Key.SolverStatus: Key.SolverStatusCodes.Crashed }, {
Key.PrimalBound: 0.0,
Key.SolvingTime: 0.0,
"MemoryMaxUsed": 0.0} ],
"conopt439-pinadd" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
"Iterations": 36,
Key.SolverStatus: Key.SolverStatusCodes.LocallyOptimal }, {
Key.PrimalBound: 1386.235482826,
Key.SolvingTime: 0.018,
"MemoryMaxUsed": 0.21} ],
"conopt439-mono07" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
"Iterations": 6,
Key.SolverStatus: Key.SolverStatusCodes.Infeasible }, {
Key.PrimalBound: 1000000000000000.0,
Key.SolvingTime: 0.004,
"MemoryMaxUsed": 0.02} ],
"conopt439-leastsq" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
"Iterations": None,
Key.SolverStatus: Key.SolverStatusCodes.Crashed }, {
Key.PrimalBound: None,
Key.SolvingTime: None,
"MemoryMaxUsed": None} ],
}

solvers = []
Expand All @@ -615,6 +681,7 @@ def setUp(self):
self.solvers.append([CbcSolver(), "CBC"])
self.solvers.append([XpressSolver(), "XPRESS"])
self.solvers.append([MipclSolver(), "MIPCL"])
self.solvers.append([ConoptSolver(), "CONOPT"])
self.activeSolver = self.solvers[0][SOLVER]

def tearDown(self):
Expand Down
60 changes: 60 additions & 0 deletions test/data/conopt439-const01.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@


C O N O P T version 4.39.0
Copyright (C) GAMS Software GmbH
GAMS Development Corporation

Will use up to 4 threads.


** No valid license -- continue in small-scale demo mode.
Contact GAMS at sales@gams.com to purchase a license.

** Cannot open option file 'const01.opt'.

The user model has 2 constraints and 4 variables
with 6 Jacobian elements, 4 of which are nonlinear.

Iter Phase Ninf Infeasibility RGmax NSB Step InItr MX OK
0 0 5.0000000000E+00 (Input point)

The pre-triangular part of the model has 0 constraints and 3 variables.
The post-triangular part of the model has 2 constraints and 1 variables.

Preprocessed model is empty.

Iter Phase Ninf Infeasibility RGmax NSB Step InItr MX OK
0.0000000000E+00 (Full preprocessed model)
0.0000000000E+00 (After scaling)

** Feasible solution. Value of objective = 15.0000000000

Iter Phase Ninf Objective RGmax NSB Step InItr MX OK
1 4 1.5000000000E+01 0.0E+00 0

** Optimal solution. There are no superbasic variables.


CONOPT has finished optimizing.
Model status = 1
Solver status = 1
Iteration count= 1
Objective value= 15.000000000000000

Solving Statistics
------------------
Model Status 1 OPTIMAL
Solver Status 1 NORMAL COMPLETION
Iteration Count 1
Objective Value 1.500000000000E+01

CONOPT time Total 1.000E-03 seconds
of which: Function evaluations 0.00 =0.%
1st Derivative evaluations 0.00 =0.%
Interval derivative evals 0.00 =0.%

Memory: Max used = 0.02 Mbytes
Total Allocated = 0.02 Mbytes


End of const01 example. Return code= 0
56 changes: 56 additions & 0 deletions test/data/conopt439-const12-localinf.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@


C O N O P T version 4.39.0
Copyright (C) GAMS Software GmbH
GAMS Development Corporation

Will use up to 4 threads.


** No valid license -- continue in small-scale demo mode.
Contact GAMS at sales@gams.com to purchase a license.

** Cannot open option file 'const12.opt'.

The user model has 2 constraints and 3 variables
with 5 Jacobian elements, 3 of which are nonlinear.

Iter Phase Ninf Infeasibility RGmax NSB Step InItr MX OK
0 0 1.5108256238E+00 (Input point)

** An equation in the pre-triangular part of the model cannot
be solved because the infeasibility is positive after all
variables in the constraint have been moved to best bound.
Some bounds may have been derived from other constraints.


The pre-triangular part of the model has 1 constraints and 3 variables.
The post-triangular part of the model has 1 constraints and 0 variables.

** Infeasible solution. The Preprocessor has determined that the model
is infeasible.


CONOPT has finished optimizing.
Model status = 4
Solver status = 1
Iteration count= 0
Objective value= 8.0000000000000000

Solving Statistics
------------------
Model Status 5 LOCALLY INFEASIBLE
Solver Status 1 NORMAL COMPLETION
Iteration Count 0
Objective Value 8.000000000000E+00

CONOPT time Total 0.00 seconds
of which: Function evaluations 0.00 =0.%
1st Derivative evaluations 0.00 =0.%
Interval derivative evals 0.00 =0.%

Memory: Max used = 0.01 Mbytes
Total Allocated = 0.01 Mbytes


End of const12 example. Return code= 0
Loading
Loading