33.3 Pedantic mode

Pedantic mode is a compilation option built into Stanc3 that warns you about potential issues in your Stan program.

For example, consider the following program.

data {
  int N;
  array[N] real x;
}
parameters {
  real sigma;
}
model {
  real mu;
  x ~ normal(mu, sigma);
}

When pedantic mode is turned on, the compiler will produce the following warnings.

Warning:
  The parameter sigma has no priors.
Warning at 'ped-mode-ex1.stan', line 10, column 14 to column 16:
  The variable mu may not have been assigned a value before its use.
Warning at 'ped-mode-ex1.stan', line 10, column 18 to column 23:
  A normal distribution is given parameter sigma as a scale parameter
  (argument 2), but sigma was not constrained to be strictly positive.

Here are the kinds of issues that pedantic mode will find (which are described in more detail in following sections):

  • Distribution usages issues. Distribution arguments don’t match the distribution specification, or some specific distribution is used in an inadvisable way.
  • Unused parameter. A parameter is defined but doesn’t contribute to target.
  • Large or small constant in a distribution. Very large or very small constants are used as distribution arguments.
  • Control flow depends on a parameter. Branching control flow (like if/else) depends on a parameter value .
  • Parameter has multiple twiddles. A parameter is on the left-hand side of multiple twiddles.
  • Parameter has zero or multiple priors. A parameter has zero or more than one prior distribution.
  • Variable is used before assignment. A variable is used before being assigned a value.
  • Strict or nonsensical parameter bounds. A parameter is given questionable bounds.

Some important limitations of pedantic mode are listed at the end of this chapter.

33.3.1 Distribution argument and variate constraint issues

When an argument to a built-in distribution certainly does not match that distribution’s specification in the Stan Functions Reference, a warning is thrown. This primarily checks if any distribution argument’s bounds at declaration, compile-time value, or subtype at declaration (e.g. simplex) is incompatible with the domain of the distribution. x

For example, consider the following program.

parameters {
  real unb_p;
  real<lower=0> pos_p;
}
model {
  1 ~ poisson(unb_p);
  1 ~ poisson(pos_p);
}

The parameter of poisson should be strictly positive, but unb_p is not constrained to be positive.

Pedantic mode produces the following warning.

Warning at 'ex-dist-args.stan', line 6, column 14 to column 19:
  A poisson distribution is given parameter unb_p as a rate parameter
  (argument 1), but unb_p was not constrained to be strictly positive.

33.3.2 Special-case distribution issues

Pedantic mode checks for some specific uses of distributions that may indicate a statistical mistake:

33.3.2.1 Uniform distributions

Any use of uniform distribution generates a warning, except when the variate parameter’s declared upper and lower bounds exactly match the uniform distribution bounds. In general, assigning a parameter a uniform distribution can create non-differentiable boundary conditions and is not recommended.

For example, consider the following program.

parameters {
  real a;
  real<lower=0, upper=1> b;
}
model {
  a ~ uniform(0, 1);
  b ~ uniform(0, 1);
}

a is assigned a uniform distribution that doesn’t match its constraints.

Pedantic mode produces the following warning.

Warning at 'uniform-warn.stan', line 6, column 2 to column 20:
  Parameter a is given a uniform distribution. The uniform distribution is
  not recommended, for two reasons: (a) Except when there are logical or
  physical constraints, it is very unusual for you to be sure that a
  parameter will fall inside a specified range, and (b) The infinite gradient
  induced by a uniform density can cause difficulties for Stan's sampling
  algorithm. As a consequence, we recommend soft constraints rather than hard
  constraints; for example, instead of giving an elasticity parameter a
  uniform(0, 1) distribution, try normal(0.5, 0.5).

33.3.2.2 (Inverse-) Gamma distributions

Gamma distributions are sometimes used as an attempt to assign an improper prior to a parameter. Pedantic mode gives a warning when the Gamma arguments indicate that this may be the case.

33.3.2.3 lkj_corr distribution

Any use of the lkj_corr distribution generates a warning that suggests using the Cholesky variant instead. See https://mc-stan.org/docs/functions-reference/lkj-correlation.html for details.

33.3.3 Unused parameters

A warning is generated when a parameter is declared but does not have any effect on the program. This is determined by checking whether the value of the target variable depends in any way on each of the parameters.

For example, consider the following program.

parameters {
  real a;
  real b;
}
model {
  a ~ normal(1, 1);
}

a participates in the density function but b does not.

Pedantic mode produces the following warning.

Warning:
  The parameter b was declared but was not used in the density calculation.

33.3.4 Large or small constants in a distribution

When numbers with magnitude less than 0.1 or greater than 10 are used as arguments to a distribution, it indicates that some parameter is not scaled to unit value, so a warning is thrown. See https://mc-stan.org/docs/stan-users-guide/standardizing-predictors-and-outputs.html for a discussion of scaling parameters.

For example, consider the following program.

parameters {
  real x;
  real y;
}
model {
  x ~ normal(-100, 100);
  y ~ normal(0, 1);
}

The constants -100 and 100 suggest that x is not unit scaled.

Pedantic mode produces the following warning.

Warning at 'constants-warn.stan', line 6, column 14 to column 17:
  Argument -100 suggests there may be parameters that are not unit scale;
  consider rescaling with a multiplier (see manual section 22.12).
Warning at 'constants-warn.stan', line 6, column 19 to column 22:
  Argument 100 suggests there may be parameters that are not unit scale;
  consider rescaling with a multiplier (see manual section 22.12).

33.3.5 Control flow depends on a parameter

