or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

constants-enums.mdcore-modeling.mdfile-io.mdindex.mdmathematical-operations.mdsolver-interfaces.mdutility-functions.md

core-modeling.mddocs/

0

# Core Modeling Classes

1

2

Fundamental classes for creating and manipulating linear and mixed integer programming problems in PuLP. These classes provide the foundation for mathematical optimization modeling with intuitive Python syntax.

3

4

## Capabilities

5

6

### Problem Management

7

8

The LpProblem class serves as the main container for optimization problems, managing variables, constraints, objectives, and solution processes.

9

10

```python { .api }

11

class LpProblem:

12

def __init__(self, name="NoName", sense=LpMinimize):

13

"""

14

Create a new optimization problem.

15

16

Parameters:

17

- name (str): Problem name for identification

18

- sense (int): Optimization direction (LpMinimize=1 or LpMaximize=-1)

19

"""

20

21

def solve(self, solver=None, **kwargs):

22

"""

23

Solve the optimization problem.

24

25

Parameters:

26

- solver: Solver instance (defaults to LpSolverDefault)

27

- **kwargs: Additional solver-specific parameters

28

29

Returns:

30

int: Status code (LpStatusOptimal=1, LpStatusInfeasible=-1, etc.)

31

"""

32

33

def writeLP(self, filename):

34

"""

35

Export problem to LP format file.

36

37

Parameters:

38

- filename (str): Output file path

39

"""

40

41

def writeMPS(self, filename):

42

"""

43

Export problem to MPS format file.

44

45

Parameters:

46

- filename (str): Output file path

47

"""

48

49

def copy(self):

50

"""

51

Create a deep copy of the problem.

52

53

Returns:

54

LpProblem: Copy of the problem

55

"""

56

57

def deepcopy(self):

58

"""

59

Create a deep copy of the problem with all components.

60

61

Returns:

62

LpProblem: Deep copy of the problem

63

"""

64

65

def variables(self):

66

"""

67

Get all variables in the problem.

68

69

Returns:

70

list: List of LpVariable objects

71

"""

72

73

@property

74

def objective(self):

75

"""Get or set the objective function (LpAffineExpression)."""

76

77

@property

78

def constraints(self):

79

"""Get dictionary of all constraints in the problem."""

80

81

@property

82

def status(self):

83

"""Get the solution status of the problem."""

84

85

def sequentialSolve(self, objectives):

86

"""

87

Solve problem with multiple objectives sequentially.

88

89

Parameters:

90

- objectives (list): List of LpAffineExpression objectives to optimize in order

91

92

Returns:

93

int: Status code of final solve

94

"""

95

96

def toJson(self, filename):

97

"""

98

Export problem to JSON format file.

99

100

Parameters:

101

- filename (str): Output JSON file path

102

"""

103

104

def fromJson(self, filename):

105

"""

106

Load problem from JSON format file.

107

108

Parameters:

109

- filename (str): Input JSON file path

110

"""

111

112

def roundSolution(self, epsilon=1e-7):

113

"""

114

Round variable values in solution to remove numerical precision artifacts.

115

116

Parameters:

117

- epsilon (float): Tolerance for rounding near-integer values

118

"""

119

120

def checkDuplicateVars(self):

121

"""

122

Check for duplicate variable names in the problem.

123

124

Returns:

125

bool: True if duplicates found, False otherwise

126

"""

127

128

def numVariables(self):

129

"""

130

Get the number of variables in the problem.

131

132

Returns:

133

int: Number of variables

134

"""

135

136

def numConstraints(self):

137

"""

138

Get the number of constraints in the problem.

139

140

Returns:

141

int: Number of constraints

142

"""

143

144

def isMIP(self):

145

"""

146

Check if problem is a Mixed Integer Program.

147

148

Returns:

149

bool: True if problem contains integer or binary variables

150

"""

151

152

def valid(self):

153

"""

154

Check if problem is valid and well-formed.

155

156

Returns:

157

bool: True if problem is valid

158

"""

159

160

def assignStatus(self, status):

161

"""

162

Assign solution status to the problem.

163

164

Parameters:

165

- status (int): Status code to assign

166

"""

167

168

def toDict(self):

169

"""

170

Convert problem to dictionary representation.

171

172

Returns:

173

dict: Dictionary representation of the problem

174

"""

175

176

def fromDict(self, data):

177

"""

178

Load problem from dictionary representation.

179

180

Parameters:

181

- data (dict): Dictionary containing problem data

182

"""

183

184

def toDataclass(self):

185

"""

186

Convert problem to dataclass representation.

187

188

Returns:

189

Dataclass representation of the problem

190

"""

191

192

def fromDataclass(self, data):

193

"""

194

Load problem from dataclass representation.

195

196

Parameters:

197

- data: Dataclass containing problem data

198

"""

199

200

def variablesDict(self):

201

"""

202

Get dictionary of all variables keyed by name.

203

204

Returns:

205

dict: Dictionary mapping variable names to LpVariable objects

206

"""

207

208

def addVariable(self, var):

209

"""

210

Add a single variable to the problem.

211

212

Parameters:

213

- var (LpVariable): Variable to add

214

"""

215

216

def addVariables(self, vars):

217

"""

218

Add multiple variables to the problem.

219

220

Parameters:

221

- vars (list): List of LpVariable objects to add

222

"""

223

224

def addConstraint(self, constraint):

225

"""

226

Add a constraint to the problem.

227

228

Parameters:

229

- constraint (LpConstraint): Constraint to add

230

"""

231

232

def extend(self, other):

233

"""

234

Extend problem with variables and constraints from another problem.

235

236

Parameters:

237

- other (LpProblem): Problem to merge into this problem

238

"""

239

240

def setObjective(self, obj):

241

"""

242

Set the objective function for the problem.

243

244

Parameters:

245

- obj (LpAffineExpression): Objective expression to minimize/maximize

246

"""

247

248

def resolve(self):

249

"""

250

Re-solve the problem with the same solver and parameters.

251

252

Returns:

253

int: Status code

254

"""

255

256

def getSense(self):

257

"""

258

Get the optimization sense (minimize or maximize).

259

260

Returns:

261

int: LpMinimize (1) or LpMaximize (-1)

262

"""

263

```

