0
# Parameters and Configuration
1
2
Comprehensive parameter system for fine-tuning solver behavior, setting limits, configuring algorithms, and accessing solver statistics. PySCIPOpt provides extensive control over SCIP's optimization process through hundreds of parameters.
3
4
## Capabilities
5
6
### Parameter Management
7
8
Core functions for getting, setting, and managing solver parameters.
9
10
```python { .api }
11
def setParam(self, name, value):
12
"""
13
Set a solver parameter.
14
15
Parameters:
16
- name (str): Parameter name (hierarchical with '/' separators)
17
- value: Parameter value (type depends on parameter)
18
19
Examples:
20
- "limits/time": float (time limit in seconds)
21
- "limits/nodes": int (node limit)
22
- "numerics/feastol": float (feasibility tolerance)
23
- "branching/scorefunc": str (scoring function)
24
"""
25
26
def getParam(self, name):
27
"""
28
Get current value of a solver parameter.
29
30
Parameters:
31
- name (str): Parameter name
32
33
Returns:
34
Parameter value (int, float, str, or bool depending on parameter type)
35
"""
36
37
def getParams(self):
38
"""
39
Get all parameters and their current values.
40
41
Returns:
42
dict: Dictionary mapping parameter names to values
43
"""
44
45
def setParams(self, params):
46
"""
47
Set multiple parameters at once.
48
49
Parameters:
50
- params (dict): Dictionary mapping parameter names to values
51
"""
52
53
def resetParam(self, name):
54
"""
55
Reset parameter to its default value.
56
57
Parameters:
58
- name (str): Parameter name to reset
59
"""
60
61
def resetParams(self):
62
"""Reset all parameters to their default values."""
63
64
def readParams(self, file):
65
"""
66
Read parameters from file.
67
68
Parameters:
69
- file (str): Path to parameter file (.set format)
70
"""
71
72
def writeParams(self, filename='param.set', comments=True, changed=True):
73
"""
74
Write parameters to file.
75
76
Parameters:
77
- filename (str): Output filename
78
- comments (bool): Include parameter descriptions as comments
79
- changed (bool): Only write parameters that differ from defaults
80
"""
81
```
82
83
### Parameter Emphasis Settings
84
85
Predefined parameter configurations for different solving strategies.
86
87
```python { .api }
88
def setEmphasis(self, emphasis, quiet=True):
89
"""
90
Set parameter emphasis for different solving strategies.
91
92
Parameters:
93
- emphasis: Emphasis setting from SCIP_PARAMEMPHASIS
94
'DEFAULT': Balanced default settings
95
'CPSOLVER': Settings for constraint programming
96
'EASYCIP': Settings for easy instances
97
'FEASIBILITY': Focus on finding feasible solutions quickly
98
'HARDLP': Settings for hard linear programming relaxations
99
'OPTIMALITY': Focus on proving optimality
100
'COUNTER': Settings for adversarial/counter examples
101
'PHASEFEAS': Phase 1: focus on feasibility
102
'PHASEIMPROVE': Phase 2: improve solution quality
103
'PHASEPROOF': Phase 3: prove optimality
104
- quiet (bool): Suppress output during emphasis setting
105
"""
106
107
# Parameter emphasis constants
108
SCIP_PARAMEMPHASIS = {
109
'DEFAULT', 'CPSOLVER', 'EASYCIP', 'FEASIBILITY',
110
'HARDLP', 'OPTIMALITY', 'COUNTER', 'PHASEFEAS',
111
'PHASEIMPROVE', 'PHASEPROOF'
112
}
113
```
114
115
### Time and Resource Limits
116
117
Parameters controlling computational resource usage.
118
119
```python { .api }
120
# Time limits
121
def setParam(self, "limits/time", seconds):
122
"""Set time limit in seconds (float)"""
123
124
def setParam(self, "limits/abortfactor", factor):
125
"""Set abort factor for early termination (float, default: 1e-6)"""
126
127
# Node limits
128
def setParam(self, "limits/nodes", count):
129
"""Set maximum number of branch-and-bound nodes (int, default: -1 = unlimited)"""
130
131
def setParam(self, "limits/totalnodes", count):
132
"""Set total node limit across all runs (int)"""
133
134
def setParam(self, "limits/stallnodes", count):
135
"""Set stalling node limit (int, default: -1)"""
136
137
# Memory limits
138
def setParam(self, "limits/memory", megabytes):
139
"""Set memory limit in megabytes (float, default: 8796093022208.0)"""
140
141
# Solution limits
142
def setParam(self, "limits/solutions", count):
143
"""Set maximum number of solutions to find (int, default: -1)"""
144
145
def setParam(self, "limits/bestsol", count):
146
"""Set limit on number of best solutions (int, default: -1)"""
147
148
# Gap limits
149
def setParam(self, "limits/gap", gap):
150
"""Set relative gap limit for termination (float, default: 0.0)"""
151
152
def setParam(self, "limits/absgap", gap):
153
"""Set absolute gap limit for termination (float, default: 0.0)"""
154
```
155
156
### Numerical Tolerances
157
158
Parameters controlling numerical precision and feasibility checking.
159
160
```python { .api }
161
# Feasibility tolerances
162
def setParam(self, "numerics/feastol", tolerance):
163
"""Set feasibility tolerance (float, default: 1e-6)"""
164
165
def setParam(self, "numerics/lpfeastol", tolerance):
166
"""Set LP feasibility tolerance (float, default: 1e-6)"""
167
168
def setParam(self, "numerics/dualfeastol", tolerance):
169
"""Set dual feasibility tolerance (float, default: 1e-7)"""
170
171
# Optimality tolerances
172
def setParam(self, "numerics/epsilon", tolerance):
173
"""Set epsilon for equality comparisons (float, default: 1e-9)"""
174
175
def setParam(self, "numerics/sumepsilon", tolerance):
176
"""Set epsilon for sum comparisons (float, default: 1e-6)"""
177
178
# Integrality tolerance
179
def setParam(self, "numerics/integralityTol", tolerance):
180
"""Set integrality tolerance (float, default: 1e-6)"""
181
182
# Infinity value
183
def setParam(self, "numerics/infinity", value):
184
"""Set infinity value (float, default: 1e20)"""
185
```
186
187
### Branching Parameters
188
189
Parameters controlling branching strategies and variable selection.
190
191
```python { .api }
192
# Branching rules
193
def setParam(self, "branching/scorefunc", function):
194
"""
195
Set branching score function (str):
196
- 's': sum of scores
197
- 'p': product of scores
198
- 'q': quotient of scores
199
"""
200
201
def setParam(self, "branching/scorefactor", factor):
202
"""Set branching score factor (float, default: 0.167)"""
203
204
def setParam(self, "branching/preferbinary", prefer):
205
"""Prefer branching on binary variables (bool, default: False)"""
206
207
# Variable selection
208
def setParam(self, "branching/relpscost/conflictweight", weight):
209
"""Set conflict weight in reliable pseudocost branching (float)"""
210
211
def setParam(self, "branching/relpscost/minreliable", count):
212
"""Set minimum reliable count (int, default: 1)"""
213
```
214
215
### Cutting Planes Parameters
216
217
Parameters controlling cutting plane generation and separation.
218
219
```python { .api }
220
# General cutting settings
221
def setParam(self, "separating/maxrounds", rounds):
222
"""Set maximum separation rounds per node (int, default: -1)"""
223
224
def setParam(self, "separating/maxroundsroot", rounds):
225
"""Set maximum separation rounds at root (int, default: -1)"""
226
227
def setParam(self, "separating/maxcuts", cuts):
228
"""Set maximum cuts per separation round (int, default: 100)"""
229
230
def setParam(self, "separating/maxcutsroot", cuts):
231
"""Set maximum cuts per round at root (int, default: 2000)"""
232
233
# Specific cut types
234
def setParam(self, "separating/gomory/freq", frequency):
235
"""Set Gomory cut frequency (int, default: 10)"""
236
237
def setParam(self, "separating/clique/freq", frequency):
238
"""Set clique cut frequency (int, default: 0)"""
239
240
def setParam(self, "separating/knapsackcover/freq", frequency):
241
"""Set knapsack cover cut frequency (int, default: 0)"""
242
```
243
244
### Presolving Parameters
245
246
Parameters controlling problem preprocessing and simplification.
247
248
```python { .api }
249
# Presolving rounds
250
def setParam(self, "presolving/maxrounds", rounds):
251
"""Set maximum presolving rounds (int, default: -1)"""
252
253
def setParam(self, "presolving/maxrestarts", restarts):
254
"""Set maximum presolving restarts (int, default: -1)"""
255
256
# Component presolvers
257
def setParam(self, "presolving/components/maxintvars", count):
258
"""Set maximum integer variables for component detection (int)"""
259
260
def setParam(self, "presolving/dualfix/enabled", enabled):
261
"""Enable dual fixing presolver (bool, default: True)"""
262
263
def setParam(self, "presolving/domcol/enabled", enabled):
264
"""Enable dominated columns presolver (bool, default: True)"""
265
```
266
267
### Heuristics Parameters
268
269
Parameters controlling primal heuristics and solution finding strategies.
270
271
```python { .api }
272
# General heuristic settings
273
def setParam(self, "heuristics/emphasis", emphasis):
274
"""
275
Set heuristic emphasis:
276
- 'DEFAULT': balanced approach
277
- 'AGGRESSIVE': more heuristic calls
278
- 'FAST': fewer heuristic calls
279
- 'OFF': disable heuristics
280
"""
281
282
# Specific heuristics
283
def setParam(self, "heuristics/rounding/freq", frequency):
284
"""Set simple rounding frequency (int, default: 1)"""
285
286
def setParam(self, "heuristics/shifting/freq", frequency):
287
"""Set shifting heuristic frequency (int, default: 10)"""
288
289
def setParam(self, "heuristics/localbranching/freq", frequency):
290
"""Set local branching frequency (int, default: -1)"""
291
292
def setParam(self, "heuristics/diving/maxdepth", depth):
293
"""Set maximum diving depth (int, default: -1)"""
294
```
295
296
### LP Solver Parameters
297
298
Parameters for controlling the linear programming solver interface.
299
300
```python { .api }
301
# LP solver selection
302
def setParam(self, "lp/solver", solver):
303
"""
304
Set LP solver (str):
305
- 'soplex': SoPlex (default)
306
- 'cplex': IBM CPLEX
307
- 'gurobi': Gurobi
308
- 'clp': COIN-OR CLP
309
"""
310
311
# LP solving parameters
312
def setParam(self, "lp/pricing", pricing):
313
"""
314
Set LP pricing strategy (str):
315
- 'lpi': LP interface default
316
- 'auto': automatic
317
- 'dantzig': Dantzig rule
318
- 'partial': partial pricing
319
- 'steep': steepest edge
320
- 'quicksteep': quick steepest edge
321
- 'devex': devex
322
"""
323
324
def setParam(self, "lp/iterlim", limit):
325
"""Set LP iteration limit (int, default: -1)"""
326
327
def setParam(self, "lp/rootiterlim", limit):
328
"""Set root LP iteration limit (int, default: -1)"""
329
```
330
331
### Output and Verbosity Parameters
332
333
Parameters controlling solver output and logging.
334
335
```python { .api }
336
# Verbosity levels
337
def setParam(self, "display/verblevel", level):
338
"""
339
Set verbosity level (int):
340
- 0: quiet (errors only)
341
- 1: normal (default)
342
- 2: verbose
343
- 3: full
344
- 4: debug
345
- 5: trace
346
"""
347
348
# Display columns
349
def setParam(self, "display/freq", frequency):
350
"""Set display frequency for node processing (int, default: 100)"""
351
352
def setParam(self, "display/headerfreq", frequency):
353
"""Set header display frequency (int, default: 15)"""
354
355
# Statistics output
356
def setParam(self, "display/statistics", enabled):
357
"""Enable statistics display (bool, default: True)"""
358
```
359
360
### Solver Statistics Access
361
362
Functions to access detailed solving statistics and performance information.
363
364
```python { .api }
365
def getTotalTime(self):
366
"""Get total solving time including reading and presolving (float)"""
367
368
def getSolvingTime(self):
369
"""Get pure solving time excluding presolving (float)"""
370
371
def getReadingTime(self):
372
"""Get time spent reading problem files (float)"""
373
374
def getPresolvingTime(self):
375
"""Get time spent in presolving (float)"""
376
377
def getNNodes(self):
378
"""Get number of processed branch-and-bound nodes (int)"""
379
380
def getNTotalNodes(self):
381
"""Get total number of created nodes (int)"""
382
383
def getNRuns(self):
384
"""Get number of runs performed (int)"""
385
386
def getGap(self):
387
"""Get current optimality gap as percentage (float)"""
388
389
def getDepth(self):
390
"""Get current depth in branch-and-bound tree (int)"""
391
392
def getMaxDepth(self):
393
"""Get maximum depth reached (int)"""
394
395
def getDualboundRoot(self):
396
"""Get dual bound at root node (float)"""
397
398
def getPrimalboundRoot(self):
399
"""Get primal bound at root node (float)"""
400
401
def getNSols(self):
402
"""Get number of feasible solutions found (int)"""
403
404
def getNSolsFound(self):
405
"""Get total number of solutions found including infeasible (int)"""
406
407
def getNLimSolsFound(self):
408
"""Get number of solutions found respecting objective limit (int)"""
409
```
410
411
## Usage Examples
412
413
### Basic Parameter Configuration
414
415
```python
416
from pyscipopt import Model
417
418
model = Model("parameter_example")
419
420
# Set time limit to 60 seconds
421
model.setParam("limits/time", 60.0)
422
423
# Set node limit
424
model.setParam("limits/nodes", 1000)
425
426
# Set gap tolerance to 1%
427
model.setParam("limits/gap", 0.01)
428
429
# Set verbosity level
430
model.setParam("display/verblevel", 2) # Verbose output
431
432
# Check current parameter values
433
print(f"Time limit: {model.getParam('limits/time')}")
434
print(f"Gap tolerance: {model.getParam('limits/gap')}")
435
print(f"Verbosity: {model.getParam('display/verblevel')}")
436
```
437
438
### Multiple Parameter Configuration
439
440
```python
441
from pyscipopt import Model
442
443
model = Model("multiple_params")
444
445
# Set multiple parameters at once
446
params = {
447
"limits/time": 300.0, # 5 minutes
448
"limits/gap": 0.005, # 0.5% gap
449
"limits/nodes": 10000, # Node limit
450
"numerics/feastol": 1e-7, # Tighter feasibility tolerance
451
"branching/scorefunc": 'p', # Product scoring
452
"separating/maxrounds": 5, # Limit cutting rounds
453
"display/verblevel": 1 # Normal verbosity
454
}
455
456
model.setParams(params)
457
458
# Verify settings
459
current_params = model.getParams()
460
for param, value in params.items():
461
print(f"{param}: {current_params[param]}")
462
```
463
464
### Emphasis-Based Configuration
465
466
```python
467
from pyscipopt import Model, SCIP_PARAMEMPHASIS
468
469
model = Model("emphasis_example")
470
471
# Configure for feasibility finding
472
model.setEmphasis(SCIP_PARAMEMPHASIS.FEASIBILITY)
473
474
# Add problem...
475
x = model.addVar(name="x", vtype="I", lb=0, ub=100)
476
y = model.addVar(name="y", vtype="I", lb=0, ub=100)
477
478
model.addCons(3*x + 2*y <= 150)
479
model.addCons(x + 4*y <= 200)
480
model.addCons(2*x + y >= 50)
481
482
model.setObjective(x + y, "maximize")
483
484
# Solve with feasibility emphasis
485
model.optimize()
486
487
if model.getNSols() > 0:
488
print("Feasible solution found quickly!")
489
490
# Switch emphasis to optimality proving
491
model.setEmphasis(SCIP_PARAMEMPHASIS.OPTIMALITY)
492
493
# Continue solving for better bounds
494
model.optimize()
495
```
496
497
### Fine-Tuning for Specific Problem Types
498
499
```python
500
from pyscipopt import Model
501
502
# Configuration for hard mixed-integer programming
503
def configure_for_hard_MIP(model):
504
"""Configure parameters for difficult MIP instances"""
505
506
# Increase time and node limits
507
model.setParam("limits/time", 3600.0) # 1 hour
508
model.setParam("limits/nodes", 1000000) # 1M nodes
509
510
# Tighter tolerances
511
model.setParam("numerics/feastol", 1e-8)
512
model.setParam("numerics/integralityTol", 1e-8)
513
514
# Aggressive cutting planes
515
model.setParam("separating/maxroundsroot", 100)
516
model.setParam("separating/maxcutsroot", 5000)
517
518
# More thorough presolving
519
model.setParam("presolving/maxrounds", 20)
520
521
# Strong branching for better tree exploration
522
model.setParam("branching/scorefunc", 'p')
523
524
# More aggressive heuristics
525
model.setParam("heuristics/emphasis", "AGGRESSIVE")
526
527
# Configuration for quick feasibility checking
528
def configure_for_quick_feasibility(model):
529
"""Configure for finding feasible solutions quickly"""
530
531
# Short time limit
532
model.setParam("limits/time", 60.0)
533
534
# Looser tolerances
535
model.setParam("numerics/feastol", 1e-5)
536
537
# Minimal cutting planes
538
model.setParam("separating/maxrounds", 1)
539
540
# Quick presolving
541
model.setParam("presolving/maxrounds", 3)
542
543
# Focus on heuristics
544
model.setParam("heuristics/emphasis", "AGGRESSIVE")
545
model.setParam("heuristics/rounding/freq", 1)
546
model.setParam("heuristics/shifting/freq", 1)
547
548
# Usage
549
model = Model("specialized_config")
550
551
# Choose configuration based on problem characteristics
552
problem_is_hard = True
553
554
if problem_is_hard:
555
configure_for_hard_MIP(model)
556
else:
557
configure_for_quick_feasibility(model)
558
559
# Add problem and solve...
560
```
561
562
### Parameter File Management
563
564
```python
565
from pyscipopt import Model
566
567
model = Model("param_files")
568
569
# Configure parameters
570
model.setParam("limits/time", 300.0)
571
model.setParam("limits/gap", 0.01)
572
model.setParam("display/verblevel", 2)
573
574
# Save current parameters to file
575
model.writeParams("my_settings.set", comments=True, changed=True)
576
577
# Create new model and load parameters
578
model2 = Model("param_load_test")
579
model2.readParams("my_settings.set")
580
581
# Verify parameters were loaded
582
print(f"Loaded time limit: {model2.getParam('limits/time')}")
583
print(f"Loaded gap: {model2.getParam('limits/gap')}")
584
```
585
586
### Performance Monitoring
587
588
```python
589
from pyscipopt import Model
590
import time
591
592
model = Model("performance_monitoring")
593
594
# Add a complex problem
595
n = 50
596
x = [[model.addVar(name=f"x_{i}_{j}", vtype="B")
597
for j in range(n)] for i in range(n)]
598
599
# Assignment constraints
600
for i in range(n):
601
model.addCons(quicksum(x[i][j] for j in range(n)) == 1)
602
for j in range(n):
603
model.addCons(quicksum(x[i][j] for i in range(n)) == 1)
604
605
# Objective with random costs
606
import random
607
random.seed(42)
608
costs = [[random.randint(1, 100) for j in range(n)] for i in range(n)]
609
model.setObjective(quicksum(costs[i][j] * x[i][j]
610
for i in range(n) for j in range(n)), "minimize")
611
612
# Set parameters for monitoring
613
model.setParam("limits/time", 120.0)
614
model.setParam("display/freq", 50) # Display every 50 nodes
615
616
# Solve and monitor
617
start_time = time.time()
618
model.optimize()
619
wall_time = time.time() - start_time
620
621
# Print detailed statistics
622
print("\n=== Solving Statistics ===")
623
print(f"Status: {model.getStatus()}")
624
print(f"Wall time: {wall_time:.2f} seconds")
625
print(f"SCIP total time: {model.getTotalTime():.2f} seconds")
626
print(f"SCIP solving time: {model.getSolvingTime():.2f} seconds")
627
print(f"Presolving time: {model.getPresolvingTime():.2f} seconds")
628
print(f"Nodes processed: {model.getNNodes()}")
629
print(f"Total nodes: {model.getNTotalNodes()}")
630
print(f"Maximum depth: {model.getMaxDepth()}")
631
print(f"Solutions found: {model.getNSols()}")
632
print(f"Gap: {model.getGap():.4%}")
633
634
if model.getStatus() == 'optimal':
635
print(f"Optimal value: {model.getObjVal()}")
636
elif model.getNSols() > 0:
637
print(f"Best value found: {model.getObjVal()}")
638
```
639
640
### Dynamic Parameter Adjustment
641
642
```python
643
from pyscipopt import Model, Eventhdlr, SCIP_EVENTTYPE
644
645
class ParameterAdjuster(Eventhdlr):
646
"""Adjust parameters dynamically during solving"""
647
648
def __init__(self):
649
self.nodes_processed = 0
650
651
def eventexec(self, eventhdlr, event):
652
"""Adjust parameters based on solving progress"""
653
654
if event.getType() == SCIP_EVENTTYPE.NODEBRANCHED:
655
self.nodes_processed += 1
656
657
# After 1000 nodes, switch to faster cutting
658
if self.nodes_processed == 1000:
659
self.model.setParam("separating/maxrounds", 2)
660
print("Switched to faster cutting after 1000 nodes")
661
662
# After 5000 nodes, reduce heuristic frequency
663
elif self.nodes_processed == 5000:
664
self.model.setParam("heuristics/rounding/freq", 10)
665
self.model.setParam("heuristics/shifting/freq", 20)
666
print("Reduced heuristic frequency after 5000 nodes")
667
668
# Usage
669
model = Model("dynamic_params")
670
671
# Set up problem...
672
n = 20
673
x = [model.addVar(name=f"x_{i}", vtype="I", lb=0, ub=10) for i in range(n)]
674
model.addCons(quicksum(x[i] for i in range(n)) <= n*5)
675
model.setObjective(quicksum((i+1)*x[i] for i in range(n)), "maximize")
676
677
# Include parameter adjuster
678
adjuster = ParameterAdjuster()
679
model.includeEventhdlr(adjuster, "ParamAdjuster", "Adjust parameters dynamically")
680
681
# Catch node events
682
model.catchEvent(SCIP_EVENTTYPE.NODEBRANCHED, adjuster)
683
684
model.optimize()
685
```