Skip to content

Commit fd2e0c6

Browse files
authored
Add setTracefile() method for structured optimization progress loggingAdd settracefile api (#1158)
* Add structured_optimization_trace recipe and tests * Add CHANGELOG entry for structured_optimization_trace * Use private class name for TraceEventhdlr to fix stubtest
1 parent 98b7e01 commit fd2e0c6

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Added automated script for generating type stubs
66
- Include parameter names in type stubs
77
- Speed up MatrixExpr.sum(axis=...) via quicksum
8+
- Added structured_optimization_trace recipe for structured optimization progress tracking
89
### Fixed
910
- all fundamental callbacks now raise an error if not implemented
1011
- Fixed the type of MatrixExpr.sum(axis=...) result from MatrixVariable to MatrixExpr.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from pyscipopt import SCIP_EVENTTYPE, Eventhdlr, Model
2+
3+
4+
def attach_structured_optimization_trace(model: Model):
5+
"""
6+
Attaches an event handler that records optimization progress in structured JSONL format.
7+
8+
Args:
9+
model: SCIP Model
10+
"""
11+
12+
class _TraceEventhdlr(Eventhdlr):
13+
def eventinit(self):
14+
self.model.catchEvent(SCIP_EVENTTYPE.BESTSOLFOUND, self)
15+
self.model.catchEvent(SCIP_EVENTTYPE.DUALBOUNDIMPROVED, self)
16+
17+
def eventexec(self, event):
18+
record = {
19+
"time": self.model.getSolvingTime(),
20+
"primalbound": self.model.getPrimalbound(),
21+
"dualbound": self.model.getDualbound(),
22+
"gap": self.model.getGap(),
23+
"nodes": self.model.getNNodes(),
24+
"nsol": self.model.getNSols(),
25+
}
26+
self.model.data["trace"].append(record)
27+
28+
if not hasattr(model, "data") or model.data is None:
29+
model.data = {}
30+
model.data["trace"] = []
31+
32+
hdlr = _TraceEventhdlr()
33+
model.includeEventhdlr(
34+
hdlr, "structured_trace", "Structured optimization trace handler"
35+
)
36+
37+
return model
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from helpers.utils import bin_packing_model
2+
3+
from pyscipopt.recipes.structured_optimization_trace import (
4+
attach_structured_optimization_trace,
5+
)
6+
7+
8+
def test_structured_optimization_trace():
9+
from random import randint
10+
11+
model = bin_packing_model(sizes=[randint(1, 40) for _ in range(120)], capacity=50)
12+
model.setParam("limits/time", 5)
13+
14+
model.data = {"test": True}
15+
model = attach_structured_optimization_trace(model)
16+
17+
assert "test" in model.data
18+
assert "trace" in model.data
19+
20+
model.optimize()
21+
22+
required_fields = {"time", "primalbound", "dualbound", "gap", "nodes", "nsol"}
23+
for record in model.data["trace"]:
24+
assert required_fields <= set(record.keys())
25+
26+
primalbounds = [r["primalbound"] for r in model.data["trace"]]
27+
for i in range(1, len(primalbounds)):
28+
assert primalbounds[i] <= primalbounds[i - 1]
29+
30+
dualbounds = [r["dualbound"] for r in model.data["trace"]]
31+
for i in range(1, len(dualbounds)):
32+
assert dualbounds[i] >= dualbounds[i - 1]

0 commit comments

Comments
 (0)