or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-model.mdexpressions.mdindex.mdmath-functions.mdparameters.mdplugins.mdvariables-constraints.md

plugins.mddocs/

0

# Plugin Framework

1

2

Extensible plugin system for implementing custom optimization algorithms and components. PySCIPOpt's plugin framework allows users to extend SCIP's functionality with custom branching rules, constraint handlers, heuristics, cutting plane separators, and other algorithmic components.

3

4

## Capabilities

5

6

### Benders Decomposition

7

8

Custom Benders decomposition handlers for implementing decomposition algorithms and cut generation methods.

9

10

```python { .api }

11

class Benders:

12

"""

13

Benders decomposition handler for implementing custom decomposition methods.

14

15

Benders decomposition separates optimization problems into master and

16

subproblems, iteratively adding cuts to improve the master problem bounds.

17

"""

18

19

def bendersinit(self, benders):

20

"""

21

Initialize Benders decomposition.

22

23

Parameters:

24

- benders: Benders decomposition object

25

"""

26

27

def bendersexit(self, benders):

28

"""

29

Cleanup Benders decomposition.

30

31

Parameters:

32

- benders: Benders decomposition object

33

"""

34

35

def bendersexec(self, benders, result):

36

"""

37

Execute Benders decomposition algorithm.

38

39

Parameters:

40

- benders: Benders decomposition object

41

- result: Dictionary to store result status

42

43

Returns:

44

Should set result["result"] to appropriate SCIP_RESULT value

45

"""

46

```

47

48

### Benders Cut Generation

49

50

Custom Benders cut handlers for generating problem-specific cutting planes in decomposition methods.

51

52

```python { .api }

53

class Benderscut:

54

"""

55

Benders cut handler for custom cut generation in decomposition methods.

56

57

Generates cuts based on dual information from Benders subproblems

58

to strengthen the master problem formulation.

59

"""

60

61

def benderscutexec(self, benderscut, result):

62

"""

63

Execute Benders cut generation.

64

65

Parameters:

66

- benderscut: Benders cut object

67

- result: Dictionary to store result and cut information

68

69

Returns:

70

Should set result["result"] and add cuts if generated

71

"""

72

```

73

74

### Branching Rules

75

76

Custom branching strategies for controlling the branch-and-bound tree exploration.

77

78

```python { .api }

79

class Branchrule:

80

"""

81

Custom branching rule handler for implementing domain-specific

82

branching strategies in branch-and-bound algorithms.

83

"""

84

85

def branchinit(self, branchrule):

86

"""

87

Initialize branching rule.

88

89

Parameters:

90

- branchrule: Branching rule object

91

"""

92

93

def branchexit(self, branchrule):

94

"""

95

Cleanup branching rule.

96

97

Parameters:

98

- branchrule: Branching rule object

99

"""

100

101

def branchexeclp(self, branchrule, allowaddcons, result):

102

"""

103

Execute branching on LP solution.

104

105

Parameters:

106

- branchrule: Branching rule object

107

- allowaddcons (bool): Whether adding constraints is allowed

108

- result: Dictionary to store branching result

109

110

Returns:

111

Should set result["result"] and create child nodes if branching

112

"""

113

114

def branchexecext(self, branchrule, allowaddcons, result):

115

"""

116

Execute branching on external candidates.

117

118

Parameters:

119

- branchrule: Branching rule object

120

- allowaddcons (bool): Whether adding constraints is allowed

121

- result: Dictionary to store branching result

122

"""

123

124

def branchexecps(self, branchrule, allowaddcons, result):

125

"""

126

Execute branching on pseudo solution.

127

128

Parameters:

129

- branchrule: Branching rule object

130

- allowaddcons (bool): Whether adding constraints is allowed

131

- result: Dictionary to store branching result

132

"""

133

```

134

135

### Node Selection

136

137

Custom node selection strategies for controlling the order of node processing in the branch-and-bound tree.

138

139

