or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

atoms.mdconstraints.mderrors.mdexpressions.mdindex.mdproblems.mdsolvers.mdtransforms.md

transforms.mddocs/

0

# Transform Functions

1

2

Problem transformation utilities for advanced optimization techniques including linearization, partial optimization, and support function transformations in CVXPY.

3

4

## Capabilities

5

6

### Linearization

7

8

Linearize expressions around current variable values for successive linear programming and sensitivity analysis.

9

10

```python { .api }

11

def linearize(expr, var_id=None):

12

"""

13

Linearize expression around current variable values.

14

15

Parameters:

16

- expr: Expression to linearize

17

- var_id: Variable ID to linearize around (None for all variables)

18

19

Returns:

20

- Expression: linearized expression (affine approximation)

21

"""

22

...

23

```

24

25

Usage examples:

26

27

```python

28

import cvxpy as cp

29

import numpy as np

30

31

# Successive linear programming example

32

x = cp.Variable(2)

33

y = cp.Variable(2)

34

35

# Non-convex constraint: x[0] * y[0] + x[1] * y[1] >= 1

36

nonconvex_expr = x[0] * y[0] + x[1] * y[1]

37

38

# Initialize variables

39

x.value = np.array([1.0, 1.0])

40

y.value = np.array([0.5, 0.5])

41

42

# Solve sequence of linearized problems

43

for iteration in range(10):

44

# Linearize the non-convex expression

45

linear_approx = cp.linearize(nonconvex_expr)

46

47

# Solve linearized problem

48

objective = cp.Minimize(cp.sum_squares(x) + cp.sum_squares(y))

49

constraints = [linear_approx >= 1, x >= 0, y >= 0]

50

problem = cp.Problem(objective, constraints)

51

52

problem.solve()

53

54

print(f"Iteration {iteration}: obj = {problem.value:.4f}")

55

print(f"x = {x.value}, y = {y.value}")

56

57

# Check convergence

58

if iteration > 0 and abs(problem.value - prev_obj) < 1e-6:

59

break

60

prev_obj = problem.value

61

62

# Sensitivity analysis using linearization

63

# Perturb a parameter and use linearization to estimate effect

64

A = cp.Parameter((3, 2), value=np.random.randn(3, 2))

65

b = cp.Parameter(3, value=np.random.randn(3))

66

x = cp.Variable(2)

67

68

original_problem = cp.Problem(

69

cp.Minimize(cp.sum_squares(x)),

70

[A @ x == b, x >= 0]

71

)

72

original_problem.solve()

73

original_obj = original_problem.value

74

75

# Linearize objective around current solution

76

obj_linear = cp.linearize(cp.sum_squares(x))

77

78

# Perturb parameter and estimate new objective

79

b_new = b.value + 0.1 * np.random.randn(3)

80

b.value = b_new

81

82

# Solve with linearized objective (approximation)

83

approx_problem = cp.Problem(cp.Minimize(obj_linear), [A @ x == b, x >= 0])

84

approx_problem.solve()

85

approx_obj = approx_problem.value

86

87

# Solve exactly for comparison

88

b.value = b_new

89

original_problem.solve()

90

exact_obj = original_problem.value

91

92

print(f"Original objective: {original_obj:.6f}")

93

print(f"Approximated objective: {approx_obj:.6f}")

94

print(f"Exact objective: {exact_obj:.6f}")

95

print(f"Approximation error: {abs(exact_obj - approx_obj):.6f}")

96

```

97

98

### Partial Optimization

99

100

Partially optimize over a subset of variables while keeping others as parameters.

101

102

```python { .api }

103

def partial_optimize(problem, opt_vars, opt_params=None):

104

"""

105

Partially optimize a problem over specified variables.

106

107

Parameters:

108

- problem: Problem to partially optimize

109

- opt_vars: list of variables to optimize over

110

- opt_params: list of parameters to treat as optimization variables

111

112

Returns:

113

- Expression: optimal value as function of remaining variables

114

"""

115

...

116

```

117

118

Usage examples:

119

120

