CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyscipopt

Python interface and modeling environment for SCIP optimization solver

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

parameters.mddocs/

Parameters and Configuration

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.

Capabilities

Parameter Management

Core functions for getting, setting, and managing solver parameters.

def setParam(self, name, value):
    """
    Set a solver parameter.
    
    Parameters:
    - name (str): Parameter name (hierarchical with '/' separators)
    - value: Parameter value (type depends on parameter)
    
    Examples:
    - "limits/time": float (time limit in seconds)
    - "limits/nodes": int (node limit) 
    - "numerics/feastol": float (feasibility tolerance)
    - "branching/scorefunc": str (scoring function)
    """

def getParam(self, name):
    """
    Get current value of a solver parameter.
    
    Parameters:
    - name (str): Parameter name
    
    Returns:
    Parameter value (int, float, str, or bool depending on parameter type)
    """

def getParams(self):
    """
    Get all parameters and their current values.
    
    Returns:
    dict: Dictionary mapping parameter names to values
    """

def setParams(self, params):
    """
    Set multiple parameters at once.
    
    Parameters:
    - params (dict): Dictionary mapping parameter names to values
    """

def resetParam(self, name):
    """
    Reset parameter to its default value.
    
    Parameters:
    - name (str): Parameter name to reset
    """

def resetParams(self):
    """Reset all parameters to their default values."""

def readParams(self, file):
    """
    Read parameters from file.
    
    Parameters:
    - file (str): Path to parameter file (.set format)
    """

def writeParams(self, filename='param.set', comments=True, changed=True):
    """
    Write parameters to file.
    
    Parameters:
    - filename (str): Output filename
    - comments (bool): Include parameter descriptions as comments
    - changed (bool): Only write parameters that differ from defaults
    """

Parameter Emphasis Settings

Predefined parameter configurations for different solving strategies.

def setEmphasis(self, emphasis, quiet=True):
    """
    Set parameter emphasis for different solving strategies.
    
    Parameters:
    - emphasis: Emphasis setting from SCIP_PARAMEMPHASIS
        'DEFAULT': Balanced default settings
        'CPSOLVER': Settings for constraint programming
        'EASYCIP': Settings for easy instances
        'FEASIBILITY': Focus on finding feasible solutions quickly
        'HARDLP': Settings for hard linear programming relaxations
        'OPTIMALITY': Focus on proving optimality
        'COUNTER': Settings for adversarial/counter examples
        'PHASEFEAS': Phase 1: focus on feasibility
        'PHASEIMPROVE': Phase 2: improve solution quality
        'PHASEPROOF': Phase 3: prove optimality
    - quiet (bool): Suppress output during emphasis setting
    """

# Parameter emphasis constants
SCIP_PARAMEMPHASIS = {
    'DEFAULT', 'CPSOLVER', 'EASYCIP', 'FEASIBILITY', 
    'HARDLP', 'OPTIMALITY', 'COUNTER', 'PHASEFEAS', 
    'PHASEIMPROVE', 'PHASEPROOF'
}

Time and Resource Limits

Parameters controlling computational resource usage.

# Time limits
def setParam(self, "limits/time", seconds):
    """Set time limit in seconds (float)"""

def setParam(self, "limits/abortfactor", factor):
    """Set abort factor for early termination (float, default: 1e-6)"""

# Node limits  
def setParam(self, "limits/nodes", count):
    """Set maximum number of branch-and-bound nodes (int, default: -1 = unlimited)"""

def setParam(self, "limits/totalnodes", count):
    """Set total node limit across all runs (int)"""

def setParam(self, "limits/stallnodes", count):
    """Set stalling node limit (int, default: -1)"""

# Memory limits
def setParam(self, "limits/memory", megabytes):
    """Set memory limit in megabytes (float, default: 8796093022208.0)"""

# Solution limits
def setParam(self, "limits/solutions", count):
    """Set maximum number of solutions to find (int, default: -1)"""

def setParam(self, "limits/bestsol", count):
    """Set limit on number of best solutions (int, default: -1)"""