264

265

Usage example:

266

267

```python

268

# Create minimization problem

269

prob = LpProblem("Production_Planning", LpMinimize)

270

271

# Add variables and constraints

272

x = LpVariable("production", 0, 1000)

273

prob += 2*x >= 100 # Minimum production constraint

274

prob += 3*x # Objective: minimize cost

275

276

# Solve

277

status = prob.solve()

278

print(f"Status: {LpStatus[status]}")

279

```

280

281

### Variable Creation and Management

282

283

The LpVariable class represents decision variables in optimization problems with support for bounds, categories, and bulk creation methods.

284

285

```python { .api }

286

class LpVariable:

287

def __init__(self, name, lowBound=None, upBound=None, cat=LpContinuous, e=None):

288

"""

289

Create a decision variable.

290

291

Parameters:

292

- name (str): Variable name

293

- lowBound (float, optional): Lower bound (default: None = -infinity)

294

- upBound (float, optional): Upper bound (default: None = +infinity)

295

- cat (str): Variable category (LpContinuous, LpInteger, LpBinary)

296

- e (LpElement, optional): Associated element for column generation

297

"""

298

299

@classmethod

300

def dicts(cls, name, indices, lowBound=None, upBound=None, cat=LpContinuous):

301

"""

302

Create dictionary of variables with shared properties.

303

304

Parameters:

305

- name (str): Base name for variables

306

- indices: Iterable of indices for variable names

307

- lowBound (float, optional): Lower bound for all variables

308

- upBound (float, optional): Upper bound for all variables

309

- cat (str): Variable category for all variables

310

311

Returns:

312

dict: Dictionary mapping indices to LpVariable objects

313

"""

314

315

@classmethod

316

def dict(cls, name, indices, lowBound=None, upBound=None, cat=LpContinuous):

317

"""

318

Alias for dicts() method.

319

"""

320

321

@classmethod

322

def matrix(cls, name, indices1, indices2, lowBound=None, upBound=None, cat=LpContinuous):

323

"""

324

Create 2D matrix of variables.

325

326

Parameters:

327

- name (str): Base name for variables

328

- indices1: First dimension indices

329

- indices2: Second dimension indices

330

- lowBound (float, optional): Lower bound for all variables

331

- upBound (float, optional): Upper bound for all variables

332

- cat (str): Variable category for all variables

333

334

Returns:

335

dict: Nested dictionary of LpVariable objects

336

"""

337

338

def bounds(self, low, up):

339

"""

340

Set variable bounds.

341

342

Parameters:

343

- low (float): Lower bound

344

- up (float): Upper bound

345

"""

346

347

def positive(self):

348

"""

349

Make variable non-negative (set lower bound to 0).

350

"""

351

352

def value(self):

353

"""

354

Get the solution value of the variable.

355

356

Returns:

357

float: Variable value in solution (None if not solved)

358

"""

359

360

def setInitialValue(self, val):

361

"""

362

Set initial value for warm starts.

363

364

Parameters:

365

- val (float): Initial value

366

"""

367

368

@property

369

def lowBound(self):

370

"""Get or set the lower bound of the variable."""

371

372

@property

373

def upBound(self):

374

"""Get or set the upper bound of the variable."""

375

376

@property

377

def cat(self):

378

"""Get or set the category of the variable."""

379

380

@property

381

def name(self):

382

"""Get the name of the variable."""

383

384

def roundedValue(self, epsilon=1e-7):

385

"""

386

Get rounded solution value of the variable.

387

388

Parameters:

389

- epsilon (float): Tolerance for rounding near-integer values

390

391

Returns:

392

float: Rounded variable value

393

"""

394

395

def valueOrDefault(self):

396

"""

397

Get variable value or default within bounds if not solved.

398

399

Returns:

400

float: Variable value or default within bounds

401

"""

402

403

def fixValue(self, value=None):

404

"""

405

Fix variable to a specific value.

406

407

Parameters:

408

- value (float, optional): Value to fix variable to (uses current value if None)

409

"""

410

411

def unfixValue(self):

412

"""

413

Unfix variable, restoring original bounds.

414

"""

415

416

def isFixed(self):

417

"""

418

Check if variable is fixed to a specific value.

419

420

Returns:

421

bool: True if variable is fixed

422

"""

423

424

def isBinary(self):

425

"""

426

Check if variable is binary (0 or 1).

427

428

Returns:

429

bool: True if variable category is LpBinary

430

"""

431

432

def isInteger(self):

433

"""

434

Check if variable is integer.

435

436

Returns:

437

bool: True if variable category is LpInteger or LpBinary

438

"""

439

440

def isFree(self):

441

"""

442

Check if variable is free (unbounded).

443

444

Returns:

445

bool: True if variable has no bounds

446

"""

447

448

def isConstant(self):

449

"""

450

Check if variable has constant value (both bounds equal).

451

452

Returns:

453

bool: True if lower bound equals upper bound

454

"""

455

456

def isPositive(self):

457

"""

458

Check if variable is constrained to be positive.

459

460

Returns:

461

bool: True if lower bound >= 0

462

"""

463

464

def getLb(self):

465

"""

466

Get lower bound of the variable.

467

468

Returns:

469

float: Lower bound value

470

"""

471

472

def getUb(self):

473

"""

474

Get upper bound of the variable.

475

476

Returns:

477

float: Upper bound value

478

"""

479

480

def valid(self, eps=1e-7):

481

"""

482

Check if variable value is within bounds.

483

484

Parameters:

485

- eps (float): Tolerance for bound checking

486

487

Returns:

488

bool: True if variable value is valid

489

"""

490

491

def infeasibilityGap(self):

492

"""

493

Calculate infeasibility gap for variable bounds.

494

495

Returns:

496

float: Gap value if infeasible, 0 if feasible

497

"""

498

499

def toDict(self):

500

"""

501

Convert variable to dictionary representation.

502

503

Returns:

504

dict: Dictionary representation of the variable

505

"""

506

507

def fromDict(self, data):

508

"""

509

Load variable from dictionary representation.

510

511

Parameters:

512

- data (dict): Dictionary containing variable data

513

"""

514

515

def toDataclass(self):

516

"""

517

Convert variable to dataclass representation.

518

519

Returns:

520

Dataclass representation of the variable

521

"""

522

523

def fromDataclass(self, data):

524

"""

525

Load variable from dataclass representation.

526

527

Parameters:

528

- data: Dataclass containing variable data

529

"""

530

```