```python { .api }

140

class Nodesel:

141

"""

142

Node selection handler for implementing custom strategies

143

to choose which node to process next in branch-and-bound.

144

"""

145

146

def nodeselinit(self, nodesel):

147

"""

148

Initialize node selector.

149

150

Parameters:

151

- nodesel: Node selector object

152

"""

153

154

def nodeselexit(self, nodesel):

155

"""

156

Cleanup node selector.

157

158

Parameters:

159

- nodesel: Node selector object

160

"""

161

162

def nodeselselect(self, nodesel, selnode, result):

163

"""

164

Select next node to process.

165

166

Parameters:

167

- nodesel: Node selector object

168

- selnode: List to store selected node

169

- result: Dictionary to store selection result

170

171

Should select the most promising node from the tree

172

"""

173

174

def nodeselcomp(self, nodesel, node1, node2):

175

"""

176

Compare two nodes for selection priority.

177

178

Parameters:

179

- nodesel: Node selector object

180

- node1: First node to compare

181

- node2: Second node to compare

182

183

Returns:

184

int: -1 if node1 has higher priority, 1 if node2, 0 if equal

185

"""

186

```

187

188

### Constraint Handlers

189

190

Custom constraint types with propagation, separation, and enforcement methods.

191

192

```python { .api }

193

class Conshdlr:

194

"""

195

Constraint handler for implementing custom constraint types

196

with specialized propagation and separation algorithms.

197

"""

198

199

def consinit(self, constraints):

200

"""

201

Initialize constraint handler.

202

203

Parameters:

204

- constraints: List of constraints handled by this handler

205

"""

206

207

def consexit(self, constraints):

208

"""

209

Cleanup constraint handler.

210

211

Parameters:

212

- constraints: List of constraints

213

"""

214

215

def constrans(self, sourceconstraints, targetconstraints):

216

"""

217

Transform constraints during problem transformation.

218

219

Parameters:

220

- sourceconstraints: Original constraints

221

- targetconstraints: Transformed constraints

222

"""

223

224

def consenfolp(self, constraints, nusefulconss, solinfeasible, result):

225

"""

226

Enforce constraints for LP solution.

227

228

Parameters:

229

- constraints: List of constraints to enforce

230

- nusefulconss (int): Number of useful constraints

231

- solinfeasible (bool): Whether solution is already known infeasible

232

- result: Dictionary to store enforcement result

233

"""

234

235

def consenfops(self, constraints, nusefulconss, solinfeasible, objinfeasible, result):

236

"""

237

Enforce constraints for pseudo solution.

238

239

Parameters:

240

- constraints: List of constraints to enforce

241

- nusefulconss (int): Number of useful constraints

242

- solinfeasible (bool): Whether solution is already known infeasible

243

- objinfeasible (bool): Whether solution is objectively infeasible

244

- result: Dictionary to store enforcement result

245

"""

246

247

def conscheck(self, constraints, solution, checkintegrality, checklprows, printreason, result):

248

"""

249

Check feasibility of solution.

250

251

Parameters:

252

- constraints: List of constraints to check

253

- solution: Solution to check

254

- checkintegrality (bool): Check integrality constraints

255

- checklprows (bool): Check LP row constraints

256

- printreason (bool): Print infeasibility reasons

257

- result: Dictionary to store check result

258

"""

259

260

def consprop(self, constraints, nusefulconss, result):

261

"""

262

Propagate constraints (domain reduction).

263

264

Parameters:

265

- constraints: List of constraints to propagate

266

- nusefulconss (int): Number of useful constraints

267

- result: Dictionary to store propagation result

268

"""

269

270

def conssepalp(self, constraints, nusefulconss, result):

271

"""

272

Separate constraints for LP solution.

273

274

Parameters:

275

- constraints: List of constraints for separation

276

- nusefulconss (int): Number of useful constraints

277

- result: Dictionary to store separation result

278

"""

279

280

def conssepasol(self, constraints, nusefulconss, solution, result):

281

"""

282

Separate constraints for given solution.

283

284

Parameters:

285

- constraints: List of constraints for separation

286

- nusefulconss (int): Number of useful constraints

287

- solution: Solution to separate

288

- result: Dictionary to store separation result

289

"""

290

```

291

292

### Event Handlers

293

294

Event handling system for monitoring solver progress and implementing custom callbacks.

295

296

```python { .api }

297

class Eventhdlr:

298

"""

299

Event handler for monitoring solver events and implementing

300

custom callbacks during the optimization process.

301

"""

302

303

def eventinit(self, eventhdlr):

304

"""

305

Initialize event handler.

306

307

Parameters:

308

- eventhdlr: Event handler object

309

"""

310

311

def eventexit(self, eventhdlr):

312

"""

313

Cleanup event handler.

314

315

Parameters:

316

- eventhdlr: Event handler object

317

"""

318

319

def eventexec(self, eventhdlr, event):

320

"""

321

Execute event handling.

322

323

Parameters:

324

- eventhdlr: Event handler object

325

- event: Event object containing event information

326

327

Event types include:

328

- Variable events: bound changes, domain changes, addition/deletion

329

- Node events: focus, unfocus, branch, solution found

330

- LP events: solved, objective change

331

- Solution events: found, improved

332

"""

333

```

