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

utility-functions.mddocs/

0

# Utility Functions

1

2

Supporting functions for combinatorial operations, data structure manipulation, and system utilities that enhance PuLP's modeling capabilities. These utilities provide essential tools for complex optimization problem formulation and data handling.

3

4

## Capabilities

5

6

### Data Structure Functions

7

8

Functions for creating and manipulating dictionaries and structured data, particularly useful for organizing variables and parameters in large-scale optimization problems.

9

10

```python { .api }

11

def makeDict(headers, array, default=None):

12

"""

13

Create a dictionary from column headers and data array.

14

15

Parameters:

16

- headers (list): List of header names for dictionary keys

17

- array (list of lists): Data rows where each row contains values for headers

18

- default: Default value for missing entries

19

20

Returns:

21

dict: Dictionary with headers as keys and corresponding data as values

22

23

Examples:

24

headers = ['name', 'cost', 'capacity']

25

data = [['plant1', 100, 500], ['plant2', 120, 600]]

26

result = makeDict(headers, data)

27

# Returns: {'name': ['plant1', 'plant2'], 'cost': [100, 120], 'capacity': [500, 600]}

28

"""

29

30

def splitDict(data):

31

"""

32

Split a dictionary containing lists into multiple dictionaries.

33

34

Parameters:

35

- data (dict): Dictionary where values are lists of equal length

36

37

Returns:

38

list: List of dictionaries, one for each index position

39

40

Examples:

41

data = {'name': ['A', 'B'], 'cost': [10, 20], 'capacity': [100, 200]}

42

result = splitDict(data)

43

# Returns: [{'name': 'A', 'cost': 10, 'capacity': 100},

44

# {'name': 'B', 'cost': 20, 'capacity': 200}]

45

"""

46

47

def read_table(data, coerce_type, transpose=False):

48

"""

49

Read table data into dictionary structure with type coercion.

50

51

Parameters:

52

- data: Input data in various formats (list of lists, nested structure)

53

- coerce_type: Function or type to apply to data elements

54

- transpose (bool): Whether to transpose the data structure

55

56

Returns:

57

dict: Processed data dictionary

58

59

Examples:

60

data = [['1', '2'], ['3', '4']]

61

result = read_table(data, int)

62

# Converts string data to integers

63

"""

64

```

65

66

Usage examples:

67

68

```python

69

# Organize problem data

70

facilities = ['F1', 'F2', 'F3']

71

costs = [100, 150, 120]

72

capacities = [500, 600, 400]

73

74

# Create structured data dictionary

75

facility_data = makeDict(['facility', 'cost', 'capacity'],

76

[facilities, costs, capacities])

77

78

# Split into individual facility records

79

facility_records = splitDict(facility_data)

80

for record in facility_records:

81

print(f"Facility {record['facility']}: cost={record['cost']}, capacity={record['capacity']}")

82

83

# Process CSV-like data for optimization

84

raw_data = [

85

['10', '20', '30'],

86

['15', '25', '35'],

87

['12', '22', '32']

88

]

89

cost_matrix = read_table(raw_data, float)

90

91

# Use in variable creation

92

plants = list(facility_data['facility'])

93

production = LpVariable.dicts('prod', plants, 0)

94

95

# Create cost constraints using structured data

96

for i, plant in enumerate(plants):

97

prob += facility_data['cost'][i] * production[plant] <= facility_data['capacity'][i]

98

```

99

100

### Combinatorial Functions

101

102

Functions for generating combinations and permutations, essential for modeling complex assignment and scheduling problems.

103

104