531

532

Usage examples:

533

534

```python

535

# Single variables

536

x = LpVariable("x", 0, 10) # 0 <= x <= 10

537

y = LpVariable("y", cat="Binary") # Binary variable

538

z = LpVariable("z", lowBound=0) # Non-negative variable

539

540

# Dictionary of variables

541

plants = ["A", "B", "C"]

542

production = LpVariable.dicts("prod", plants, 0, 1000)

543

# Creates: prod_A, prod_B, prod_C with bounds [0, 1000]

544

545

# Matrix of variables

546

supply_points = ["S1", "S2"]

547

demand_points = ["D1", "D2", "D3"]

548

transport = LpVariable.matrix("transport", supply_points, demand_points, 0)

549

# Creates: transport_S1_D1, transport_S1_D2, etc.

550

```

551

552

### Constraint Management

553

554

The LpConstraint class handles mathematical relationships between variables with support for different constraint senses and elastic subproblems.

555

556

```python { .api }

557

class LpConstraint:

558

def __init__(self, e=None, sense=LpConstraintEQ, name=None, rhs=None):

559

"""

560

Create a constraint.

561

562

Parameters:

563

- e (LpAffineExpression, optional): Left-hand side expression

564

- sense (int): Constraint sense (LpConstraintLE=-1, LpConstraintEQ=0, LpConstraintGE=1)

565

- name (str, optional): Constraint name

566

- rhs (float, optional): Right-hand side value

567

"""

568

569

def changeRHS(self, RHS):

570

"""

571

Change the right-hand side value.

572

573

Parameters:

574

- RHS (float): New right-hand side value

575

"""

576

577

def copy(self):

578

"""

579

Create a copy of the constraint.

580

581

Returns:

582

LpConstraint: Copy of the constraint

583

"""

584

585

def makeElasticSubProblem(self, penalty=1e6, proportionFreeBound=1e-4, proportionFreeBoundList=None):

586

"""

587

Create elastic version of constraint for infeasibility analysis.

588

589

Parameters:

590

- penalty (float): Penalty coefficient for constraint violations

591

- proportionFreeBound (float): Proportion of constraint bound that can be violated freely

592

- proportionFreeBoundList (list, optional): List of proportion bounds for multiple constraints

593

594

Returns:

595

FixedElasticSubProblem: Elastic subproblem object

596

"""

597

598

def emptyCopy(self):

599

"""

600

Create an empty copy of the constraint without coefficients.

601

602

Returns:

603

LpConstraint: Empty constraint with same sense and name

604

"""

605

606

def addInPlace(self, other):

607

"""

608

Add another constraint or expression to this constraint in place.

609

610

Parameters:

611

- other (LpConstraint or LpAffineExpression): Expression to add

612

"""

613

614

def getLb(self):

615

"""

616

Get lower bound equivalent of constraint.

617

618

Returns:

619

float: Lower bound value based on constraint sense

620

"""

621

622

def getUb(self):

623

"""

624

Get upper bound equivalent of constraint.

625

626

Returns:

627

float: Upper bound value based on constraint sense

628

"""

629

630

def valid(self):

631

"""

632

Check if constraint is valid and well-formed.

633

634

Returns:

635

bool: True if constraint is valid

636

"""

637

638

def value(self):

639

"""

640

Calculate the value of the constraint's left-hand side.

641

642

Returns:

643

float: Current value of constraint expression

644

"""

645

646

def keys(self):

647

"""

648

Get variables in the constraint.

649

650

Returns:

651

dict_keys: Variable keys in constraint

652

"""

653

654

def values(self):

655

"""

656

Get coefficients in the constraint.

657

658

Returns:

659

dict_values: Coefficient values in constraint

660

"""

661

662

def items(self):

663

"""

664

Get variable-coefficient pairs in the constraint.

665

666

Returns:

667

dict_items: Variable-coefficient pairs

668

"""

669

670

def get(self, var, default=0):

671

"""

672

Get coefficient for a variable.

673

674

Parameters:

675

- var (LpVariable): Variable to get coefficient for

676

- default (float): Default value if variable not in constraint

677

678

Returns:

679

float: Coefficient value

680

"""

681

682

def toDataclass(self):

683

"""

684

Convert constraint to dataclass representation.

685

686

Returns:

687

Dataclass representation of the constraint

688

"""

689

690

def fromDataclass(self, data):

691

"""

692

Load constraint from dataclass representation.

693

694

Parameters:

695

- data: Dataclass containing constraint data

696

"""

697

```

