Learning Curve Modeling Approaches

Learning curves are mathematical models predicting improvements in productivity and efficiency as experience with a task increases. These curves are essential tools for:

  • Estimating project costs and timelines.
  • Analyzing historical data for efficiency trends.
  • Forecasting and decision-making.

The following documentation covers three popular methods implemented using Julia with multiple dispatch:

Learning Curve Methods

The learning curve methods are implemented as an abstract type hierarchy:

  • LearningCurveMethod: Abstract base type
  • WrightMethod: Wright's cumulative-average model
  • CrawfordMethod: Crawford's unit-time model
  • ExperienceMethod: Experience curve model

Wright's Curve

MCHammer.WrightMethodType

Wright learning curve method.

struct WrightMethod <: LearningCurveMethod end

Introduced by T.P. Wright in 1936 in his seminal work on airplane production cost analysis (Wright, 1936). This model observes that with each doubling of cumulative production, the unit cost decreases by a fixed percentage. It is well‑suited for processes where learning is continuous and gradual.

Parameters (package-wide convention)

  • Learning = progress ratio LR in (0,1] (e.g. 0.85 = 85%)
  • b = log(Learning)/log(2) (negative when there is learning)
  • InitialEffort = first‑unit cost C₁

Implementation returns cumulative total cost (cumulative‑average form):

\[\mathrm{Total}(N)=C_1\,N^{\,b+1},\qquad b=\frac{\log(\mathrm{LR})}{\log 2}\]

Unit‑cost form (reference):

\[C_N = C_1\,N^{\,b}\]

When to Use

  • When historical data show a smooth, predictable decline in unit costs as production doubles.

When to Avoid

  • When cost reductions occur in discrete steps or when the production process experiences structural changes.
source

Crawford's Curve

MCHammer.CrawfordMethodType

Crawford learning curve method.

struct CrawfordMethod <: LearningCurveMethod end

Crawford models per‑unit learning discretely and accumulates unit costs.

Parameters

  • Learning = progress ratio LR in (0,1]
  • b = log(Learning)/log(2)
  • InitialEffort = first‑unit cost C₁

Implementation returns cumulative total cost (discrete sum):

\[\mathrm{Total}(N)=\sum_{i=1}^N C_1\, i^{\,b}\]

Per‑unit cost (reference):

\[C_i = C_1\, i^{\,b}\]

source

Experience Curve

MCHammer.ExperienceMethodType

Experience learning curve method.

struct ExperienceMethod <: LearningCurveMethod end

BCG/Excel-style experience curve where the exponent equals the progress ratio LR. This matches spreadsheet formulas like C1 * N^(LR); e.g., with LR=0.8 the total is C1 * N^0.8.

Parameters

  • Learning = progress ratio LR in (0,1]
  • InitialEffort = average cost at N=1 (ar{C}_1)

Implementation returns cumulative total cost:

\[\mathrm{Total}(N)=\bar{C}_1\,N^{\,\mathrm{LR}}\]

When to Use

  • Strategic/competitive planning when broad efficiency improvements are observed and spreadsheet convention is desired.

When to Avoid

  • When per‑unit discreteness dominates (see CrawfordMethod).
source

Cumulative Cost Analysis

To compute cumulative cost analytically for an experience curve, here are the functions to accomplish this.

Wright Learning Curve

# compute the cumulative total cost for 500 units with a progress ratio of 0.85
result = lc_analytic(WrightMethod(), 200, 500, 0.85)
println(result)
23290.84865742685

Crawford Learning Curve

# compute the cumulative total cost for 500 units with a progress ratio of 0.85
result = lc_analytic(CrawfordMethod(), 200, 500, 0.85)
println(result)
30290.08483739403

Experience Curve

# compute the cumulative total cost for 500 units with a progress ratio of 0.85
result = lc_analytic(ExperienceMethod(), 200, 500, 0.85)
println(result)
39369.01049745011

Curve Functions

Generates detailed DataFrame including cumulative, incremental, and average costs.

MCHammer.lc_curveFunction
lc_curve(method::LearningCurveMethod,
         InitialEffort::Real,
         StartUnit::Integer,
         TotalUnits::Integer,
         Learning::Real;
         steps::Integer=1) -> DataFrame

Build a table of cumulative and per-unit costs.

Columns:

  • Units — cumulative units at this row (StartUnit:steps:TotalUnits)
  • CumulativeCost — total cost up to Units (via lc_analytic)
  • Incrementalper-unit cost at Units (C_N)
    • Wright/Experience: T(N) - T(N-1) where T(·) is the cumulative total
    • Crawford: direct unit cost C_N = C₁ · N^b, with b = log(LR)/log(2)
  • AvgCostCumulativeCost / Units
  • Method — method name
source

Wright Learning Curve

Generate a table of cumulative and per‑unit costs for Wright’s model using initial cost 200, from unit 1 to 500, progress ratio 0.85, sampling every 25 units