334

335

### Primal Heuristics

336

337

Custom heuristic algorithms for finding feasible solutions.

338

339

```python { .api }

340

class Heur:

341

"""

342

Primal heuristic handler for implementing custom algorithms

343

to find feasible solutions during the optimization process.

344

"""

345

346

def heurinit(self, heur):

347

"""

348

Initialize heuristic.

349

350

Parameters:

351

- heur: Heuristic object

352

"""

353

354

def heurexit(self, heur):

355

"""

356

Cleanup heuristic.

357

358

Parameters:

359

- heur: Heuristic object

360

"""

361

362

def heurexec(self, heur, heurtiming, nodeinfeasible, result):

363

"""

364

Execute heuristic algorithm.

365

366

Parameters:

367

- heur: Heuristic object

368

- heurtiming: Timing information (when heuristic is called)

369

- nodeinfeasible (bool): Whether current node is infeasible

370

- result: Dictionary to store heuristic result

371

372

Timing values:

373

- BEFORENODE: Before processing node

374

- DURINGLPLOOP: During LP solving loop

375

- AFTERLPLOOP: After LP solving loop

376

- AFTERNODE: After processing node

377

"""

378

```

379

380

### Presolving Methods

381

382

Custom presolving routines for problem simplification and preprocessing.

383

384

```python { .api }

385

class Presol:

386

"""

387

Presolving handler for implementing custom problem simplification

388

and preprocessing routines before the main optimization begins.

389

"""

390

391

def presolinit(self, presol):

392

"""

393

Initialize presolving method.

394

395

Parameters:

396

- presol: Presolving object

397

"""

398

399

def presolexit(self, presol):

400

"""

401

Cleanup presolving method.

402

403

Parameters:

404

- presol: Presolving object

405

"""

406

407

def presolexec(self, presol, presolvinground, presoltiming, nnewfixedvars,

408

nnewaggrvars, nnewchgvartypes, nnewchgbds, nnewholes,

409

nnewdelconss, nnewaddconss, nnewupgdconss, nnewchgcoefs,

410

nnewchgsides, nfixedvars, naggrvars, nchgvartypes,

411

nchgbds, naddholes, ndelconss, naddconss, nupgdconss,

412

nchgcoefs, nchgsides, result):

413

"""

414

Execute presolving routine.

415

416

Parameters:

417

- presol: Presolving object

418

- presolvinground (int): Current presolving round

419

- presoltiming: Timing information

420

- Various counters for tracking changes made

421

- result: Dictionary to store presolving result

422

423

Should modify problem and update counters for changes made

424

"""

425

```

426

427

### Variable Pricers

428

429

Column generation algorithms for adding variables dynamically during optimization.

430

431

```python { .api }

432

class Pricer:

433

"""

434

Variable pricer for implementing column generation algorithms

435

that add variables dynamically during the optimization process.

436

"""

437

438

def pricerinit(self, pricer):

439

"""

440

Initialize pricer.

441

442

Parameters:

443

- pricer: Pricer object

444

"""

445

446

def pricerexit(self, pricer):

447

"""

448

Cleanup pricer.

449

450

Parameters:

451

- pricer: Pricer object

452

"""

453

454

def pricerredcost(self, pricer, result):

455

"""

456

Perform reduced cost pricing.

457

458

Parameters:

459

- pricer: Pricer object

460

- result: Dictionary to store pricing result

461

462

Should add variables with negative reduced cost

463

"""

464

465

def pricerfarkas(self, pricer, result):

466

"""

467

Perform Farkas pricing for infeasible LP.

468

469

Parameters:

470

- pricer: Pricer object

471

- result: Dictionary to store pricing result

472

473

Should add variables to prove infeasibility

474

"""

475

```

476

477

### Propagators

478

479

Custom domain propagation algorithms for tightening variable bounds.

480

481