698

699

Usage examples:

700

701

```python

702

# Create constraints using operators

703

prob += x + 2*y <= 10 # Less than or equal

704

prob += 3*x - y == 5 # Equality

705

prob += x >= 0 # Greater than or equal

706

707

# Named constraints

708

constraint1 = LpConstraint(x + y, LpConstraintLE, "capacity", 100)

709

prob += constraint1

710

711

# Modify constraint

712

constraint1.changeRHS(120) # Change right-hand side to 120

713

```

714

715

### Linear Expressions

716

717

The LpAffineExpression class represents linear combinations of variables with constant terms, supporting arithmetic operations and solution value extraction.

718

719

```python { .api }

720

class LpAffineExpression:

721

def __init__(self, e=None, constant=0.0, name=None):

722

"""

723

Create a linear expression.

724

725

Parameters:

726

- e (dict or LpVariable, optional): Initial variable coefficients

727

- constant (float): Constant term

728

- name (str, optional): Expression name

729

"""

730

731

def addterm(self, var, coeff):

732

"""

733

Add a term to the expression.

734

735

Parameters:

736

- var (LpVariable): Variable to add

737

- coeff (float): Coefficient for the variable

738

"""

739

740

def copy(self):

741

"""

742

Create a copy of the expression.

743

744

Returns:

745

LpAffineExpression: Copy of the expression

746

"""

747

748

def value(self):

749

"""

750

Calculate the value of the expression using current variable values.

751

752

Returns:

753

float: Expression value (None if variables not solved)

754

"""

755

756

def valueOrDefault(self):

757

"""

758

Get expression value or default if variables not solved.

759

760

Returns:

761

float: Expression value or constant term

762

"""

763

764

@property

765

def constant(self):

766

"""Get or set the constant term."""

767

768

def emptyCopy(self):

769

"""

770

Create an empty copy of the expression.

771

772

Returns:

773

LpAffineExpression: Empty expression with same name

774

"""

775

776

def addInPlace(self, other):

777

"""

778

Add another expression to this expression in place.

779

780

Parameters:

781

- other (LpAffineExpression or LpVariable): Expression to add

782

"""

783

784

def isAtomic(self):

785

"""

786

Check if expression contains only one variable with coefficient 1.

787

788

Returns:

789

bool: True if expression is atomic

790

"""

791

792

def isNumericalConstant(self):

793

"""

794

Check if expression is a numerical constant (no variables).

795

796

Returns:

797

bool: True if expression contains no variables

798

"""

799

800

def atom(self):

801

"""

802

Get the single variable if expression is atomic.

803

804

Returns:

805

LpVariable: Single variable if atomic, None otherwise

806

"""

807

808

def sorted_keys(self):

809

"""

810

Get variables sorted by name.

811

812

Returns:

813

list: List of variables sorted by name

814

"""

815

816

def keys(self):

817

"""

818

Get variables in the expression.

819

820

Returns:

821

dict_keys: Variable keys in expression

822

"""

823

824

def values(self):

825

"""

826

Get coefficients in the expression.

827

828

Returns:

829

dict_values: Coefficient values in expression

830

"""

831

832

def items(self):

833

"""

834

Get variable-coefficient pairs in the expression.

835

836

Returns:

837

dict_items: Variable-coefficient pairs

838

"""

839

840

def get(self, var, default=0):

841

"""

842

Get coefficient for a variable.

843

844

Parameters:

845

- var (LpVariable): Variable to get coefficient for

846

- default (float): Default value if variable not in expression

847

848

Returns:

849

float: Coefficient value

850

"""

851

852

def clear(self):

853

"""

854

Clear all variables and constant from the expression.

855

"""

856

857

def toDict(self):

858

"""

859

Convert expression to dictionary representation.

860

861

Returns:

862

dict: Dictionary representation of the expression

863

"""

864

865

def toDataclass(self):

866

"""

867

Convert expression to dataclass representation.

868

869

Returns:

870

Dataclass representation of the expression

871

"""

872

```