df = lc_curve(WrightMethod(), 200, 1, 500, 0.85; steps=25)
println(first(df, 5))
5×5 DataFrame
 Row │ Units    CumulativeCost  Incremental  AvgCost   Method
     │ Float64  Float64         Float64      Float64   String
─────┼────────────────────────────────────────────────────────
   1 │     1.0          200.0      200.0     200.0     Wright
   2 │    26.0         2422.37      71.6503   93.1682  Wright
   3 │    51.0         4057.27      61.0428   79.5544  Wright
   4 │    76.0         5506.28      55.5498   72.451   Wright
   5 │   101.0         6845.54      51.9466   67.7776  Wright

Crawford Learning Curve

Generate a table of cumulative and per‑unit costs for Crawford’s model using initial cost 200, from unit 1 to 500, progress ratio 0.85, sampling every 25 units

df = lc_curve(CrawfordMethod(), 200, 1, 500, 0.85; steps=25)
println(first(df, 5))
5×5 DataFrame
 Row │ Units    CumulativeCost  Incremental  AvgCost   Method
     │ Float64  Float64         Float64      Float64   String
─────┼──────────────────────────────────────────────────────────
   1 │     1.0          200.0      200.0     200.0     Crawford
   2 │    26.0         3053.31      93.1682  117.435   Crawford
   3 │    51.0         5182.18      79.5544  101.611   Crawford
   4 │    76.0         7071.44      72.451    93.0452  Crawford
   5 │   101.0         8818.55      67.7776   87.3124  Crawford

Experience Curve

Generate a table of cumulative and per‑unit costs for the Experience model using initial cost 200, from unit 1 to 500, progress ratio 0.85, sampling every 25 units

df = lc_curve(ExperienceMethod(), 200, 1, 500, 0.85; steps=25)
println(first(df, 5))
5×5 DataFrame
 Row │ Units    CumulativeCost  Incremental  AvgCost  Method
     │ Float64  Float64         Float64      Float64  String
─────┼───────────────────────────────────────────────────────────
   1 │     1.0          200.0      200.0     200.0    Experience
   2 │    26.0         3189.76     104.586   122.683  Experience
   3 │    51.0         5655.42      94.3966  110.891  Experience
   4 │    76.0         7938.19      88.8705  104.45   Experience
   5 │   101.0        10108.9       85.1382  100.088  Experience

Analysis Functions

Fitting Functions

MCHammer.lc_fitFunction
lc_fit(::LearningCurveMethod, n1, x1, n2, x2) -> (b, p)

Generic two‑point fit for a power law x = a n^b. Returns the slope b and the progress ratio p = 2^b.

source

Example:

The function lc_fit estimates the slope $b$ and progress ratio $p = 2^b$ from two observations. Given two points at units $n_1$ and $n_2$ with corresponding costs $x_1$ and $x_2$, we can estimate $b$ and $p$ for any of the learning‑curve methods. The following example uses the same data for Wright, Crawford and Experience models. Though the results are identical, the derivations are different.

# two observation points
n1, x1 = 8, 200.0
n2, x2 = 32, 140.0

# estimate (b, progress ratio) for each method using the same inputs
(b_w, L_w) = lc_fit(WrightMethod(),    n1, x1, n2, x2)
(b_c, L_c) = lc_fit(CrawfordMethod(),  n1, x1, n2, x2)
(b_e, L_e) = lc_fit(ExperienceMethod(),n1, x1, n2, x2)

((b_w, L_w), (b_c, L_c), (b_e, L_e))
((-0.2572865864148791, 0.8366600265340756), (-0.2572865864148791, 0.8366600265340756), (-0.2572865864148791, 0.8366600265340756))

Learning Rate Estimation

Estimates learning rates using Wright's method from two data points.

MCHammer.learn_rateFunction
learn_rate(::WrightMethod, n1, y1, n2, y2; mode=:avg) -> Float64

Estimate Wright progress ratio p from two observations.

  • If mode = :avg (default), y values are cumulative averages at n1 and n2:

\[b = \frac{\ln(y_2/y_1)}{\ln(n_2/n_1)}, \quad p = 2^b.\]

  • If mode = :total or mode = :cumulative, y values are cumulative totals at n1 and n2. First converts to averages, then applies average formula.
  • If mode = :unit, y values are unit times at n1 and n2. The function solves for b from the unit‑increment relation and returns p = 2^b.
  • If mode = :auto (default), automatically detects data type: if y2 > y1, assumes :total mode; otherwise :avg mode.
source
learn_rate(::WrightMethod, n::AbstractVector, y::AbstractVector; mode=:auto) -> Float64

Estimate Wright progress ratio p from ≥3 points. If mode = :auto (default), fits both average and unit models and picks the lower SSE. Set mode=:avg or :unit to force a specific interpretation.