# Gap limits
def setParam(self, "limits/gap", gap):
    """Set relative gap limit for termination (float, default: 0.0)"""

def setParam(self, "limits/absgap", gap):
    """Set absolute gap limit for termination (float, default: 0.0)"""

Numerical Tolerances

Parameters controlling numerical precision and feasibility checking.

# Feasibility tolerances
def setParam(self, "numerics/feastol", tolerance):
    """Set feasibility tolerance (float, default: 1e-6)"""

def setParam(self, "numerics/lpfeastol", tolerance):
    """Set LP feasibility tolerance (float, default: 1e-6)"""

def setParam(self, "numerics/dualfeastol", tolerance):
    """Set dual feasibility tolerance (float, default: 1e-7)"""

# Optimality tolerances  
def setParam(self, "numerics/epsilon", tolerance):
    """Set epsilon for equality comparisons (float, default: 1e-9)"""

def setParam(self, "numerics/sumepsilon", tolerance):
    """Set epsilon for sum comparisons (float, default: 1e-6)"""

# Integrality tolerance
def setParam(self, "numerics/integralityTol", tolerance):
    """Set integrality tolerance (float, default: 1e-6)"""

# Infinity value
def setParam(self, "numerics/infinity", value):
    """Set infinity value (float, default: 1e20)"""

Branching Parameters

Parameters controlling branching strategies and variable selection.

# Branching rules
def setParam(self, "branching/scorefunc", function):
    """
    Set branching score function (str):
    - 's': sum of scores
    - 'p': product of scores  
    - 'q': quotient of scores
    """

def setParam(self, "branching/scorefactor", factor):
    """Set branching score factor (float, default: 0.167)"""

def setParam(self, "branching/preferbinary", prefer):
    """Prefer branching on binary variables (bool, default: False)"""

# Variable selection
def setParam(self, "branching/relpscost/conflictweight", weight):
    """Set conflict weight in reliable pseudocost branching (float)"""

def setParam(self, "branching/relpscost/minreliable", count):
    """Set minimum reliable count (int, default: 1)"""

Cutting Planes Parameters

Parameters controlling cutting plane generation and separation.

# General cutting settings
def setParam(self, "separating/maxrounds", rounds):
    """Set maximum separation rounds per node (int, default: -1)"""

def setParam(self, "separating/maxroundsroot", rounds):
    """Set maximum separation rounds at root (int, default: -1)"""

def setParam(self, "separating/maxcuts", cuts):
    """Set maximum cuts per separation round (int, default: 100)"""

def setParam(self, "separating/maxcutsroot", cuts):
    """Set maximum cuts per round at root (int, default: 2000)"""

# Specific cut types
def setParam(self, "separating/gomory/freq", frequency):
    """Set Gomory cut frequency (int, default: 10)"""

def setParam(self, "separating/clique/freq", frequency):
    """Set clique cut frequency (int, default: 0)"""

def setParam(self, "separating/knapsackcover/freq", frequency):
    """Set knapsack cover cut frequency (int, default: 0)"""

Presolving Parameters

Parameters controlling problem preprocessing and simplification.

# Presolving rounds
def setParam(self, "presolving/maxrounds", rounds):
    """Set maximum presolving rounds (int, default: -1)"""

def setParam(self, "presolving/maxrestarts", restarts):
    """Set maximum presolving restarts (int, default: -1)"""

# Component presolvers
def setParam(self, "presolving/components/maxintvars", count):
    """Set maximum integer variables for component detection (int)"""

def setParam(self, "presolving/dualfix/enabled", enabled):
    """Enable dual fixing presolver (bool, default: True)"""

def setParam(self, "presolving/domcol/enabled", enabled):
    """Enable dominated columns presolver (bool, default: True)"""

Heuristics Parameters

Parameters controlling primal heuristics and solution finding strategies.