873

874

Usage examples:

875

876

```python

877

# Create expressions

878

expr1 = 2*x + 3*y + 5 # Linear expression with constant

879

expr2 = LpAffineExpression([x, y], [2, 3], 5) # Equivalent creation

880

881

# Build expressions incrementally

882

expr = LpAffineExpression()

883

expr.addterm(x, 2)

884

expr.addterm(y, 3)

885

expr.constant = 5

886

887

# Use in constraints and objectives

888

prob += expr <= 100 # As constraint

889

prob += expr # As objective function

890

```

891

892

### Specialized Constraint Types

893

894

Additional constraint types for advanced modeling scenarios including fraction constraints and elastic formulations.

895

896

```python { .api }

897

class LpConstraintVar:

898

"""

899

Special constraint type for column-wise modeling where constraints

900

are treated as variables in the dual problem.

901

"""

902

def __init__(self, name=None, sense=None, rhs=None, e=None): ...

903

904

class LpFractionConstraint:

905

"""

906

Constraint enforcing fraction requirement: numerator/denominator = target.

907

Used for ratio optimization problems.

908

"""

909

def __init__(self, numerator, denominator, name=None, sense=LpConstraintEQ, rhs=None): ...

910

911

class FixedElasticSubProblem:

912

"""

913

Elastic constraint subproblem for handling infeasible constraints

914

by allowing violations with penalty costs.

915

"""

916

def reConstrain(self, newRHS): ...

917

918

class FractionElasticSubProblem:

919

"""

920

Elastic version of fraction constraints with violation penalties.

921

"""

922

def reConstrain(self, newRHS): ...

923

924

class LpElement:

925

"""

926

Base class for LpVariable and LpConstraintVar, providing common

927

functionality for problem elements.

928

"""

929

def __init__(self, name): ...

930

```

931

932

These specialized classes enable advanced modeling techniques including column generation, ratio optimization, and robust optimization with constraint relaxation.