admm

Contents

  • 1. Overview
  • 2. Installation
    • 2.1. Supported Platforms
    • 2.2. Install ADMM Python Library
      • 2.2.1. Install from PyPI
      • 2.2.2. Install from Source
      • 2.2.3. Isolated Python Environment
      • 2.2.4. Installation Verification
      • 2.2.5. Troubleshooting
  • 3. User Guide
    • 3.1. Minimal Model
    • 3.2. Supported Problem Structure
      • 3.2.1. Map This Abstract Form to Code
      • 3.2.2. Support Boundary
    • 3.3. Modeling Workflow
    • 3.4. Variables
      • 3.4.1. Choose the Shape First
      • 3.4.2. Attributes vs. Explicit Constraints
      • 3.4.3. Accessing Solution Values
      • 3.4.4. Warm Start
      • 3.4.5. Basic Operators
      • 3.4.6. Variable Shapes and Transformations
    • 3.5. Parameters
    • 3.6. Objective
      • 3.6.1. Build the Objective in Layers
      • 3.6.2. Common Objective Ingredients
    • 3.7. Constraints
      • 3.7.1. How to Choose the Direct Form
      • 3.7.2. Walkthrough: Projecting Onto a Feasible Set
    • 3.8. Solver Options
    • 3.9. Solve the Model
      • 3.9.1. Read Results in This Order
      • 3.9.2. Error Handling and Troubleshooting
      • 3.9.3. What to Do When the Solve Does Not Succeed
    • 3.10. Model Save and Reload
      • 3.10.1. What Is Saved
      • 3.10.2. What Is Not Saved
      • 3.10.3. Compression
      • 3.10.4. Example: Save, Reload, and Re-solve
    • 3.11. Supported Building Blocks
      • 3.11.1. Three Modeling Roles
      • 3.11.2. Worked Example: One Model, Three Roles
      • 3.11.3. Elementwise Atoms
      • 3.11.4. Vector and Matrix Atoms
      • 3.11.5. Structural Variable Attributes and Domain Constraints
      • 3.11.6. Compact Atom Reference
    • 3.12. Symbolic Canonicalization
      • 3.12.1. Write Clean Math First
      • 3.12.2. Walkthrough: Readable Math, Recognized Structure
      • 3.12.3. Mathematical Rewrite Examples
      • 3.12.4. Transform Examples With Auxiliary Variables
    • 3.13. User-Defined Proximal Extensions
      • 3.13.1. What a UDF Provides
      • 3.13.2. Walkthrough: The L0 Norm as a UDF
      • 3.13.3. Walkthrough: Log-Cosh Loss via grad
  • 4. Examples
    • 4.1. Linear Program
    • 4.2. Quadratic Program
    • 4.3. Semidefinite Program
    • 4.4. Second-Order Cone Program
    • 4.5. Least Squares
    • 4.6. Ridge Regression
    • 4.7. Huber Regression
    • 4.8. Sparse Logistic Regression
    • 4.9. SVM with L1 Regularization
    • 4.10. Quantile Regression
    • 4.11. Robust PCA
    • 4.12. Sparse Inverse Covariance Selection
    • 4.13. Entropy Maximization
    • 4.14. Fault Detection
    • 4.15. Water Filling
    • 4.16. Convolutional Image Deblurring
    • 4.17. Portfolio Optimization
    • 4.18. L0 Norm
    • 4.19. L0 Ball Indicator
    • 4.20. L1/2 Quasi-Norm
    • 4.21. Group Sparsity
    • 4.22. Matrix Rank Function
    • 4.23. Rank-r Indicator
    • 4.24. The Unit-Sphere Indicator
    • 4.25. The Stiefel-Manifold Indicator
    • 4.26. The Simplex Indicator
    • 4.27. The Binary Indicator
    • 4.28. L0-Regularized Regression
    • 4.29. Log-Cosh Robust Regression
    • 4.30. Cauchy Loss Robust Regression
    • 4.31. Smooth Quantile Regression
    • 4.32. Wing Loss for Precise Regression
    • 4.33. Smooth Total Variation Denoising
    • 4.34. Gamma Regression (GLM with Log Link)
  • 5. Python API
    • 5.1. Global functions
      • 5.1.1. Functions
    • 5.2. ADMMError
      • ADMMError
    • 5.3. OptionConstClass
      • OptionConstClass
    • 5.4. TensorLike
      • TensorLike
    • 5.5. Constant
      • Constant
    • 5.6. Var
      • Var
    • 5.7. Param
      • Param
    • 5.8. Constr
      • Constr
    • 5.9. TuningContext
      • TuningContext
    • 5.10. UDFBase
      • UDFBase
    • 5.11. Model
      • Model
    • 5.12. ArrayLike
      • ArrayLike
  • 6. Citing ADMM
  • 7. Contact
admm
  • 4. Examples
  • 4.34. Gamma Regression (GLM with Log Link)

4.34. Gamma Regression (GLM with Log Link)¶