```python

121

import cvxpy as cp

122

import numpy as np

123

124

# Bilevel optimization example

125

# Lower level: min_y ||Ay - b||^2 subject to y >= 0

126

# Upper level: min_x f(x) subject to x in optimal solution set of lower level

127

128

# Problem dimensions

129

m, n = 10, 5

130

131

# Upper level variables

132

x = cp.Variable(n)

133

134

# Lower level variables and data

135

y = cp.Variable(m)

136

A = cp.Parameter((m, n), value=np.random.randn(m, n))

137

b = cp.Parameter(m)

138

139

# Lower level problem (parameterized by x)

140

b.value = A.value @ np.ones(n) # Make problem feasible

141

lower_obj = cp.sum_squares(A @ y - (b + x)) # b depends on x

142

lower_constraints = [y >= 0]

143

lower_problem = cp.Problem(cp.Minimize(lower_obj), lower_constraints)

144

145

# Partially optimize over y to get upper level constraint

146

try:

147

# This creates an expression in terms of x

148

optimal_lower_value = cp.partial_optimize(lower_problem, [y])

149

150

# Upper level problem

151

upper_obj = cp.sum_squares(x) + optimal_lower_value

152

upper_constraints = [cp.norm(x, 'inf') <= 1]

153

upper_problem = cp.Problem(cp.Minimize(upper_obj), upper_constraints)

154

155

upper_problem.solve()

156

print(f"Optimal x: {x.value}")

157

print(f"Upper level objective: {upper_problem.value}")

158

159

except Exception as e:

160

print(f"Partial optimization failed: {e}")

161

162

# Portfolio optimization with transaction costs

163

# Outer problem: choose target portfolio

164

# Inner problem: minimize transaction costs to reach target

165

166

n_assets = 5

167

w_current = cp.Parameter(n_assets, value=np.random.rand(n_assets))

168

w_current.value = w_current.value / np.sum(w_current.value) # normalize

169

170

# Target portfolio (outer variable)

171

w_target = cp.Variable(n_assets)

172

173

# Trade amounts (inner variables)

174

w_buy = cp.Variable(n_assets, nonneg=True)

175

w_sell = cp.Variable(n_assets, nonneg=True)

176

177

# Transaction cost parameters

178

cost_buy = 0.01 # 1% transaction cost for buying

179

cost_sell = 0.01 # 1% transaction cost for selling

180

181

# Inner problem: minimize transaction costs to reach target

182

transaction_costs = cost_buy * cp.sum(w_buy) + cost_sell * cp.sum(w_sell)

183

rebalancing_constraint = w_current + w_buy - w_sell == w_target

184

185

inner_problem = cp.Problem(

186

cp.Minimize(transaction_costs),

187

[rebalancing_constraint, w_buy >= 0, w_sell >= 0]

188

)

189

190

# Outer problem: choose target portfolio considering transaction costs

191

expected_return = cp.Parameter(n_assets, value=0.1 * np.random.rand(n_assets))

192

risk_param = 0.5

193

194

try:

195

# Partially optimize over trading variables

196

min_transaction_cost = cp.partial_optimize(inner_problem, [w_buy, w_sell])

197

198

# Outer objective: maximize return minus transaction costs

199

portfolio_return = expected_return.T @ w_target

200

outer_obj = cp.Maximize(portfolio_return - risk_param * min_transaction_cost)

201

202

# Portfolio constraints

203

outer_constraints = [

204

cp.sum(w_target) == 1, # fully invested

205

w_target >= 0 # long-only

206

]

207

208

outer_problem = cp.Problem(outer_obj, outer_constraints)

209

outer_problem.solve()

210

211

print(f"Optimal target portfolio: {w_target.value}")

212

print(f"Current portfolio: {w_current.value}")

213

print(f"Expected net return: {outer_problem.value}")

214

215

except Exception as e:

216

print(f"Bilevel portfolio optimization failed: {e}")

217

```

218

219

### Support Function

220

221

Transform expressions using support function representations for convex analysis.

222

223

```python { .api }

224

def suppfunc(expr, vars=None):

225

"""

226

Compute support function of expression.

227

228

Parameters:

229

- expr: Expression to compute support function for

230

- vars: Variables to compute support function over

231

232

Returns:

233

- Expression: support function

234

"""

235

...

236

```

237

238

Usage examples:

239

240