```python { .api }

482

class Prop:

483

"""

484

Propagator handler for implementing custom domain propagation

485

algorithms that tighten variable bounds and domains.

486

"""

487

488

def propinit(self, prop):

489

"""

490

Initialize propagator.

491

492

Parameters:

493

- prop: Propagator object

494

"""

495

496

def propexit(self, prop):

497

"""

498

Cleanup propagator.

499

500

Parameters:

501

- prop: Propagator object

502

"""

503

504

def propexec(self, prop, proptiming, result):

505

"""

506

Execute propagation algorithm.

507

508

Parameters:

509

- prop: Propagator object

510

- proptiming: When propagation is called

511

- result: Dictionary to store propagation result

512

513

Timing values:

514

- BEFORELP: Before LP solving

515

- DURINGLPLOOP: During LP solving

516

- AFTERLPLOOP: After LP solving

517

"""

518

519

def propresprop(self, prop, cutoff, result):

520

"""

521

Resolve propagation after bound changes.

522

523

Parameters:

524

- prop: Propagator object

525

- cutoff (bool): Whether cutoff occurred

526

- result: Dictionary to store result

527

"""

528

```

529

530

### Cutting Plane Separators

531

532

Custom cutting plane generation for strengthening LP relaxations.

533

534

```python { .api }

535

class Sepa:

536

"""

537

Separator handler for implementing custom cutting plane generation

538

algorithms to strengthen LP relaxations.

539

"""

540

541

def sepainit(self, sepa):

542

"""

543

Initialize separator.

544

545

Parameters:

546

- sepa: Separator object

547

"""

548

549

def sepaexit(self, sepa):

550

"""

551

Cleanup separator.

552

553

Parameters:

554

- sepa: Separator object

555

"""

556

557

def sepaexeclp(self, sepa, result):

558

"""

559

Execute separation for LP solution.

560

561

Parameters:

562

- sepa: Separator object

563

- result: Dictionary to store separation result

564

565

Should add cutting planes that cut off current LP solution

566

"""

567

568

def sepaexecsol(self, sepa, solution, result):

569

"""

570

Execute separation for given solution.

571

572

Parameters:

573

- sepa: Separator object

574

- solution: Solution to separate

575

- result: Dictionary to store separation result

576

"""

577

```

578

579

### File Readers

580

581

Custom file format readers for specialized problem formats.

582

583

```python { .api }

584

class Reader:

585

"""

586

File reader handler for implementing custom file format parsers

587

to read optimization problems from specialized formats.

588

"""

589

590

def readerread(self, reader, filename, result):

591

"""

592

Read problem from file.

593

594

Parameters:

595

- reader: Reader object

596

- filename (str): Path to file to read

597

- result: Dictionary to store reading result

598

599

Should parse file and create corresponding SCIP problem

600

"""

601

602

def readerwrite(self, reader, file, name, transformed, objsense, objscale,

603

objoffset, binvars, intvars, implvars, contvars, fixedvars,

604

startnvars, conss, maxnconss, startnconss, genericnames, result):

605

"""

606

Write problem to file.

607

608

Parameters:

609

- reader: Reader object

610

- file: File handle for writing

611

- Various problem components to write

612

- result: Dictionary to store writing result

613

"""

614

```

615

616

### Linear Programming Interface

617

618

Access to the LP relaxation and linear programming solver interface for advanced LP operations.

619

620

```python { .api }

621

class LP:

622

"""

623

Linear programming interface providing access to LP relaxation,

624

dual values, basis information, and advanced LP solver operations.

625

"""

626

627

def getNRows(self):

628

"""

629

Get number of rows in current LP.

630

631

Returns:

632

int: Number of LP rows

633

"""

634

635

def getNCols(self):

636

"""

637

Get number of columns in current LP.

638

639

Returns:

640

int: Number of LP columns

641

"""

642

643

def getSolstat(self):

644

"""

645

Get LP solution status.

646

647

Returns:

648

SCIP_LPSOLSTAT: LP solution status

649

"""

650

651

def getObjval(self):

652

"""

653

Get LP objective value.

654

655

Returns:

656

float: LP objective value

657

"""

658

659

def getColsData(self):

660

"""

661

Get LP column data.

662

663

Returns:

664

tuple: Column data including lower bounds, upper bounds, objective coefficients

665

"""

666

667

def getRowsData(self):

668

"""

669

Get LP row data.

670

671

Returns:

672

tuple: Row data including left-hand sides, right-hand sides, row matrix

673

"""

674

675

def getPrimalSol(self):

676

"""

677

Get primal LP solution.

678

679

Returns:

680

list: Primal solution values for LP columns

681

"""

682

683

def getDualSol(self):

684

"""

685

Get dual LP solution.

686

687

Returns:

688

list: Dual solution values for LP rows

689

"""

690

691

def getRedcostSol(self):

692

"""

693

Get reduced cost solution.

694

695

Returns:

696

list: Reduced costs for LP columns

697

"""

698

```