```python { .api }

105

def allcombinations(orgset, k):

106

"""

107

Generate all combinations of elements from orgset with up to k items.

108

109

Parameters:

110

- orgset (iterable): Set of elements to combine

111

- k (int): Maximum number of elements in each combination

112

113

Returns:

114

list: List of all combinations as tuples

115

116

Examples:

117

allcombinations(['A', 'B', 'C'], 2)

118

# Returns: [(), ('A',), ('B',), ('C',), ('A', 'B'), ('A', 'C'), ('B', 'C')]

119

"""

120

121

def allpermutations(orgset, k):

122

"""

123

Generate all permutations of elements from orgset with up to k items.

124

125

Parameters:

126

- orgset (iterable): Set of elements to permute

127

- k (int): Maximum number of elements in each permutation

128

129

Returns:

130

list: List of all permutations as tuples

131

132

Examples:

133

allpermutations(['A', 'B'], 2)

134

# Returns: [(), ('A',), ('B',), ('A', 'B'), ('B', 'A')]

135

"""

136

137

def combination(iterable, r):

138

"""

139

Alias for itertools.combinations - generate r-length combinations.

140

141

Parameters:

142

- iterable: Elements to combine

143

- r (int): Length of each combination

144

145

Returns:

146

itertools.combinations: Iterator of r-length combinations

147

"""

148

149

def permutation(iterable, r):

150

"""

151

Alias for itertools.permutations - generate r-length permutations.

152

153

Parameters:

154

- iterable: Elements to permute

155

- r (int): Length of each permutation

156

157

Returns:

158

itertools.permutations: Iterator of r-length permutations

159

"""

160

```

161

162

Usage examples:

163

164

```python

165

from itertools import combinations, permutations

166

167

# Assignment problem - select teams for projects

168

teams = ['TeamA', 'TeamB', 'TeamC', 'TeamD']

169

projects = ['Proj1', 'Proj2', 'Proj3']

170

171

# All possible assignments of 2 teams to each project

172

team_combinations = list(combination(teams, 2))

173

for combo in team_combinations:

174

for project in projects:

175

# Create binary variable for each team combination-project pair

176

var_name = f"assign_{combo[0]}_{combo[1]}_{project}"

177

assignment_var = LpVariable(var_name, cat=LpBinary)

178

179

# Scheduling problem - all possible orderings

180

tasks = ['TaskA', 'TaskB', 'TaskC']

181

all_sequences = list(permutation(tasks, len(tasks)))

182

183

# Create variables for each possible sequence

184

sequence_vars = {}

185

for i, seq in enumerate(all_sequences):

186

sequence_vars[seq] = LpVariable(f"sequence_{i}", cat=LpBinary)

187

188

# Constraint: exactly one sequence must be selected

189

prob += lpSum(sequence_vars.values()) == 1

190

191

# Resource allocation with combinations

192

resources = ['R1', 'R2', 'R3', 'R4']

193

max_resources_per_task = 2

194

195

# All valid resource combinations for tasks

196

valid_combinations = list(allcombinations(resources, max_resources_per_task))

197

for task in tasks:

198

task_resource_vars = {}

199

for combo in valid_combinations:

200

if combo: # Skip empty combination

201

var_name = f"use_{task}_{'_'.join(combo)}"

202

task_resource_vars[combo] = LpVariable(var_name, cat=LpBinary)

203

204

# Each task must use exactly one resource combination

205

if task_resource_vars:

206

prob += lpSum(task_resource_vars.values()) == 1

207

```

208

209

### Value and Type Checking Functions

210

211

Functions for handling numeric values and type validation in optimization contexts.

212

213

```python { .api }

214

def valueOrDefault(x):

215

"""

216

Get the value of a variable/expression or return a default within bounds.

217

218

Parameters:

219

- x (LpVariable or LpAffineExpression): Object to evaluate

220

221

Returns:

222

float: Value of x, or a default value if not solved

223

224

Note: For variables, returns a value within the variable's bounds.

225

For expressions, returns the constant term or calculated default.

226

"""

227

228

def isNumber(x):

229

"""

230

Check if x is a numeric value (int or float).

231

232

Parameters:

233

- x: Object to check

234

235

Returns:

236

bool: True if x is int or float, False otherwise

237

"""

238

```

239

240

Usage examples:

241

242

```python

243

# Robust value extraction after solving

244

variables = [x, y, z]

245

solution_values = {}

246

247

for var in variables:

248

val = value(var)

249

if val is not None:

250

solution_values[var.name] = val

251

else:

252

# Use default value within bounds

253

solution_values[var.name] = valueOrDefault(var)

254

255

# Type validation for parameters

256

def create_cost_constraint(variables, costs, limit):

257

# Validate that all costs are numeric

258

if not all(isNumber(cost) for cost in costs):

259

raise ValueError("All costs must be numeric")

260

261

# Create constraint

262

total_cost = lpDot(variables, costs)

263

return total_cost <= limit

264

265

# Safe arithmetic operations

266

def safe_multiply(var, coeff):

267

if isNumber(coeff):

268

return coeff * var

269

else:

270

raise TypeError(f"Coefficient must be numeric, got {type(coeff)}")

271

```

