or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-extensions.mdcore-modeling.mddae.mddata-management.mddomain-sets.mdgdp.mdindex.mdmathematical-functions.mdmpec.mdoptimization-interface.md

mpec.mddocs/

0

# Mathematical Programming with Equilibrium Constraints

1

2

Components for modeling mathematical programs with equilibrium constraints (MPEC). MPEC problems involve optimization problems subject to constraints that are themselves defined by the solution of other optimization problems, commonly arising in game theory, economics, and engineering design.

3

4

## Capabilities

5

6

### Complementarity Constraints

7

8

Components for defining complementarity relationships between variables and constraints in equilibrium problems.

9

10

```python { .api }

11

class Complementarity:

12

"""

13

Complementarity constraint component for MPEC problems.

14

15

Represents complementarity relationships of the form:

16

0 ≤ x ⊥ f(x) ≥ 0 (x and f(x) cannot both be positive)

17

"""

18

def __init__(self, *args, **kwargs): ...

19

20

def activate(self):

21

"""Activate this complementarity constraint."""

22

23

def deactivate(self):

24

"""Deactivate this complementarity constraint."""

25

26

def is_active(self):

27

"""Check if complementarity constraint is active."""

28

29

class ComplementarityList:

30

"""

31

Complementarity constraint list for dynamic constraint creation.

32

33

Allows adding complementarity constraints dynamically during

34

model construction or solution process.

35

"""

36

def __init__(self, **kwargs): ...

37

38

def add(self, expr1, expr2):

39

"""

40

Add complementarity constraint.

41

42

Args:

43

expr1: First expression in complementarity

44

expr2: Second expression in complementarity

45

"""

46

```

47

48

### Complementarity Relationship Functions

49

50

Helper functions for defining complementarity relationships between variables and expressions.

51

52

```python { .api }

53

def complements(expr1, expr2):

54

"""

55

Define complementarity relationship between two expressions.

56

57

Creates a complementarity constraint of the form:

58

expr1 ≥ 0, expr2 ≥ 0, expr1 * expr2 = 0

59

60

Args:

61

expr1: First expression (typically variable or constraint)

62

expr2: Second expression (typically constraint or variable)

63

64

Returns:

65

Complementarity: Complementarity constraint object

66

"""

67

```

68

69

## Usage Examples

70

71

### Basic Complementarity Problem

72

73

```python

74

from pyomo.environ import *

75

from pyomo.mpec import Complementarity, complements

76

77

model = ConcreteModel()

78

79

# Variables

80

model.x = Var(bounds=(0, None)) # x ≥ 0

81

model.y = Var(bounds=(0, None)) # y ≥ 0

82

83

# Objective

84

model.obj = Objective(expr=model.x + model.y, sense=minimize)

85

86

# Complementarity constraint: x ⊥ (x + y - 1)

87

# Either x = 0 or (x + y - 1) = 0 (or both)

88

model.complementarity = Complementarity(

89

expr=complements(model.x, model.x + model.y - 1)

90

)

91

92

# Alternative syntax

93

model.comp_alt = Complementarity(

94

expr=complements(model.x >= 0, model.x + model.y - 1 >= 0)

95

)

96

```

97

98

### Variational Inequality Problem

99

100

```python

101

from pyomo.environ import *

102

from pyomo.mpec import Complementarity, complements

103

104

model = ConcreteModel()

105

106

# Decision variables

107

model.x1 = Var(bounds=(0, 10))

108

model.x2 = Var(bounds=(0, 10))

109

110

# Lagrange multipliers for bound constraints

111

model.lambda1 = Var(bounds=(0, None))

112

model.lambda2 = Var(bounds=(0, None))

113

model.mu1 = Var(bounds=(0, None))

114

model.mu2 = Var(bounds=(0, None))

115

116

# KKT conditions as complementarity constraints

117

# Stationarity: ∇f(x) - λ + μ = 0

118

model.stationarity1 = Constraint(

119

expr=2*model.x1 - model.lambda1 + model.mu1 == 0

120

)

121

model.stationarity2 = Constraint(

122

expr=2*model.x2 - model.lambda2 + model.mu2 == 0

123

)

124

125

# Complementarity for lower bounds: x ⊥ λ

126

model.comp_lower1 = Complementarity(

127

expr=complements(model.x1, model.lambda1)

128

)

129

model.comp_lower2 = Complementarity(

130

expr=complements(model.x2, model.lambda2)

131

)

132

133

# Complementarity for upper bounds: (10 - x) ⊥ μ

134

model.comp_upper1 = Complementarity(

135

expr=complements(10 - model.x1, model.mu1)

136

)

137

model.comp_upper2 = Complementarity(

138

expr=complements(10 - model.x2, model.mu2)

139

)

140

141

# Dummy objective (feasibility problem)

142

model.obj = Objective(expr=0)

143

```

