Skip to content

Vol. II, Ch. 2seed 26202

DCT Laboratory — Volume II, Chapter 2

The General Enterprise Optimization Problem Revisited

Seed 26202 · Companion to the chapter and AXIOM Module AXIOM-02 (Vol. II)

The GEOP as a computational template: a two-period dynamic allocation whose interior first-order condition is infeasible (the optimum front-loads at the budget corner — Volume I Ch. 15's lesson, dynamic edition), the Objective Equivalence Theorem verified by state augmentation, and a classical LP solved by vertex enumeration — Classical Problems are GEOP Special Cases (Prop.). Mirrored in DCT_V2_Ch02_Lab.xlsx.

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['figure.dpi']=110

import numpy as np
SEED = 26202
K0, RHO, BUD = 10.0, 0.9, 6.0
def J(u0):
    K1 = RHO*K0 + u0
    K2 = RHO*K1 + (BUD-u0)
    return 2*np.sqrt(K1) + 6*np.sqrt(K2)
def J_augmented(u0):
    """terminal-only reformulation: augment state with accumulated reward."""
    K1 = RHO*K0 + u0; acc = 2*np.sqrt(K1)
    K2 = RHO*K1 + (BUD-u0)
    return acc + 6*np.sqrt(K2)          # terminal objective on (K2, acc)
GRID = np.arange(0, 6.5, 0.5)

# --- LP special case: max 3x+2y s.t. x+y<=6, 2x+y<=8, x,y>=0 ---
VERTS = [(0,0),(0,6),(2,4),(4,0)]
def lp_val(v): return 3*v[0]+2*v[1]

def reference_values():
    js = np.array([J(u) for u in GRID])
    u_star = float(GRID[int(np.argmax(js))])
    vstar = max(VERTS, key=lp_val)
    return {
        "u0_star": u_star,
        "J_star": round(float(js.max()),4),
        "J_even": round(float(J(3.0)),4),
        "J_backload": round(float(J(0.0)),4),
        "equivalence_maxdiff": round(float(max(abs(J(u)-J_augmented(u)) for u in GRID)),4),
        "lp_opt_value": lp_val(vstar),
        "lp_x": vstar[0], "lp_y": vstar[1],
        "n_vertices": len(VERTS),
    }
if __name__ == "__main__":
    [print(f"{k:20s} {v}") for k,v in reference_values().items()]
u0_star              6.0
J_star               29.7914
J_even               29.2172
J_backload           28.53
equivalence_maxdiff  0.0
lp_opt_value         14
lp_x                 2
lp_y                 4
n_vertices           4

Panel 1 — The canonical GEOP, two periods

K1=0.9K0+u0K_1 = 0.9K_0 + u_0, K2=0.9K1+u1K_2 = 0.9K_1 + u_1, budget u0+u1=6u_0 + u_1 = 6; objective J=2K1+6K2J = 2\sqrt{K_1} + 6\sqrt{K_2} (running + terminal). The interior FOC demands K2=0.09K1K_2 = 0.09K_1 — unreachable within the budget — so the optimum sits at the corner u0∗=6u_0^* = 6: front-load everything. Early capital earns twice: it scores in the running term AND compounds (at 0.9) into the terminal one.

js = np.array([J(u) for u in GRID])
fig, ax = plt.subplots(figsize=(8.0,4.2))
ax.plot(GRID, js, "o-", c="#C8A24B", lw=2.2, ms=5)
ax.scatter([GRID[np.argmax(js)]],[js.max()], c="#0B3D2E", s=110, zorder=5, label=f"u0* = {GRID[np.argmax(js)]:.1f}, J* = {js.max():.4f}")
ax.set(xlabel="u0 (period-0 investment; u1 = 6 − u0)", ylabel="J", title="Front-loading wins at the corner — seed 26202")
ax.legend(frameon=False); ax.grid(alpha=.25); plt.tight_layout(); plt.show()
print(f"J(front-load 6) = {J(6.0):.4f}   J(even 3) = {J(3.0):.4f}   J(back-load 0) = {J(0.0):.4f}")
Front-loading wins at the corner — seed 26202
J(front-load 6) = 29.7914   J(even 3) = 29.2172   J(back-load 0) = 28.5300

Panel 2 — The Objective Equivalence Theorem, executed

Running objectives can be absorbed into terminal ones by augmenting the state with an accumulator. Both formulations computed across the whole grid: maximum difference 0.0000. The theorem is why solvers may standardize on terminal form without loss — a formulation freedom Volume II uses constantly.

diffs = [abs(J(u)-J_augmented(u)) for u in GRID]
for u, d in zip(GRID, diffs):
    if u in (0.0, 3.0, 6.0): print(f"u0={u:3.1f}   J_running_form={J(u):9.4f}   J_terminal_form={J_augmented(u):9.4f}   |diff|={d:.6f}")
print(f"\nmax |difference| over the grid: {max(diffs):.6f}")
u0=0.0   J_running_form=  28.5300   J_terminal_form=  28.5300   |diff|=0.000000
u0=3.0   J_running_form=  29.2172   J_terminal_form=  29.2172   |diff|=0.000000
u0=6.0   J_running_form=  29.7914   J_terminal_form=  29.7914   |diff|=0.000000

max |difference| over the grid: 0.000000

Panel 3 — A classic, as a GEOP special case

The LP max⁡3x+2y\max 3x + 2y s.t. x+y≤6x+y \le 6, 2x+y≤82x+y \le 8, x,y≥0x,y \ge 0 — Chapter 1's objective A, now with the grid removed. Linear objective on a polyhedron: the optimum sits at a vertex, and enumerating the four feasible vertices finds it: (2,4)(2,4) at value 14 — the same point the grid crowned, now with the geometry explaining why. Classical Problems are GEOP Special Cases (Prop.): LP is the GEOP with linear everything and no dynamics.

fig, ax = plt.subplots(figsize=(6.4,5.0))
xs = np.linspace(0,6,50)
ax.fill([0,0,2,4],[0,6,4,0], color="#9CC3B2", alpha=.45, label="feasible polyhedron")
ax.plot(xs, 6-xs, c="#1B6B52", lw=1.5); ax.plot(xs, 8-2*xs, c="#1B6B52", lw=1.5)
for v in VERTS:
    ax.scatter(*v, c="#0B3D2E", s=90, zorder=5)
    ax.annotate(f"{v} → {lp_val(v)}", v, textcoords="offset points", xytext=(8,6), fontsize=10)
ax.set(xlim=(-0.3,6.3), ylim=(-0.3,6.6), xlabel="x", ylabel="y", title="Vertex enumeration: the optimum is at (2,4)")
ax.legend(frameon=False, fontsize=9); ax.grid(alpha=.2); plt.tight_layout(); plt.show()
vstar = max(VERTS, key=lp_val)
print(f"optimal vertex {vstar}, value {lp_val(vstar)}")
Vertex enumeration: the optimum is at (2,4)
optimal vertex (2, 4), value 14

Validation — agrees with DCT_V2_Ch02_Lab.xlsx

ref = reference_values()
expected = {"u0_star":6.0,"J_star":29.7914,"J_even":29.2172,"J_backload":28.53,
 "equivalence_maxdiff":0.0,"lp_opt_value":14,"lp_x":2,"lp_y":4,"n_vertices":4}
for k,v in expected.items():
    assert abs(ref[k]-v)<5e-4, f"MISMATCH {k}"
    print(f"PASS  {k:20s} {ref[k]}")
print("\nAll checkpoints agree — seed 26202.")
PASS  u0_star              6.0
PASS  J_star               29.7914
PASS  J_even               29.2172
PASS  J_backload           28.53
PASS  equivalence_maxdiff  0.0
PASS  lp_opt_value         14
PASS  lp_x                 2
PASS  lp_y                 4
PASS  n_vertices           4

All checkpoints agree — seed 26202.

Next: Exercises 2.5–2.9 (Part C) vary persistence and horizon; AXIOM-02's canonical-form console rewrites your GEOP into terminal form live. Chapter 3 makes convexity the reason all of this is solvable. Solutions: IM Vol. II, Ch. 2.