Contents
Deep Breakdown
What it tells me (Situation Awareness): The cancellation identities express the inverse relationship between exponentiation and logarithm with the same base : they undo each other. Two forms: (1) — exponentiating a logarithm recovers the original argument; (2) — taking the logarithm of an exponential recovers the original exponent. Together they confirm that and are inverse functions: and . The natural-base versions are the most common in DA/DS: and . These identities appear everywhere: the softmax function involves , log-likelihood maximization takes of exponential families, the logistic function is , KL divergence uses , and the Box-Cox transformation uses as the limiting case. Understanding cancellation is essential for simplifying composed expressions and for computing derivatives via the chain rule.
Flowchart
Real-world use
Where it is used
Log-likelihood of exponential family: for a Poisson distribution, . Taking log: . The identity directly cancels the exponent. Sigmoid/logit inverse: ; the logit function inverts it: , using . KL divergence simplification: — involves repeated cancellations in exponential family models.
Problem it solves
Composed expressions like look complex until the cancellation identity simplifies them to . Without recognizing the inverse relationship, deriving gradients of log-likelihood functions for exponential family distributions would require tedious algebra. The identity makes simplification immediate.
How it solves the problem
From the definition: . Substituting into gives . Conversely, because has the property that (using the power rule for logarithms with ).
Example in a business
A data scientist works with a log-linear demand model: . To estimate , they take logs of both sides: . This step uses — the cancellation identity converts a nonlinear model into a linear regression. The identity is the algebraic foundation of log-linear modeling.
The formula, piece by piece
Breaking the notation:
-
: the base exponential cancels the .
-
is the exponent to which must be raised to get .
-
Raising to that exponent gives back . No surprise: that's the definition.
-
: the logarithm base cancels the base- exponent.
-
is an exponential. Taking of it extracts the exponent .
-
Both hold for , , (for the first form), (for the second). Natural base versions (most used in practice):
-
(for ).
-
(for all real ). Base-10 versions:
-
.
-
. TRAP: bases must match: if .
Example: . Both the exponential base and the log base must be the same.
The formula in words
": exponentiating undoes the logarithm. : the logarithm undoes the exponentiation. They are inverse functions. In natural logs: and . Use these to: simplify directly, convert log-linear models to linear form by taking of both sides, and eliminate from exponential family log-likelihoods. TRAP: bases must match. ."
Critical Concepts
- Inverse functions: and are inverses. The cancellation identities are the formal expression of this: composing them in either order returns the identity function. This is the most fundamental fact about logarithms.
- Natural log is the default: in ML and statistics, is assumed unless otherwise stated. and are used constantly in gradient derivations, likelihood functions, and activation functions.
- Log-linear model transformation: transforms to via . This linearization is the basis of Poisson regression, log-normal regression, and exponential family GLMs.
- Logit is the inverse of sigmoid: ; logit . This uses implicitly. The logit is the inverse link function in logistic regression.
- TRAP: mismatched bases: .
The cancellation requires identical bases. A frequent error in information-theoretic computations that mix nats and bits.
Step-by-step calculation (tiny example)
Task: simplify and evaluate at .
Step 1: Recognize the form — this is with .
Step 2: Apply cancellation .
Step 3: Evaluate at .
Step 4: Verify directly .
Step 5: Reverse direction — compute directly. Verify: ; .
Code examples
Beginner example (Python)
# Cancellation identities: e^(ln x) = x and ln(e^x) = x
import math
import numpy as np
# Form 1: a^(log_a x) = x
print("Form 1: a^(log_a x) = x — exponentiating undoes the log")
test_values = [0.1, 1.0, 2.0, math.e, 10.0, 100.0]
print(f"{'x':>8} {'ln(x)':>10} {'e^(ln x)':>12} {'match x':>8}")
for x in test_values:
ln_x = math.log(x)
recovered = math.exp(ln_x)
print(f"{x:>8.4f} {ln_x:>10.6f} {recovered:>12.6f} {str(abs(recovered - x) < 1e-9):>8}")
# Form 2: log_a(a^x) = x
print("\nForm 2: ln(e^x) = x — log undoes the exponent")
exponents = [-3.0, -1.0, 0.0, 1.0, 2.5, 10.0]
print(f"{'x':>8} {'e^x':>12} {'ln(e^x)':>10} {'match x':>8}")
for x in exponents:
exp_x = math.exp(x)
recovered = math.log(exp_x)
print(f"{x:>8.4f} {exp_x:>12.6f} {recovered:>10.6f} {str(abs(recovered - x) < 1e-9):>8}")
# TRAP: mismatched bases — e^(log2 x) ≠ x
print("\nTRAP: e^(log2 x) ≠ x (mismatched bases)")
for x in [2.0, 4.0, 8.0]:
log2_x = math.log2(x)
e_pow_log2 = math.exp(log2_x) # e^(log2 x) ≠ x
print(f" x={x:.0f} log2(x)={log2_x:.4f} e^(log2 x)={e_pow_log2:.4f} equals x: {abs(e_pow_log2 - x) < 1e-9}")
# Log-linear model: ln(e^(ax+b)) = ax+b
print("\nLog-linear model simplification: ln(e^(ax+b)) = ax+b")
a_coef, b_coef = 2.5, -1.0
for x_val in [0.0, 1.0, 2.0, -1.0]:
lhs = math.log(math.exp(a_coef * x_val + b_coef))
rhs = a_coef * x_val + b_coef
print(f" x={x_val:5.1f} ln(e^(ax+b))={lhs:.6f} ax+b={rhs:.6f} match={abs(lhs - rhs) < 1e-9}")Beginner example (R)
# Cancellation identities in R: e^(ln x) = x and ln(e^x) = x
# Form 1
cat("Form 1: e^(ln x) = x\n")
test_values <- c(0.1, 1, 2, exp(1), 10, 100)
for (x in test_values) {
recovered <- exp(log(x))
cat(sprintf(" x=%-8.4f ln(x)=%-10.6f e^ln(x)=%-10.6f match=%s\n", x, log(x), recovered, abs(recovered - x) < 1e-9))
}
# Form 2
cat("\nForm 2: ln(e^x) = x\n")
exponents <- c(-3, -1, 0, 1, 2.5, 10)
for (x in exponents) {
recovered <- log(exp(x))
cat(sprintf(" x=%-8.4f e^x=%-12.6f ln(e^x)=%-10.6f match=%s\n", x, exp(x), recovered, abs(recovered - x) < 1e-9))
}
# Log-linear model
a_coef <- 2.5; b_coef <- -1.0
cat("\nLog-linear: ln(e^(ax+b)) = ax+b\n")
for (x_val in c(0, 1, 2, -1)) {
lhs <- log(exp(a_coef * x_val + b_coef))
rhs <- a_coef * x_val + b_coef
cat(sprintf(" x=%5.1f lhs=%.6f rhs=%.6f match=%s\n", x_val, lhs, rhs, abs(lhs - rhs) < 1e-9))
}Professional example (Python)
import numpy as np
import pandas as pd
# Scenario: verify the cancellation identity in a log-linear demand model
# Model: log(demand) = X @ beta (linear on log scale)
# Demonstrate the round-trip: predict on log scale, exponentiate, compare to original
np.random.seed(42)
N = 500
N_FEATURES = 3
# True coefficients (log-linear model)
beta_true = np.array([4.0, -0.5, 0.3]) # intercept + 2 features
feature_matrix = np.column_stack([
np.ones(N),
np.random.normal(10, 2, N), # price
np.random.normal(5, 1, N), # discount_pct
])
log_demand_true = feature_matrix @ beta_true + np.random.normal(0, 0.2, N)
demand_true = np.exp(log_demand_true) # back to demand scale
def log_linear_predict(
features: np.ndarray,
coefficients: np.ndarray,
) -> tuple[np.ndarray, np.ndarray]:
"""Predict from a log-linear model.
Uses: e^(ln(demand)) = demand (cancellation identity)
Args:
features: Feature matrix (n_samples x n_features).
coefficients: Model coefficients vector.
Returns:
Tuple of (log_predictions, demand_predictions).
"""
log_preds = features @ coefficients # linear on log scale
demand_preds = np.exp(log_preds) # e^(log_preds) = preds
return log_preds, demand_preds
log_preds, demand_preds = log_linear_predict(feature_matrix, beta_true)
# Verify the round-trip: ln(e^(X@beta)) = X@beta
log_of_exp = np.log(demand_preds) # ln(e^(X@beta)) should = X@beta
round_trip_error = np.max(np.abs(log_of_exp - log_preds))
# Report
report_df = pd.DataFrame({
"demand_true": demand_true[:5].round(2),
"log_preds": log_preds[:5].round(4),
"demand_preds": demand_preds[:5].round(2),
"ln_demand": log_of_exp[:5].round(4),
})
print("Log-Linear Model: e^(ln(demand)) = demand (Cancellation Identity)")
print("=" * 72)
print(report_df.to_string(index=False))
print(f"\nRound-trip max error |ln(e^(Xβ)) - Xβ|: {round_trip_error:.2e}")
print(f"RMSE (log scale): {np.sqrt(np.mean((log_preds - log_demand_true)**2)):.4f}")
print(f"RMSE (demand): {np.sqrt(np.mean((demand_preds - demand_true)**2)):.4f}")Professional example (R)
# Log-linear model: e^(ln(demand)) = demand (cancellation)
set.seed(42)
n <- 100
X <- cbind(1, log(runif(n, 10, 100)))
beta <- c(2, 0.5)
log_demand_true <- X %*% beta
demand_true <- exp(log_demand_true)
log_preds <- log_demand_true + rnorm(n, 0, 0.1)
demand_preds <- exp(log_preds)
round_trip_error <- max(abs(log(exp(log_preds[1:5])) - log_preds[1:5]))
cat("Log-Linear: e^(ln(demand)) = demand\n")
cat(sprintf("Round-trip max error: %.2e RMSE (demand): %.4f\n", round_trip_error, sqrt(mean((demand_preds - demand_true)^2))))Source: MFB p. 143