272

273

### System Utilities

274

275

Functions for performance monitoring and system resource tracking.

276

277

```python { .api }

278

def resource_clock():

279

"""

280

Return the current resource usage time for performance monitoring.

281

282

Returns:

283

float: Resource time in seconds

284

285

Note: Used for tracking solver performance and optimization runtime.

286

"""

287

```

288

289

Usage examples:

290

291

```python

292

# Performance monitoring for optimization

293

start_time = resource_clock()

294

295

# Build and solve problem

296

prob = LpProblem("Performance_Test", LpMinimize)

297

variables = LpVariable.dicts("x", range(1000), 0, 1)

298

prob += lpSum(variables)

299

300

# Add many constraints

301

for i in range(500):

302

prob += lpSum(variables[j] for j in range(i, min(i+10, 1000))) <= 5

303

304

solve_start = resource_clock()

305

status = prob.solve()

306

solve_time = resource_clock() - solve_start

307

total_time = resource_clock() - start_time

308

309

print(f"Model building time: {solve_start - start_time:.3f} seconds")

310

print(f"Solve time: {solve_time:.3f} seconds")

311

print(f"Total time: {total_time:.3f} seconds")

312

313

# Benchmark different approaches

314

def benchmark_approach(approach_func, *args):

315

start = resource_clock()

316

result = approach_func(*args)

317

elapsed = resource_clock() - start

318

return result, elapsed

319

320

# Compare different formulation methods

321

formulation1_result, time1 = benchmark_approach(create_formulation_v1, data)

322

formulation2_result, time2 = benchmark_approach(create_formulation_v2, data)

323

324

print(f"Formulation 1: {time1:.3f}s")

325

print(f"Formulation 2: {time2:.3f}s")

326

if time1 < time2:

327

print("Formulation 1 is faster")

328

else:

329

print("Formulation 2 is faster")

330

```

331

332

### Advanced Data Processing

333

334

Complex data manipulation patterns for large-scale optimization problems.

335

336

```python

337

# Multi-dimensional data organization

338

def organize_transportation_data(supply_points, demand_points, costs, capacities, demands):

339

"""

340

Organize transportation problem data into structured format.

341

"""

342

# Create cost matrix

343

cost_data = {}

344

for i, supply in enumerate(supply_points):

345

cost_data[supply] = {}

346

for j, demand in enumerate(demand_points):

347

cost_data[supply][demand] = costs[i][j]

348

349

# Combine with capacity and demand data

350

supply_data = dict(zip(supply_points, capacities))

351

demand_data = dict(zip(demand_points, demands))

352

353

return cost_data, supply_data, demand_data

354

355

# Use organized data in optimization

356

cost_matrix, supply_capacity, demand_requirement = organize_transportation_data(

357

['S1', 'S2', 'S3'],

358

['D1', 'D2', 'D3', 'D4'],

359

[[10, 15, 20, 25], [12, 18, 22, 28], [8, 14, 16, 30]],

360

[100, 150, 120],

361

[80, 90, 100, 70]

362

)

363

364

# Create transportation variables and constraints

365

transport_vars = LpVariable.matrix("transport",

366

list(supply_capacity.keys()),

367

list(demand_requirement.keys()), 0)

368

369

# Supply constraints

370

for supply_point in supply_capacity:

371

prob += lpSum([transport_vars[supply_point][demand_point]

372

for demand_point in demand_requirement]) <= supply_capacity[supply_point]

373

374

# Demand constraints

375

for demand_point in demand_requirement:

376

prob += lpSum([transport_vars[supply_point][demand_point]

377

for supply_point in supply_capacity]) >= demand_requirement[demand_point]

378

379

# Objective function using organized cost data

380

total_cost = lpSum([cost_matrix[s][d] * transport_vars[s][d]

381

for s in supply_capacity

382

for d in demand_requirement])

383

prob += total_cost

384

```