Control flow statements, such as if, for and while should not depend on parameters or functions of parameters to determine their branching conditions. This is likely to introduce a discontinuity into the density function. Pedantic mode generates a warning when any branching condition may depend on a parameter value.

For example, consider the following program.

parameters {
  real a;
}
model {
  // x depends on parameter a
  real x = a * a;

  int m;

  // the if-then-else depends on x which depends on a
  if(x > 0) {
    //now m depends on x which depends on a
    m = 1;
  } else {
    m = 2;
  }

  // for loop depends on m -> x -> a
  for (i in 0:m) {
    a ~ normal(i, 1);
  }
}

The if and for statements are control flow that depend (indirectly) on the value of the parameter m.

Pedantic mode produces the following warning.

Warning at 'param-dep-cf-warn.stan', line 11, column 2 to line 16, column 3:
  A control flow statement depends on parameter(s): a.
Warning at 'param-dep-cf-warn.stan', line 19, column 2 to line 21, column 3:
  A control flow statement depends on parameter(s): a.

33.3.6 Parameters with multiple twiddles

A warning is generated when a parameter is found on the left-hand side of more than one ~ statements (or an equivalent target += conditional density statement). This pattern is not inherently an issue, but it is unusual and may indicate a mistake.

Pedantic mode only searches for repeated statements, it will not for example generate a warning when a ~ statement is executed repeatedly inside of a loop.

For example, consider the following program.

data {
  real x;
}
parameters {
  real a;
  real b;
}
model {
  a ~ normal(0, 1);
  a ~ normal(x, 1);

  b ~ normal(1, 1);
}

Pedantic mode produces the following warning.

Warning at 'multi-twiddle.stan', line 9, column 2 to column 19:
  The parameter a is on the left-hand side of more than one twiddle
  statement.

33.3.7 Parameters with zero or multiple priors

A warning is generated when a parameter appears to have greater than or less than one prior distribution factor.

This analysis depends on a factor graph representation of a Stan program. A factor F that depends on a parameter P is called a prior factor for P if there is no path in the factor graph from F to any data variable except through P.

One limitation of this approach is that the compiler cannot distinguish between modeled data variables and other convenient uses of data variables such as data sizes or hyperparameters. This warning assumes that all data variables (except for int variables) are modeled data, which may cause extra warnings.

For example, consider the following program.

data {
  real x;
}
parameters {
  real a;
  real b;
  real c;
  real d;
}
model
{
  a ~ normal(0, 1); // this is a prior
  x ~ normal(a, 1); // this is not a prior, since data is involved

  b ~ normal(x, 1); // this is also not a prior, since data is involved

  // this is not a prior for c, since data is involved through b
  // but it is a prior for b, since the data is only involved through b
  c ~ normal(b, 1);

  //these are multiple priors:
  d ~ normal(0, 1);
  1 ~ normal(d, 1);
}

One prior is found for a and for b, while c only has a factor that touches a data variable and d has multiple priors.

Pedantic mode produces the following warning.

Warning:
  The parameter c has no priors.
Warning:
  The parameter d has 2 priors.

33.3.8 Variables used before assignment

A warning is generated when any variable is used before it has been assigned a value.

For example, consider the following program.

transformed data {
  real x;
  if (1 > 2) {
    x = 1;
  } else {
    print("oops");
  }
  print(x);
}

Since x is only assigned in one of the branches of the if statement, it might get to print(x) without having been assigned to.

Pedantic mode produces the following warning.

Warning at 'uninit-warn.stan', line 7, column 8 to column 9:
  The variable x may not have been assigned a value before its use.

33.3.9 Strict or nonsensical parameter bounds

Except when there are logical or physical constraints, it is very unusual for you to be sure that a parameter will fall inside a specified range. A warning is generated for all parameters declared with the bounds <lower=.., upper=..> except for <lower=0, upper=1> or <lower=-1, upper=1>.

In addition, a warning is generated when a parameter bound is found to have lower >= upper.

For example, consider the following program.

parameters {
  real<lower=0, upper=1> a;
  real<lower=-1, upper=1> b;
  real<lower=-2, upper=1012> c;
}
model {
  c ~ normal(b, a);
}

Pedantic mode produces the following warning.

Warning:
  Your Stan program has a parameter c with a lower and upper bound in its
  declaration. These hard constraints are not recommended, for two reasons:
  (a) Except when there are logical or physical constraints, it is very
  unusual for you to be sure that a parameter will fall inside a specified
  range, and (b) The infinite gradient induced by a hard constraint can cause
  difficulties for Stan's sampling algorithm. As a consequence, we recommend
  soft constraints rather than hard constraints; for example, instead of
  constraining an elasticity parameter to fall between 0, and 1, leave it
  unconstrained and give it a normal(0.5, 0.5) prior distribution.

33.3.10 Pedantic mode limitations

  • Constant values are sometimes uncomputable

    Pedantic mode attempts to evaluate expressions down to literal values so that they can be used to generate warnings. For example, in the code normal(x, 1 - 2), the expression 1 - 2 will be evaluated to -1, which is not a valid variance argument so a warning is generated. However, this strategy is limited; it is often impossible to fully evaluate expressions in finite time.

  • Container types

    Currently, indexed variables are not handled intelligently, so they are treated as monolithic variables. Each analysis treats indexed variables conservatively (erring toward generating fewer warnings).

  • Data variables

    The declaration information for data variables is currently not considered, so using data as incompatible arguments to distributions may not generate the appropriate warnings.

  • Control flow dependent on parameters in nested functions

    If a parameter is passed as an argument to a user-defined function within another user-defined function, and then some control flow depends on that argument, the appropriate warning will not be thrown.