This example shows how to package a Gamma regression loss — a generalized linear model (GLM) for positive-valued responses — as a gradient-based UDF. The full model is

\[\begin{split}\begin{array}{ll} \min\limits_\mu & \displaystyle\sum_{i=1}^{n} \bigl(y_i e^{-\mu_i} + \mu_i\bigr) \;+\; \tfrac{\lambda}{2}\|\mu\|_2^2 \\[6pt] \text{s.t.} & -5 \le \mu_i \le 10. \end{array}\end{split}\]

Here \(\mu_i = \log(\mathbb{E}[y_i])\) is the log-scale parameter (log link), and \(y_i > 0\) is the observed positive response. The Gamma deviance \(y e^{-\mu} + \mu\) has no closed-form proximal operator, but its gradient is trivial — making it a natural fit for the grad UDF path.

The Gamma distribution is a standard model for positive, right-skewed data:

  • Insurance: claim amounts

  • Survival analysis: waiting times, durations

  • Environmental science: rainfall, pollutant concentrations

The log link \(\mathbb{E}[y] = e^\mu\) ensures positivity of the predicted mean without explicit positivity constraints.

The function value returned by UDFBase.eval() sums the Gamma deviance over all observations:

\[f(\mu) = \sum_i \bigl(y_i \, e^{-\mu_i} + \mu_i\bigr).\]

This function is convex, with a unique minimum at \(\mu_i = \log(y_i)\) (the sample log-mean). So eval computes:

def eval(self, arglist):
    mu = np.asarray(arglist[0], dtype=float).ravel()
    return float(np.sum(self.y * np.exp(-mu) + mu))

The gradient returned by UDFBase.grad() is

\[\nabla f(\mu)_i = -y_i \, e^{-\mu_i} + 1,\]

which is zero exactly at \(\mu_i = \log(y_i)\). The implementation:

def grad(self, arglist):
    mu = np.asarray(arglist[0], dtype=float).ravel()
    return [(-self.y * np.exp(-mu) + 1.0).reshape(arglist[0].shape)]

Note the .reshape(arglist[0].shape) at the end — this ensures the gradient has the same shape as the input, which is important when the solver passes 2-D arrays.

The UDFBase.arguments() method returns the single optimization variable. The observed data \(y\) is a fixed parameter stored as an instance attribute:

def arguments(self):
    return [self.arg]

This pattern — storing fixed data in __init__ while listing only the optimization variable in arguments — is the standard way to embed problem data in a UDF.

Complete runnable example:

import admm
import numpy as np

class GammaRegressionLoss(admm.UDFBase):
    """Gamma regression loss (log link): f(mu) = sum(y*exp(-mu) + mu).

    The minimum is at mu_i = log(y_i).
    Gradient: -y*exp(-mu) + 1.

    Parameters
    ----------
    arg : admm.Var
        The log-scale parameter mu.
    y : array
        Observed positive responses.
    """
    def __init__(self, arg, y):
        self.arg = arg
        self.y = np.asarray(y, dtype=float)

    def arguments(self):
        return [self.arg]

    def eval(self, arglist):
        mu = np.asarray(arglist[0], dtype=float).ravel()
        return float(np.sum(self.y * np.exp(-mu) + mu))

    def grad(self, arglist):
        mu = np.asarray(arglist[0], dtype=float).ravel()
        return [(-self.y * np.exp(-mu) + 1.0).reshape(arglist[0].shape)]

# Generate Gamma-distributed data
np.random.seed(314)
n = 30
mu_true = np.random.uniform(0.5, 3.0, size=n)
k = 5.0  # shape parameter
y = np.random.gamma(shape=k, scale=np.exp(mu_true) / k, size=n)

model = admm.Model()
mu = admm.Var("mu", n)
model.setObjective(GammaRegressionLoss(mu, y) + 0.025 * admm.sum(admm.square(mu)))
model.addConstr(mu >= -5)
model.addConstr(mu <= 10)
model.optimize()

mu_val = np.asarray(mu.X).ravel()
print(" * status:", model.StatusString)  # Expected: SOLVE_OPT_SUCCESS
print(f" * RMSE: {np.sqrt(np.mean((mu_val - mu_true) ** 2)):.4f}")  # Expected: ≈ 0.42
print(f" * Correlation: {np.corrcoef(np.exp(mu_val), np.exp(mu_true))[0,1]:.4f}")

This example is available as a standalone script in the examples/ folder of the ADMM repository:

python examples/udf_grad_gamma_regression.py

This example demonstrates how ADMM’s constraint handling composes naturally with custom smooth losses through the grad path. The box constraints \(-5 \le \mu \le 10\) prevent numerical instability in \(e^{-\mu}\), while the L2 regularizer shrinks the estimates toward zero. The Gamma regression UDF recovers the log-mean parameters with an RMSE comparable to the unregularized MLE (\(\hat\mu_i = \log y_i\)).

Previous Next

© Copyright 2026, Decision Intelligence Lab @ DAMO Academy. Last updated on Apr 12, 2026.

Built with Sphinx using a theme provided by Read the Docs.