# General heuristic settings
def setParam(self, "heuristics/emphasis", emphasis):
    """
    Set heuristic emphasis:
    - 'DEFAULT': balanced approach
    - 'AGGRESSIVE': more heuristic calls
    - 'FAST': fewer heuristic calls
    - 'OFF': disable heuristics
    """

# Specific heuristics
def setParam(self, "heuristics/rounding/freq", frequency):
    """Set simple rounding frequency (int, default: 1)"""

def setParam(self, "heuristics/shifting/freq", frequency):
    """Set shifting heuristic frequency (int, default: 10)"""

def setParam(self, "heuristics/localbranching/freq", frequency):
    """Set local branching frequency (int, default: -1)"""

def setParam(self, "heuristics/diving/maxdepth", depth):
    """Set maximum diving depth (int, default: -1)"""

LP Solver Parameters

Parameters for controlling the linear programming solver interface.

# LP solver selection
def setParam(self, "lp/solver", solver):
    """
    Set LP solver (str):
    - 'soplex': SoPlex (default)
    - 'cplex': IBM CPLEX
    - 'gurobi': Gurobi
    - 'clp': COIN-OR CLP
    """

# LP solving parameters
def setParam(self, "lp/pricing", pricing):
    """
    Set LP pricing strategy (str):
    - 'lpi': LP interface default
    - 'auto': automatic
    - 'dantzig': Dantzig rule
    - 'partial': partial pricing
    - 'steep': steepest edge
    - 'quicksteep': quick steepest edge
    - 'devex': devex
    """

def setParam(self, "lp/iterlim", limit):
    """Set LP iteration limit (int, default: -1)"""

def setParam(self, "lp/rootiterlim", limit):
    """Set root LP iteration limit (int, default: -1)"""

Output and Verbosity Parameters

Parameters controlling solver output and logging.

# Verbosity levels
def setParam(self, "display/verblevel", level):
    """
    Set verbosity level (int):
    - 0: quiet (errors only)
    - 1: normal (default)
    - 2: verbose  
    - 3: full
    - 4: debug
    - 5: trace
    """

# Display columns
def setParam(self, "display/freq", frequency):
    """Set display frequency for node processing (int, default: 100)"""

def setParam(self, "display/headerfreq", frequency):
    """Set header display frequency (int, default: 15)"""

# Statistics output
def setParam(self, "display/statistics", enabled):
    """Enable statistics display (bool, default: True)"""

Solver Statistics Access

Functions to access detailed solving statistics and performance information.

def getTotalTime(self):
    """Get total solving time including reading and presolving (float)"""

def getSolvingTime(self):
    """Get pure solving time excluding presolving (float)"""

def getReadingTime(self):
    """Get time spent reading problem files (float)"""

def getPresolvingTime(self):
    """Get time spent in presolving (float)"""

def getNNodes(self):
    """Get number of processed branch-and-bound nodes (int)"""

def getNTotalNodes(self):
    """Get total number of created nodes (int)"""

def getNRuns(self):
    """Get number of runs performed (int)"""

def getGap(self):
    """Get current optimality gap as percentage (float)"""

def getDepth(self):
    """Get current depth in branch-and-bound tree (int)"""

def getMaxDepth(self):
    """Get maximum depth reached (int)"""

def getDualboundRoot(self):
    """Get dual bound at root node (float)"""

def getPrimalboundRoot(self):
    """Get primal bound at root node (float)"""

def getNSols(self):
    """Get number of feasible solutions found (int)"""

def getNSolsFound(self):
    """Get total number of solutions found including infeasible (int)"""

def getNLimSolsFound(self):
    """Get number of solutions found respecting objective limit (int)"""

Usage Examples

Basic Parameter Configuration

from pyscipopt import Model

model = Model("parameter_example")

# Set time limit to 60 seconds
model.setParam("limits/time", 60.0)

# Set node limit
model.setParam("limits/nodes", 1000)

# Set gap tolerance to 1%
model.setParam("limits/gap", 0.01)

# Set verbosity level
model.setParam("display/verblevel", 2)  # Verbose output