```python

241

import cvxpy as cp

242

import numpy as np

243

244

# Support function of a norm ball

245

x = cp.Variable(3)

246

y = cp.Variable(3) # dual variable

247

248

# L2 ball: {x : ||x||_2 <= 1}

249

# Support function: sup_{||x||_2 <= 1} y^T x = ||y||_2

250

l2_ball_constraint = cp.norm(x, 2) <= 1

251

try:

252

support_func = cp.suppfunc(y.T @ x, [x]) # Should give ||y||_2

253

print("L2 ball support function computed")

254

except Exception as e:

255

print(f"Support function computation failed: {e}")

256

257

# Support function in robust optimization

258

# Robust least squares: min_x max_{||u||_inf <= delta} ||Ax + u - b||^2

259

260

n, m = 5, 10

261

A = cp.Parameter((m, n), value=np.random.randn(m, n))

262

b = cp.Parameter(m, value=np.random.randn(m))

263

x = cp.Variable(n)

264

delta = 0.1 # uncertainty level

265

266

# Uncertainty set: ||u||_inf <= delta

267

u = cp.Variable(m)

268

residual = A @ x + u - b

269

270

try:

271

# Worst-case residual over uncertainty set

272

worst_case_obj = cp.suppfunc(cp.sum_squares(residual), [u])

273

uncertainty_constraint = cp.norm(u, 'inf') <= delta

274

275

# Robust optimization problem

276

robust_obj = cp.Minimize(worst_case_obj)

277

robust_problem = cp.Problem(robust_obj, [uncertainty_constraint])

278

279

robust_problem.solve()

280

print(f"Robust solution: {x.value}")

281

282

except Exception as e:

283

print(f"Robust optimization with support function failed: {e}")

284

285

# Fenchel conjugate computation

286

# For convex function f(x), conjugate is f*(y) = sup_x (y^T x - f(x))

287

288

x = cp.Variable()

289

y = cp.Parameter(value=1.0)

290

291

# Conjugate of f(x) = x^2/2 should be f*(y) = y^2/2

292

f_x = 0.5 * x**2

293

linear_term = y * x

294

295

try:

296

conjugate = cp.suppfunc(linear_term - f_x, [x])

297

print("Fenchel conjugate computed")

298

299

# Evaluate conjugate at different points

300

for y_val in [-2, -1, 0, 1, 2]:

301

y.value = y_val

302

conjugate_problem = cp.Problem(cp.Minimize(-conjugate)) # max -> min

303

conjugate_problem.solve()

304

analytical = 0.5 * y_val**2 # True conjugate value

305

print(f"y={y_val}: computed={conjugate_problem.value:.4f}, "

306

f"analytical={analytical:.4f}")

307

308

except Exception as e:

309

print(f"Fenchel conjugate computation failed: {e}")

310

311

# Game theory: computing Nash equilibrium

312

# Player 1: min_x max_y x^T Q y

313

# Player 2: max_y min_x x^T Q y

314

# where x, y are in probability simplexes

315

316

n_strategies = 3

317

Q = cp.Parameter((n_strategies, n_strategies),

318

value=np.random.randn(n_strategies, n_strategies))

319

320

x = cp.Variable(n_strategies, nonneg=True) # Player 1 strategy

321

y = cp.Variable(n_strategies, nonneg=True) # Player 2 strategy

322

323

# Probability simplex constraints

324

x_simplex = cp.sum(x) == 1

325

y_simplex = cp.sum(y) == 1

326

327

try:

328

# Player 1's worst-case payoff: min_x max_y x^T Q y

329

payoff = cp.quad_form(x, Q, y) # This might not work directly

330

player1_worst_case = cp.suppfunc(payoff, [y])

331

332

# Nash equilibrium computation

333

nash_problem = cp.Problem(

334

cp.Minimize(player1_worst_case),

335

[x_simplex, x >= 0, y_simplex, y >= 0]

336

)

337

338

nash_problem.solve()

339

print(f"Nash equilibrium strategies:")

340

print(f"Player 1: {x.value}")

341

print(f"Player 2: {y.value}")

342

343

except Exception as e:

344

print(f"Nash equilibrium computation failed: {e}")

345

```

346

347

### Indicator Function

348

349

Transform expressions using indicator functions for set membership constraints.

350

351

```python { .api }

352

def indicator(constraints):

353

"""

354

Indicator function for a set defined by constraints.

355

356

Parameters:

357

- constraints: list of constraints defining the set

358

359

Returns:

360

- Expression: indicator function (0 if constraints satisfied, +inf otherwise)

361

"""

362

...

363

```

364

365

### Scalarization Functions

366

367

Transform multi-objective problems into single-objective problems using scalarization techniques.

368

369

