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
3 changes: 2 additions & 1 deletion ipet/parsing/ReaderManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .TraceFileReader import TraceFileReader
from ipet.concepts.Manager import Manager
from ipet.concepts.IPETNode import IpetNode
from ipet.parsing.Solver import SCIPSolver, CbcSolver, XpressSolver, GurobiSolver, \
from ipet.parsing.Solver import SCIPSolver, SoPlexSolver, CbcSolver, XpressSolver, GurobiSolver, \
CplexSolver, FiberSCIPSolver, MatlabSolver, MosekSolver, MipclSolver, NuoptSolver, SasSolver, \
ConoptSolver, IpoptSolver
from ipet.misc import misc
Expand Down Expand Up @@ -71,6 +71,7 @@ def getEditableAttributes(self):

def addSolvers(self):
for s in [SCIPSolver(),
SoPlexSolver(),
CbcSolver(),
XpressSolver(),
GurobiSolver(),
Expand Down
73 changes: 73 additions & 0 deletions ipet/parsing/Solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,79 @@ def extractDualboundHistory(self, line : str):
"""
pass

class SoPlexSolver(Solver):

solverId = "SoPlex"
recognition_expr = re.compile(r"^SoPlex version ")
version_expr = re.compile(r"^SoPlex version (\S+)")
primalbound_expr = re.compile(r"^ Objective value\s+: (\S+)")
dualbound_expr = re.compile(r"^ Objective value\s+: (\S+)")
solvingtime_expr = re.compile(r"^ Solving\s+: (\S+)")
violbound_expr = re.compile(r"^ Max/sum bound\s+: (\S+)")
viollp_expr = re.compile(r"^ Max/sum row\s+: (\S+)")

githash_expr = re.compile(r"^SoPlex version .*\[[Gg]it[Hh]ash: (\S+)\]")
iterations_expr = re.compile(r"^Iterations\s+: (\d+)")
primalfeas_expr = re.compile(r"^Primal solution (feasible|infeasible)")
dualfeas_expr = re.compile(r"^Dual solution (feasible|infeasible)")

solverstatusmap = {
r"SoPlex status\s+: problem is solved \[optimal\]" : Key.SolverStatusCodes.Optimal,
r"SoPlex status\s+: problem is solved \[optimal with unscaled violations\]" : Key.SolverStatusCodes.Optimal,
r"SoPlex status\s+: problem is solved \[infeasible\]" : Key.SolverStatusCodes.Infeasible,
r"SoPlex status\s+: problem is solved \[unbounded\]" : Key.SolverStatusCodes.Unbounded,
r"SoPlex status\s+: problem is solved \[infeasible or unbounded\]" : Key.SolverStatusCodes.InfOrUnbounded,
r"SoPlex status\s+: solving aborted \[time limit reached\]" : Key.SolverStatusCodes.TimeLimit,
r"SoPlex status\s+: solving aborted \[iteration limit reached\]" : Key.SolverStatusCodes.Interrupted,
r"SoPlex status\s+: solving aborted \[objective limit reached\]" : Key.SolverStatusCodes.Interrupted,
r"SoPlex status\s+: solving aborted \[cycling\]" : Key.SolverStatusCodes.Interrupted,
r"SoPlex status\s+: error " : Key.SolverStatusCodes.Crashed,
r"SoPlex status\s+: no problem loaded" : Key.SolverStatusCodes.Readerror,
r"SoPlex status\s+: unknown" : Key.SolverStatusCodes.Crashed,
}

objsensemap = {
r"^Objective sense\s+: minimize" : Key.ObjectiveSenseCode.MINIMIZE,
r"^Objective sense\s+: maximize" : Key.ObjectiveSenseCode.MAXIMIZE,
}

codes_solved = set(
[Key.SolverStatusCodes.Optimal,
Key.SolverStatusCodes.Infeasible,
Key.SolverStatusCodes.Unbounded]
)

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

def reset(self):
Solver.reset(self)
self.primalfeasible = None
self.dualfeasible = None

def extractPrimalbound(self, line : str):
if self.primalfeasible or self.getData(Key.SolverStatus) in self.codes_solved:
Solver.extractPrimalbound(self, line)

def extractDualbound(self, line : str):
if self.dualfeasible or self.getData(Key.SolverStatus) in self.codes_solved:
Solver.extractDualbound(self, line)

def extractOptionalInformation(self, line : str):
m = self.primalfeas_expr.match(line)
if m:
self.primalfeasible = m.groups()[0] == "feasible"
m = self.dualfeas_expr.match(line)
if m:
self.dualfeasible = m.groups()[0] == "feasible"
self.extractByExpression(line, self.githash_expr, Key.GitHash, str)
self.extractByExpression(line, self.iterations_expr, "Iterations", int)

def cleanupData(self):
if self.getData(Key.SolverStatus) in (Key.SolverStatusCodes.Crashed, Key.SolverStatusCodes.Readerror):
self.deleteData(Key.PrimalBound)
self.deleteData(Key.DualBound)

class GurobiSolver(Solver):

solverId = "GUROBI"
Expand Down
53 changes: 52 additions & 1 deletion test/SolverTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'''
import unittest
import os
from ipet.parsing.Solver import SCIPSolver, GurobiSolver, CplexSolver, CbcSolver, XpressSolver, MipclSolver, \
from ipet.parsing.Solver import SCIPSolver, SoPlexSolver, GurobiSolver, CplexSolver, CbcSolver, XpressSolver, MipclSolver, \
ConoptSolver, IpoptSolver
from ipet import Key

Expand Down Expand Up @@ -605,6 +605,56 @@ class SolverTest(unittest.TestCase):
Key.SolverStatus: Key.SolverStatusCodes.MemoryLimit }, {
Key.PrimalBound: 1e+20,
Key.DualBound: 13.0} ],
"soplex800-optimal" : [ {
Key.Solver: "SoPlex",
Key.Version: "8.0.0",
Key.GitHash: "2207cfb2",
"Iterations": 1,
Key.SolvingTime: 0.0,
Key.ObjectiveSense: Key.ObjectiveSenseCode.MINIMIZE,
Key.SolverStatus: Key.SolverStatusCodes.Optimal }, {
Key.PrimalBound: 1.0,
Key.DualBound: 1.0} ],
"soplex800-infeasible" : [ {
Key.Solver: "SoPlex",
Key.Version: "8.0.0",
Key.GitHash: "2207cfb2",
"Iterations": 0,
Key.SolvingTime: 0.0,
Key.ObjectiveSense: Key.ObjectiveSenseCode.MINIMIZE,
Key.SolverStatus: Key.SolverStatusCodes.Infeasible }, {
Key.PrimalBound: 1e+100,
Key.DualBound: 1e+100} ],
"soplex800-unbounded" : [ {
Key.Solver: "SoPlex",
Key.Version: "8.0.0",
Key.GitHash: "2207cfb2",
"Iterations": 0,
Key.SolvingTime: 0.0,
Key.ObjectiveSense: Key.ObjectiveSenseCode.MINIMIZE,
Key.SolverStatus: Key.SolverStatusCodes.Unbounded }, {
Key.PrimalBound: -1e+100,
Key.DualBound: -1e+100} ],
"soplex800-primalfeasible" : [ {
Key.Solver: "SoPlex",
Key.Version: "8.0.0",
Key.GitHash: "2207cfb2",
"Iterations": 1,
Key.SolvingTime: 0.0,
Key.ObjectiveSense: Key.ObjectiveSenseCode.MAXIMIZE,
Key.SolverStatus: Key.SolverStatusCodes.Interrupted }, {
Key.PrimalBound: 1.0,
Key.DualBound: None} ],
"soplex800-dualfeasible" : [ {
Key.Solver: "SoPlex",
Key.Version: "8.0.0",
Key.GitHash: "2207cfb2",
"Iterations": 1,
Key.SolvingTime: 0.0,
Key.ObjectiveSense: Key.ObjectiveSenseCode.MINIMIZE,
Key.SolverStatus: Key.SolverStatusCodes.Interrupted }, {
Key.PrimalBound: None,
Key.DualBound: 1.0} ],
"conopt439-tutorial" : [ {
Key.Solver: "CONOPT",
Key.Version: "4.39.0",
Expand Down Expand Up @@ -731,6 +781,7 @@ class SolverTest(unittest.TestCase):

def setUp(self):
self.solvers.append([SCIPSolver(), "SCIP"])
self.solvers.append([SoPlexSolver(), "SoPlex"])
self.solvers.append([GurobiSolver(), "GUROBI"])
self.solvers.append([CplexSolver(), "CPLEX"])
self.solvers.append([CbcSolver(), "CBC"])
Expand Down
122 changes: 122 additions & 0 deletions test/data/soplex800-dualfeasible.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
SoPlex version 8.0.0 [mode: debug] [precision: 8 byte] [rational: GMP 6.3.0] [PaPILO: not available] [githash: 2207cfb2]
Copyright (c) 1996-2025 Zuse Institute Berlin (ZIB)

int:iterlimit = 1
int:simplifier = 0

Reading (real) LP file <dualfeasible.lp> . . .
Reading took 0.00 seconds.

LP has 2 rows 2 columns and 3 nonzeros.

Equilibrium scaling LP (persistent)
type | time | iters | facts | shift | viol sum | viol num | obj value
L | 0.0 | 0 | 2 | 0.00e+00 | 3.00e+00 | 2 | 0.00000000e+00
L | 0.0 | 1 | 2 | 0.00e+00 | 1.00e+00 | 2 | 1.00000000e+00
--- unscaling external solution

SoPlex status : solving aborted [iteration limit reached]
Solving time (sec) : 0.00
Iterations : 1
Objective value : 1.00000000e+00

Could not check primal solution.
Dual solution feasible in original problem (max. violation = 0.00000000e+00).

Statistics
==========

SoPlex status : solving aborted [iteration limit reached]
Original problem :
Columns : 2
boxed : 0
lower bound : 2
upper bound : 0
free : 0
Rows : 2
equal : 0
ranged : 0
lhs : 2
rhs : 0
free : 0
Nonzeros : 3
per column : 1.50000000
per row : 1.50000000
sparsity : 0.75000000
min. abs. value : 1.00000000
max. abs. value : 2.00000000
Objective sense : minimize
Solution (real) :
Objective value : 1.00000000e+00
Violations (real) :
Max/sum bound : - / -
Max/sum row : - / -
Max/sum redcost : 0.00000000e+00 / 0.00000000e+00
Max/sum dual : 0.00000000e+00 / 0.00000000e+00
Total time : 0.00
Reading : 0.00
Solving : 0.00
Preprocessing : 0.00
Simplex : 0.00
Synchronization : 0.00
Transformation : 0.00
Rational : 0.00
InitialPrecision : 0.00
ExtendedPrecision : 0.00
BoostingStep : 0.00
FpTime : 0.00
Other : 0.00
Refinements : 0
Stalling : 0
Pivoting : 0
Feasibility : 0
Unboundedness : 0
Precision boosts : 0
Stalling : 0
Pivoting : 0
Feasibility : 0
Unboundedness : 0
Iterations : 1
From scratch : 1 (100.00%)
From basis : 0 (0.00%)
Primal : 0 (0.00%)
Dual : 1 (100.00%)
Bound flips : 0
Sol. polishing : 0
First FP solve : 0
IterationsBoosted : 0
From scratch : 0
From basis : 0
Primal : 0
Dual : 0
Bound flips : 0
Sol. polishing : 0
LU factorizations : 2
Factor. frequency : 0.50 iterations per factorization
Factor. time : 0.00
LU solves : 6
Solve frequency : 6.00 solves per iteration
Solve time : 0.00
Matrix-Vector ops :
Sparse time : 0.00
calls : 0 (0.00% of iterations)
Full time : 0.00
calls : 0 (0.00% of iterations)
Colwise time : 0.00
calls : 0 (0.00% of iterations)
Unsetup time : 0.00
calls : 1 (99.01% of iterations)
Rat. factorizations : 0
Rat. factor. time : 0.00
Rat. solve time : 0.00
Rat. reconstructions: 0
Rat. rec. time : 0.00
Degeneracy :
Primal Pivots : 0
Dual Pivots : 0
Primal Candidates : 0
Dual Candidates : 0
Average Primal : 0.00
Average Dual : 0.00
Numerics :
Condition Number : 1.00000000e+00
Loading
Loading