# Check current parameter values
print(f"Time limit: {model.getParam('limits/time')}")
print(f"Gap tolerance: {model.getParam('limits/gap')}")
print(f"Verbosity: {model.getParam('display/verblevel')}")

Multiple Parameter Configuration

from pyscipopt import Model

model = Model("multiple_params")

# Set multiple parameters at once
params = {
    "limits/time": 300.0,           # 5 minutes
    "limits/gap": 0.005,            # 0.5% gap
    "limits/nodes": 10000,          # Node limit
    "numerics/feastol": 1e-7,       # Tighter feasibility tolerance
    "branching/scorefunc": 'p',     # Product scoring
    "separating/maxrounds": 5,      # Limit cutting rounds
    "display/verblevel": 1          # Normal verbosity
}

model.setParams(params)

# Verify settings
current_params = model.getParams()
for param, value in params.items():
    print(f"{param}: {current_params[param]}")

Emphasis-Based Configuration

from pyscipopt import Model, SCIP_PARAMEMPHASIS

model = Model("emphasis_example") 

# Configure for feasibility finding
model.setEmphasis(SCIP_PARAMEMPHASIS.FEASIBILITY)

# Add problem...
x = model.addVar(name="x", vtype="I", lb=0, ub=100)
y = model.addVar(name="y", vtype="I", lb=0, ub=100)

model.addCons(3*x + 2*y <= 150)
model.addCons(x + 4*y <= 200)
model.addCons(2*x + y >= 50)

model.setObjective(x + y, "maximize")

# Solve with feasibility emphasis
model.optimize()

if model.getNSols() > 0:
    print("Feasible solution found quickly!")
    
    # Switch emphasis to optimality proving
    model.setEmphasis(SCIP_PARAMEMPHASIS.OPTIMALITY)
    
    # Continue solving for better bounds
    model.optimize()

Fine-Tuning for Specific Problem Types

from pyscipopt import Model

# Configuration for hard mixed-integer programming
def configure_for_hard_MIP(model):
    """Configure parameters for difficult MIP instances"""
    
    # Increase time and node limits
    model.setParam("limits/time", 3600.0)      # 1 hour
    model.setParam("limits/nodes", 1000000)    # 1M nodes
    
    # Tighter tolerances
    model.setParam("numerics/feastol", 1e-8)
    model.setParam("numerics/integralityTol", 1e-8)
    
    # Aggressive cutting planes
    model.setParam("separating/maxroundsroot", 100)
    model.setParam("separating/maxcutsroot", 5000)
    
    # More thorough presolving
    model.setParam("presolving/maxrounds", 20)
    
    # Strong branching for better tree exploration
    model.setParam("branching/scorefunc", 'p')
    
    # More aggressive heuristics
    model.setParam("heuristics/emphasis", "AGGRESSIVE")

# Configuration for quick feasibility checking
def configure_for_quick_feasibility(model):
    """Configure for finding feasible solutions quickly"""
    
    # Short time limit
    model.setParam("limits/time", 60.0)
    
    # Looser tolerances
    model.setParam("numerics/feastol", 1e-5)
    
    # Minimal cutting planes
    model.setParam("separating/maxrounds", 1)
    
    # Quick presolving
    model.setParam("presolving/maxrounds", 3)
    
    # Focus on heuristics
    model.setParam("heuristics/emphasis", "AGGRESSIVE")
    model.setParam("heuristics/rounding/freq", 1)
    model.setParam("heuristics/shifting/freq", 1)

# Usage
model = Model("specialized_config")

# Choose configuration based on problem characteristics
problem_is_hard = True

if problem_is_hard:
    configure_for_hard_MIP(model)
else:
    configure_for_quick_feasibility(model)

# Add problem and solve...

Parameter File Management

from pyscipopt import Model

model = Model("param_files")

# Configure parameters
model.setParam("limits/time", 300.0)
model.setParam("limits/gap", 0.01)
model.setParam("display/verblevel", 2)

# Save current parameters to file
model.writeParams("my_settings.set", comments=True, changed=True)