144

145

### Bilevel Optimization as MPEC

146

147

```python

148

from pyomo.environ import *

149

from pyomo.mpec import Complementarity, complements

150

151

# Upper-level and lower-level variables

152

model = ConcreteModel()

153

154

# Upper-level decision variables

155

model.x = Var(bounds=(0, 10))

156

157

# Lower-level decision variables

158

model.y = Var(bounds=(0, 5))

159

160

# Lower-level Lagrange multipliers

161

model.lambda_lower = Var(bounds=(0, None))

162

model.mu_y_lower = Var(bounds=(0, None))

163

model.mu_y_upper = Var(bounds=(0, None))

164

165

# Upper-level objective

166

model.upper_obj = Objective(

167

expr=(model.x - 3)**2 + (model.y - 2)**2,

168

sense=minimize

169

)

170

171

# Lower-level KKT conditions

172

# Stationarity: ∇_y f_lower(x,y) - λ∇_y g(x,y) + μ_lower - μ_upper = 0

173

model.ll_stationarity = Constraint(

174

expr=2*(model.y - 1) - model.lambda_lower * 1 + model.mu_y_lower - model.mu_y_upper == 0

175

)

176

177

# Lower-level constraint: x + y <= 4

178

model.ll_constraint = Constraint(expr=model.x + model.y <= 4)

179

180

# Complementarity conditions for lower-level problem

181

# Primal feasibility and dual feasibility handled by bounds and constraints

182

183

# Complementary slackness: λ ⊥ (4 - x - y)

184

model.comp_ll_constraint = Complementarity(

185

expr=complements(model.lambda_lower, 4 - model.x - model.y)

186

)

187

188

# Complementarity for y bounds: y ⊥ μ_y_lower, (5-y) ⊥ μ_y_upper

189

model.comp_y_lower = Complementarity(

190

expr=complements(model.y, model.mu_y_lower)

191

)

192

model.comp_y_upper = Complementarity(

193

expr=complements(5 - model.y, model.mu_y_upper)

194

)

195

```

196

197

### Economic Equilibrium Model

198

199

```python

200

from pyomo.environ import *

201

from pyomo.mpec import Complementarity, complements

202

203

model = ConcreteModel()

204

205

# Markets

206

model.MARKETS = Set(initialize=['A', 'B', 'C'])

207

208

# Production variables (quantity produced in each market)

209

model.q = Var(model.MARKETS, bounds=(0, 100))

210

211

# Price variables

212

model.p = Var(model.MARKETS, bounds=(0, None))

213

214

# Cost parameters

215

model.marginal_cost = Param(model.MARKETS, initialize={'A': 2, 'B': 3, 'C': 4})

216

217

# Demand parameters

218

model.demand_intercept = Param(model.MARKETS, initialize={'A': 50, 'B': 40, 'C': 60})

219

model.demand_slope = Param(model.MARKETS, initialize={'A': 1, 'B': 0.8, 'C': 1.2})

220

221

# Market clearing: supply equals demand

222

def market_clearing_rule(model, i):

223

return model.q[i] == max(0, model.demand_intercept[i] - model.demand_slope[i] * model.p[i])

224

225

# Complementarity: profit maximization conditions

226

# Either q[i] = 0 or price equals marginal cost

227

def complementarity_rule(model, i):

228

return complements(

229

model.q[i],

230

model.p[i] - model.marginal_cost[i]

231

)

232

233

model.market_clearing = Constraint(model.MARKETS, rule=market_clearing_rule)

234

model.profit_max = Complementarity(model.MARKETS, rule=complementarity_rule)

235

236

# Objective (welfare maximization)

237

model.welfare = Objective(

238

expr=sum(

239

model.demand_intercept[i] * model.q[i] - 0.5 * model.demand_slope[i] * model.q[i]**2

240

- model.marginal_cost[i] * model.q[i]

241

for i in model.MARKETS

242

),

243

sense=maximize

244

)

245

```