```python { .api }

370

def log_sum_exp(expr, axis=None, keepdims=False):

371

"""

372

Log-sum-exponential scalarization: log(sum(exp(expr))).

373

374

Parameters:

375

- expr: expression

376

- axis: axis to sum along

377

- keepdims: whether to keep singleton dimensions

378

379

Returns:

380

- Expression: log-sum-exp scalarization

381

"""

382

...

383

384

def max(expr, axis=None, keepdims=False):

385

"""

386

Max scalarization for multi-objective problems.

387

388

Parameters:

389

- expr: expression or list of objective expressions

390

- axis: axis to take maximum along

391

- keepdims: whether to keep singleton dimensions

392

393

Returns:

394

- Expression: maximum scalarization

395

"""

396

...

397

398

def targets_and_priorities(objectives, targets, priorities):

399

"""

400

Target-based scalarization with priorities.

401

402

Parameters:

403

- objectives: list of objective expressions

404

- targets: target values for each objective

405

- priorities: priority weights for each objective

406

407

Returns:

408

- Expression: scalarized objective

409

"""

410

...

411

412

def weighted_sum(objectives, weights):

413

"""

414

Weighted sum scalarization.

415

416

Parameters:

417

- objectives: list of objective expressions

418

- weights: weight vector for objectives

419

420

Returns:

421

- Expression: weighted sum objective

422

"""

423

...

424

```

425

426

Usage examples for new functions:

427

428

```python

429

import cvxpy as cp

430

import numpy as np

431

432

# Indicator function example - constrained optimization

433

x = cp.Variable(2)

434

y = cp.Variable(2)

435

436

# Define a constraint set

437

constraint_set = [cp.norm(x, 2) <= 1, x >= 0, y >= -1, y <= 1]

438

439

try:

440

# Use indicator function to enforce constraints

441

indicator_expr = cp.indicator(constraint_set)

442

443

# Optimization with indicator function

444

objective = cp.Minimize(cp.sum_squares(x - y) + indicator_expr)

445

problem = cp.Problem(objective)

446

problem.solve()

447

448

print(f"Solution with indicator function: x={x.value}, y={y.value}")

449

450

except Exception as e:

451

print(f"Indicator function example failed: {e}")

452

453

# Multi-objective optimization with scalarization

454

n = 5

455

x = cp.Variable(n)

456

A1 = cp.Parameter((3, n), value=np.random.randn(3, n))

457

A2 = cp.Parameter((4, n), value=np.random.randn(4, n))

458

b1 = cp.Parameter(3, value=np.random.randn(3))

459

b2 = cp.Parameter(4, value=np.random.randn(4))

460

461

# Multiple objectives

462

obj1 = cp.norm(A1 @ x - b1, 2) # Least squares fit 1

463

obj2 = cp.norm(A2 @ x - b2, 1) # Least absolute deviations fit 2

464

obj3 = cp.norm(x, 1) # Sparsity regularization

465

466

objectives = [obj1, obj2, obj3]

467

468

# Weighted sum scalarization

469

weights = [0.5, 0.3, 0.2]

470

try:

471

weighted_objective = cp.transforms.weighted_sum(objectives, weights)

472

473

weighted_problem = cp.Problem(cp.Minimize(weighted_objective), [x >= -2, x <= 2])

474

weighted_problem.solve()

475

476

print(f"Weighted sum solution: {x.value}")

477

print(f"Objective values: {[obj.value for obj in objectives]}")

478

479

except Exception as e:

480

print(f"Weighted sum scalarization failed: {e}")

481

482

# Target-based scalarization

483

targets = [1.0, 0.5, 0.1] # Target values for each objective

484

priorities = [1.0, 2.0, 0.5] # Higher priority = more important

485

486

try:

487

target_objective = cp.transforms.targets_and_priorities(objectives, targets, priorities)

488

489

target_problem = cp.Problem(cp.Minimize(target_objective), [x >= -2, x <= 2])

490

target_problem.solve()

491

492

print(f"Target-based solution: {x.value}")

493

print(f"Distance from targets: {[abs(obj.value - target) for obj, target in zip(objectives, targets)]}")

494

495

except Exception as e:

496

print(f"Target-based scalarization failed: {e}")

497

498

# Log-sum-exp scalarization for risk-sensitive optimization

499

# Minimize risk-sensitive cost: log(E[exp(costs)])

500

n_scenarios = 10

501

scenario_costs = [cp.norm(A1 @ x - b1 + 0.1 * np.random.randn(3), 2)

502

for _ in range(n_scenarios)]

503

504

try:

505

# Stack scenario costs

506

cost_vector = cp.hstack(scenario_costs)

507

508

# Risk-sensitive objective using log-sum-exp

509

risk_sensitive_obj = cp.transforms.log_sum_exp(cost_vector) - np.log(n_scenarios)

510

511

risk_problem = cp.Problem(cp.Minimize(risk_sensitive_obj), [x >= -1, x <= 1])

512

risk_problem.solve()

513

514

print(f"Risk-sensitive solution: {x.value}")

515

print(f"Individual scenario costs: {[cost.value for cost in scenario_costs]}")

516

517

except Exception as e:

518

print(f"Risk-sensitive optimization failed: {e}")

519

```