# Create new model and load parameters
model2 = Model("param_load_test")
model2.readParams("my_settings.set")

# Verify parameters were loaded
print(f"Loaded time limit: {model2.getParam('limits/time')}")
print(f"Loaded gap: {model2.getParam('limits/gap')}")

Performance Monitoring

from pyscipopt import Model
import time

model = Model("performance_monitoring")

# Add a complex problem
n = 50
x = [[model.addVar(name=f"x_{i}_{j}", vtype="B") 
      for j in range(n)] for i in range(n)]

# Assignment constraints
for i in range(n):
    model.addCons(quicksum(x[i][j] for j in range(n)) == 1)
for j in range(n):
    model.addCons(quicksum(x[i][j] for i in range(n)) == 1)

# Objective with random costs
import random
random.seed(42)
costs = [[random.randint(1, 100) for j in range(n)] for i in range(n)]
model.setObjective(quicksum(costs[i][j] * x[i][j] 
                           for i in range(n) for j in range(n)), "minimize")

# Set parameters for monitoring
model.setParam("limits/time", 120.0)
model.setParam("display/freq", 50)    # Display every 50 nodes

# Solve and monitor
start_time = time.time()
model.optimize()
wall_time = time.time() - start_time

# Print detailed statistics
print("\n=== Solving Statistics ===")
print(f"Status: {model.getStatus()}")
print(f"Wall time: {wall_time:.2f} seconds")
print(f"SCIP total time: {model.getTotalTime():.2f} seconds")
print(f"SCIP solving time: {model.getSolvingTime():.2f} seconds")
print(f"Presolving time: {model.getPresolvingTime():.2f} seconds")
print(f"Nodes processed: {model.getNNodes()}")
print(f"Total nodes: {model.getNTotalNodes()}")
print(f"Maximum depth: {model.getMaxDepth()}")
print(f"Solutions found: {model.getNSols()}")
print(f"Gap: {model.getGap():.4%}")

if model.getStatus() == 'optimal':
    print(f"Optimal value: {model.getObjVal()}")
elif model.getNSols() > 0:
    print(f"Best value found: {model.getObjVal()}")

Dynamic Parameter Adjustment

from pyscipopt import Model, Eventhdlr, SCIP_EVENTTYPE

class ParameterAdjuster(Eventhdlr):
    """Adjust parameters dynamically during solving"""
    
    def __init__(self):
        self.nodes_processed = 0
        
    def eventexec(self, eventhdlr, event):
        """Adjust parameters based on solving progress"""
        
        if event.getType() == SCIP_EVENTTYPE.NODEBRANCHED:
            self.nodes_processed += 1
            
            # After 1000 nodes, switch to faster cutting
            if self.nodes_processed == 1000:
                self.model.setParam("separating/maxrounds", 2)
                print("Switched to faster cutting after 1000 nodes")
            
            # After 5000 nodes, reduce heuristic frequency
            elif self.nodes_processed == 5000:
                self.model.setParam("heuristics/rounding/freq", 10)
                self.model.setParam("heuristics/shifting/freq", 20)
                print("Reduced heuristic frequency after 5000 nodes")

# Usage
model = Model("dynamic_params")

# Set up problem...
n = 20
x = [model.addVar(name=f"x_{i}", vtype="I", lb=0, ub=10) for i in range(n)]
model.addCons(quicksum(x[i] for i in range(n)) <= n*5)
model.setObjective(quicksum((i+1)*x[i] for i in range(n)), "maximize")

# Include parameter adjuster
adjuster = ParameterAdjuster()
model.includeEventhdlr(adjuster, "ParamAdjuster", "Adjust parameters dynamically")

# Catch node events
model.catchEvent(SCIP_EVENTTYPE.NODEBRANCHED, adjuster)

model.optimize()

Install with Tessl CLI

npx tessl i tessl/pypi-pyscipopt

docs

core-model.md

expressions.md

index.md

math-functions.md

parameters.md

plugins.md

variables-constraints.md

tile.json