246

247

### Solving MPEC Problems

248

249

```python

250

from pyomo.environ import *

251

from pyomo.mpec import Complementarity, complements

252

253

# Create MPEC model (using previous examples)

254

model = create_mpec_model()

255

256

# Method 1: Transform to smooth NLP using complementarity reformulation

257

from pyomo.mpec import TransformationFactory

258

259

# Smooth complementarity reformulation

260

transform = TransformationFactory('mpec.simple_nonlinear')

261

transform.apply_to(model)

262

263

solver = SolverFactory('ipopt')

264

results = solver.solve(model, tee=True)

265

266

# Method 2: Use specialized MPEC solver (if available)

267

try:

268

mpec_solver = SolverFactory('knitro_mpec') # Commercial solver

269

results = mpec_solver.solve(model, tee=True)

270

except:

271

print("MPEC solver not available, using NLP reformulation")

272

273

# Access solution

274

if results.solver.termination_condition == TerminationCondition.optimal:

275

print("Solution found:")

276

for var in model.component_objects(Var):

277

if var.is_indexed():

278

for index in var.index():

279

print(f"{var.name}[{index}] = {value(var[index])}")

280

else:

281

print(f"{var.name} = {value(var)}")

282

```

283

284

### Multi-Leader-Follower Game

285

286

```python

287

from pyomo.environ import *

288

from pyomo.mpec import Complementarity, complements

289

290

model = ConcreteModel()

291

292

# Players

293

model.LEADERS = Set(initialize=[1, 2])

294

model.FOLLOWERS = Set(initialize=[1, 2, 3])

295

296

# Leader decision variables

297

model.x = Var(model.LEADERS, bounds=(0, 10))

298

299

# Follower decision variables

300

model.y = Var(model.FOLLOWERS, bounds=(0, 5))

301

302

# Follower multipliers for their KKT conditions

303

model.lambda_f = Var(model.FOLLOWERS, bounds=(0, None))

304

model.mu_f = Var(model.FOLLOWERS, bounds=(0, None))

305

306

# Leader objectives (Stackelberg competition)

307

def leader_obj_rule(model, i):

308

return (model.x[i] - 2)**2 + sum(model.y[j] for j in model.FOLLOWERS) / len(model.FOLLOWERS)

309

310

model.leader_obj = Objective(

311

expr=sum(leader_obj_rule(model, i) for i in model.LEADERS),

312

sense=minimize

313

)

314

315

# Follower KKT conditions

316

def follower_stationarity_rule(model, j):

317

# Each follower solves: min (y_j - 1)^2 subject to sum(x_i) + y_j <= 6

318

return 2*(model.y[j] - 1) + model.lambda_f[j] - model.mu_f[j] == 0

319

320

model.follower_stationarity = Constraint(model.FOLLOWERS, rule=follower_stationarity_rule)

321

322

# Follower feasibility constraint

323

def follower_constraint_rule(model, j):

324

return sum(model.x[i] for i in model.LEADERS) + model.y[j] <= 6

325

326

model.follower_constraints = Constraint(model.FOLLOWERS, rule=follower_constraint_rule)

327

328

# Follower complementarity conditions

329

def follower_comp_constraint_rule(model, j):

330

return complements(

331

model.lambda_f[j],

332

6 - sum(model.x[i] for i in model.LEADERS) - model.y[j]

333

)

334

335

def follower_comp_bound_rule(model, j):

336

return complements(model.y[j], model.mu_f[j])

337

338

model.follower_comp_constraint = Complementarity(model.FOLLOWERS, rule=follower_comp_constraint_rule)

339

model.follower_comp_bound = Complementarity(model.FOLLOWERS, rule=follower_comp_bound_rule)

340

```