Linear programming finds the best value of a linear objective while satisfying linear constraints. It turns choices about limited money, time, or materials into a model that can maximize benefit or minimize cost. Both the objective and every constraint must be linear; nonlinear interactions may call for a different optimization method. section 8.0 section 8.1.1
Formulate a resource-allocation decision in four parts:
- Define a decision variable for each choice. A project-selection variable is intended to be 1 when selected and 0 otherwise; other problems can use continuous quantities. section 8.2 section 8.3
- Choose a quantitative objective. For feature prioritization, maximize the sum of each selected feature’s priority score, where the score is value points divided by effort points. section 8.2 section 8.2.2
- Express limits as linear inequalities or equalities: for example, cap spending and require a minimum and maximum number of selections in each strategic group. section 8.2 section 8.1.3
- Solve, then inspect the solver’s status, choices, costs, and scores before treating the result as a plan. section 8.2.2
Prioritizing a feature backlog
Suppose 20 proposed features span three strategic groups. The plan must select three or four from each group, keep first-year spending at or below $700,000, and keep total lifecycle spending at or below $1.1 million. A feature with 16 value points and 13 effort points has a priority score of about 1.23, a first-year cost of $50,000, and a total cost of $80,000. Its score contributes to the objective; its costs contribute to the two budget constraints. section 8.1.1 section 8.1.4 section 8.2.2
Build the model in Python
With `features` holding records containing `epic`, `cost_1yr`, `total_cost`, `value_points`, and `effort_points`: from scipy.optimize import linprog scores = [f.value_points / f.effort_points for f in features] c = [-score for score in scores] # linprog minimizes A_ub = [[f.cost_1yr for f in features], [f.total_cost for f in features]] b_ub = [700000, 1100000] for epic in {f.epic for f in features}: row = [int(f.epic == epic) for f in features] A_ub.extend([row, [-v for v in row]]) b_ub.extend([4, -3]) result = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=(0, 1)) Negating scores converts maximization to minimization; the negative group row expresses a minimum of three. Crucially, bounds of 0 and 1 alone still allow fractional values. Check that a solution satisfies the intended yes/no selection requirement before reporting selected features. section 8.2 section 8.2.2
Table 8.1 Features aligned with the Enhance Data Infrastructure epic
|
Feature name
|
First-year cost
|
Total cost
|
Priority score
|
|---|---|---|---|
|
Automated Data Cleaning Pipeline
|
$50,000
|
$80,000
|
1.23
|
|
Real-time Data Ingestion
|
$70,000
|
$120,000
|
1.29
|
|
Data Privacy and Compliance Tools
|
$80,000
|
$130,000
|
1.19
|
|
Real-time Data Monitoring and Alerts
|
$60,000
|
$100,000
|
1.38
|
|
Integration with External Data Sources
|
$50,000
|
$85,000
|
1.42
|
|
Feature Engineering Automation
|
$55,000
|
$90,000
|
1.45
|
The feature table supplies first-year costs, total costs, and priority scores—the inputs used to construct the objective and budget constraints. section 8.1.4
The result is only as useful as its assumptions: costs, scores, and linear constraints must represent the decision accurately. Change budgets or group limits to explore what-if scenarios, and consider nonlinear constrained optimization when important relationships cannot be represented linearly. section 8.3 section 8.1.1