source
learn_rate(::CrawfordMethod, n1, y1, n2, y2; mode=:auto) -> Float64

Two-point fit for Crawford's model with multiple data types.

  • If mode = :unit, y values are per-unit costs at units n1 and n2: y(i) = C1 * i^b.
  • If mode = :avg, y values are cumulative averages at n1 and n2. Uses the exact discrete-sum relation A(N) = (C₁/N) · Sb(N) with Sb(N) = ∑ i^b and solves for b.
  • If mode = :total or mode = :cumulative, y values are cumulative totals at n1 and n2. Uses T(N) = C₁ · S_b(N) and solves for b.
  • If mode = :auto (default), automatically detects: if y2 > y1, assumes :total; otherwise :unit.

Returns the learning rate p.

source
learn_rate(::ExperienceMethod, n1, y1, n2, y2; mode=:auto) -> Float64

Two‑point fit for the Experience curve with multiple data types.

  • If mode = :avg, y values are cumulative averages at n1 and n2. For T(N) = C₁ * N^LR, avg(N) = C₁ * N^(LR-1).
  • If mode = :total or mode = :cumulative, y values are cumulative totals at n1 and n2. T(N) = C₁ * N^LR.
  • If mode = :unit, y values are per-unit costs at n1 and n2. Uses the exact incremental relation ΔT(N) = T(N) − T(N−1) = C̄₁ · [N^LR − (N−1)^LR] and solves numerically for LR from two points.
  • If mode = :auto (default), automatically detects: if y2 > y1, assumes :total; otherwise :avg.

Returns LR (e.g., 0.8).

source
rate = learn_rate(WrightMethod(), 1, 2000, 144, 1600)
println(rate)
0.9693571494126194

Comparison Utility

Compares learning curves across a range of learning rates.

MCHammer.learn_ratesFunction
learn_rates(InitialEffort, TotalUnits; LR_step=0.1) -> DataFrame

Compare cumulative total cost across methods for a sweep of progress ratios LR in (0, 1].

Totals at N = TotalUnits:

  • Wright: T_W(N) = C₁ * N^(1 + b), with b = log(LR) / log(2)
  • Crawford: TC(N) = ∑{i=1}^N C₁ * i^b, with b = log(LR) / log(2)
  • Experience: T_E(N) = C₁ * N^(LR)
source

Example:

rates_df = learn_rates(100, 500; α_step=0.05)
println(first(rates_df, 5))

Picking the right curve

Sometimes picking the right curve is challenging and in these cases plotting a comparison of average costs across methods using Plots.jl can be very helpful.

# Generate sample tables for each method and plot the average cost across units.
CC = lc_curve(CrawfordMethod(), 50, 1, 1000, 0.85; steps=25)
WC = lc_curve(WrightMethod(), 50, 1, 1000, 0.85; steps=25)
EC = lc_curve(ExperienceMethod(), 50, 1, 1000, 0.85; steps=25)

# Combine the results
GraphResults = vcat(CC, WC, EC)
first(GraphResults,5)
5×5 DataFrame
RowUnitsCumulativeCostIncrementalAvgCostMethod
Float64Float64Float64Float64String
11.050.050.050.0Crawford
226.0763.32823.292129.3588Crawford
351.01295.5419.888625.4028Crawford
476.01767.8618.112823.2613Crawford
5101.02204.6416.944421.8281Crawford

Create and display the plot

using Plots
plot(GraphResults.Units, GraphResults.AvgCost, group=GraphResults.Method,
           xlabel="Units", ylabel="Average Cost per Unit",
           title="Learning Curves Comparison",
           lw=2, legend=:topright)

Mathematical Notes

Symbols:

  • α: learning exponent (progress ratio = $2^{b}$)
  • N: number of units

Wright's Law (Cumulative Average Model):

\[\text{Cumulative Average Cost}_N = \text{Initial} \times N^{-\alpha}\]

Crawford's Law (Unit Cost Model):

\[\text{Unit Cost}_N = \text{Initial} \times N^{-\alpha}\]

Experience Curve:

\[\text{Cost}_N = \text{Initial} \times N^{-\alpha}\]

Sources & References

  • Eric Torkia, Decision Superhero Vol. 2, chapter 6 : SuperPower: The Laws of Nature that Predict, Technics Publishing, 2025
  • Available on Amazon : https://a.co/d/4YlJFzY . Volumes 2 and 3 to be released in Spring and Fall 2025.
  • Wright, T.P. (1936). Factors Affecting the Cost of Airplanes. Journal of the Aeronautical Sciences, 3(4), 122–128.
  • Henderson, B.D. (1973). Industrial Experience, Technology Transfer, and Cost Behavior. Harvard Business School Working Paper.
  • Crawford, D. (1982). Learning Curves: Theory and Practice. Journal of Cost Analysis.