699

700

## Usage Examples

701

702

### Custom Branching Rule

703

704

```python

705

from pyscipopt import Model, Branchrule, SCIP_RESULT

706

707

class CustomBranchingRule(Branchrule):

708

"""Example: Most fractional branching rule"""

709

710

def branchexeclp(self, branchrule, allowaddcons, result):

711

"""Branch on most fractional variable"""

712

713

# Get LP solution

714

lpsol = {}

715

for var in self.model.getVars():

716

if var.vtype() in ['B', 'I']: # Binary or integer variables

717

lpsol[var] = self.model.getVal(var)

718

719

# Find most fractional variable

720

most_fractional_var = None

721

max_fractionality = 0

722

723

for var, val in lpsol.items():

724

fractionality = min(val - int(val), int(val) + 1 - val)

725

if fractionality > max_fractionality:

726

max_fractionality = fractionality

727

most_fractional_var = var

728

729

if most_fractional_var is not None and max_fractionality > 1e-6:

730

# Create two child nodes

731

val = lpsol[most_fractional_var]

732

733

# Create down branch: var <= floor(val)

734

down_node = self.model.createChild(1.0, 1.0) # priority, estimate

735

self.model.addConsNode(down_node,

736

most_fractional_var <= int(val))

737

738

# Create up branch: var >= ceil(val)

739

up_node = self.model.createChild(1.0, 1.0)

740

self.model.addConsNode(up_node,

741

most_fractional_var >= int(val) + 1)

742

743

result["result"] = SCIP_RESULT.BRANCHED

744

else:

745

result["result"] = SCIP_RESULT.DIDNOTRUN

746

747

# Usage

748

model = Model("branching_example")

749

750

# Add variables and constraints

751

x = model.addVar(name="x", vtype="I", lb=0, ub=10)

752

y = model.addVar(name="y", vtype="I", lb=0, ub=8)

753

754

model.addCons(2.5*x + 3.7*y <= 15.3)

755

model.addCons(1.2*x + 0.8*y >= 3.1)

756

757

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

758

759

# Include custom branching rule

760

branching_rule = CustomBranchingRule()

761

model.includeBranchrule(branching_rule, "MostFractional", "Branch on most fractional variable",

762

priority=100000, maxdepth=-1, maxbounddist=1.0)

763

764

model.optimize()

765

```

766

767

### Custom Heuristic

768

769

```python

770

from pyscipopt import Model, Heur, SCIP_RESULT, SCIP_HEURTIMING

771

772

class RoundingHeuristic(Heur):

773

"""Simple rounding heuristic for mixed-integer problems"""

774

775

def heurexec(self, heur, heurtiming, nodeinfeasible, result):

776

"""Execute rounding heuristic"""

777

778

if nodeinfeasible:

779

result["result"] = SCIP_RESULT.DIDNOTRUN

780

return

781

782

# Get current LP solution

783

lpsol = {}

784

for var in self.model.getVars():

785

lpsol[var] = self.model.getVal(var)

786

787

# Create rounded solution

788

rounded_sol = self.model.createSol(heur)

789

790

for var in self.model.getVars():

791

if var.vtype() in ['B', 'I']:

792

# Round to nearest integer

793

rounded_val = round(lpsol[var])

794

# Respect bounds

795

rounded_val = max(var.getLbLocal(), min(var.getUbLocal(), rounded_val))

796

self.model.setSolVal(rounded_sol, var, rounded_val)

797

else:

798

# Keep continuous variables as is

799

self.model.setSolVal(rounded_sol, var, lpsol[var])

800

801

# Try to add solution

802

feasible = self.model.checkSol(rounded_sol)

803

if feasible:

804

self.model.addSol(rounded_sol)

805

result["result"] = SCIP_RESULT.FOUNDSOL

806

else:

807

result["result"] = SCIP_RESULT.DIDNOTFIND

808

809

# Free solution

810

self.model.freeSol(rounded_sol)

811

812

# Usage

813

model = Model("heuristic_example")

814

815

# Create mixed-integer problem

816

x = [model.addVar(name=f"x_{i}", vtype="I", lb=0, ub=10) for i in range(5)]

817

y = [model.addVar(name=f"y_{i}", lb=0, ub=5) for i in range(3)]

818

819

# Add constraints

820

model.addCons(quicksum(2*x[i] for i in range(5)) + quicksum(y[j] for j in range(3)) <= 25)

821

model.addCons(quicksum(x[i] for i in range(5)) >= 3)

822

823

# Objective

824

model.setObjective(quicksum(x[i] for i in range(5)) + quicksum(3*y[j] for j in range(3)), "maximize")

825

826

# Include custom heuristic

827

rounding_heur = RoundingHeuristic()

828

model.includeHeur(rounding_heur, "SimpleRounding", "Round fractional values to nearest integer",

829

'L', priority=1000, freq=1, freqofs=0, maxdepth=-1,

830

timingmask=SCIP_HEURTIMING.AFTERLPLOOP)

831

832

model.optimize()

833

```

834

835

### Custom Constraint Handler

836

837

```python

838

from pyscipopt import Model, Conshdlr, SCIP_RESULT

839

840

class AllDifferentConstraintHandler(Conshdlr):

841

"""All-different constraint: all variables must have different values"""

842

843

def conscheck(self, constraints, solution, checkintegrality, checklprows, printreason, result):

844

"""Check if all variables have different values"""

845

846

for cons in constraints:

847

# Get variables from constraint (stored during constraint creation)

848

variables = cons.data["variables"]

849

850

# Get solution values

851

values = [self.model.getSolVal(solution, var) for var in variables]

852

853

# Check if all values are different (within tolerance)

854

epsilon = 1e-6

855

for i in range(len(values)):

856

for j in range(i+1, len(values)):

857

if abs(values[i] - values[j]) < epsilon:

858

if printreason:

859

print(f"All-different violated: {variables[i].name} = {variables[j].name} = {values[i]}")

860

result["result"] = SCIP_RESULT.INFEASIBLE

861

return

862

863

result["result"] = SCIP_RESULT.FEASIBLE

864

865

def consenfolp(self, constraints, nusefulconss, solinfeasible, result):

866

"""Enforce all-different constraints for LP solution"""

867

868

cuts_added = False

869

870

for cons in constraints:

871

variables = cons.data["variables"]

872

873

# Get current LP values

874

values = [(var, self.model.getVal(var)) for var in variables]

875

876

# Find pairs of variables with same values

877

epsilon = 1e-6

878

for i in range(len(values)):

879

for j in range(i+1, len(values)):

880

var1, val1 = values[i]

881

var2, val2 = values[j]

882

883

if abs(val1 - val2) < epsilon:

884

# Add cut to separate this solution

885

# For integer variables: var1 - var2 >= 1 OR var2 - var1 >= 1

886

# Relaxed: |var1 - var2| >= 1

887

888

# Add two cuts

889

cut1_expr = var1 - var2 >= 1

890

cut2_expr = var2 - var1 >= 1

891

892

self.model.addCons(cut1_expr, name=f"alldiff_cut1_{var1.name}_{var2.name}")

893

self.model.addCons(cut2_expr, name=f"alldiff_cut2_{var1.name}_{var2.name}")

894

895

cuts_added = True

896

897

if cuts_added:

898

result["result"] = SCIP_RESULT.SEPARATED

899

else:

900

result["result"] = SCIP_RESULT.FEASIBLE

901

902

# Usage

903

model = Model("alldiff_example")

904

905

# Create variables

906

n = 4

907

x = [model.addVar(name=f"x_{i}", vtype="I", lb=1, ub=n) for i in range(n)]

908

909

# Create all-different constraint handler

910

alldiff_handler = AllDifferentConstraintHandler()

911

model.includeConshdlr(alldiff_handler, "AllDifferent", "All variables must be different",

912

sepapriority=100, enfopriority=100, checkpriority=-100,

913

sepafreq=1, propfreq=1, eagerfreq=100, maxprerounds=-1,

914

delaysepa=False, delayprop=False, needscons=True)

915

916

# Add all-different constraint

917

alldiff_cons = model.createCons(alldiff_handler, "alldiff_constraint")

918

alldiff_cons.data = {"variables": x}

919

model.addCons(alldiff_cons)

920

921

# Additional constraints

922

model.addCons(quicksum(x[i] for i in range(n)) == 10)

923

924

# Objective

925

model.setObjective(quicksum((i+1)*x[i] for i in range(n)), "maximize")

926

927

model.optimize()

928

```