httpstan icon indicating copy to clipboard operation
httpstan copied to clipboard

Cannot provide an empty int-valued list

Open riddell-stan opened this issue 5 years ago • 5 comments

Models which use data which contains an empty int-valued list cannot be used.

This does not have a trivial solution since we use JSON for serializing data and JSON cannot distinguish between an empty list of floats and an empty list of ints.

A completely satisfactory solution will probably involve asking Stan or stanc3 to tell us the type of data variables.

riddell-stan avatar Apr 24 '20 13:04 riddell-stan

Stanc3 should have this option, because pystan 2 has the same problem.

ahartikainen avatar Apr 24 '20 15:04 ahartikainen

I think cmdstan might have solved this. If this is true, we could copy their solution.

riddell-stan avatar Aug 08 '20 13:08 riddell-stan

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Nov 09 '20 23:11 stale[bot]

Now with Stan 2.27 stanc3 has --info which returns a dictionary with needed information.

stanc --info path/to/stan_file.stan

(Here is an example with bernoulli example in CmdStan examples.)

{ "inputs": { "N": { "type": "int", "dimensions": 0},
              "y": { "type": "int", "dimensions": 1} },
  "parameters": { "theta": { "type": "real", "dimensions": 0} },
  "transformed parameters": {  },
  "generated quantities": {  },
  "functions": [  ],
  "distributions": [ "bernoulli_lupmf",
                     "beta_lupdf" ] }

And in httpstan solution (copy from httpstan/compile) with example from 8-schools (pystan docs)

import httpstan
import stan
import importlib.resources
import tempfile
from pathlib import Path
from typing import List, Union, Tuple
import os
import subprocess
import json

program_code = """
data {
  int<lower=0> J;         // number of schools
  real y[J];              // estimated treatment effects
  real<lower=0> sigma[J]; // standard error of effect estimates
}
parameters {
  real mu;                // population treatment effect
  real<lower=0> tau;      // standard deviation in treatment effects
  vector[J] eta;          // unscaled deviation from mu by school
}
transformed parameters {
  vector[J] theta = mu + tau * eta;        // school treatment effects
}
model {
  target += normal_lpdf(eta | 0, 1);       // prior log-density
  target += normal_lpdf(y | theta, sigma); // log-likelihood
}
"""

schools_data = {"J": 8,
                "y": [28,  8, -3,  7, -1,  1, 18, 12],
                "sigma": [15, 10, 16, 11,  9, 11, 10, 18]}

posterior = stan.build(program_code, data=schools_data)

def model_info(program_code: str, stan_model_name: str) -> Tuple[str, str]:
    with importlib.resources.path(httpstan.__package__, "stanc") as stanc_binary:
        with tempfile.TemporaryDirectory(prefix="httpstan_") as tmpdir:
            filepath = Path(tmpdir) / f"{stan_model_name}.stan"
            with filepath.open("w") as fh:
                fh.write(program_code)
            run_args: List[Union[os.PathLike, str]] = [
                stanc_binary,
                "--info",
                str(filepath),
            ]
            completed_process = subprocess.run(run_args, capture_output=True, timeout=1)
    stderr = completed_process.stderr.decode().strip()
    if completed_process.returncode != 0:
        raise ValueError(stderr)
    return completed_process.stdout.decode().strip(), stderr

model_name = httpstan.models.calculate_model_name(program_code)
stan_model_name = f"model_{model_name.split('/')[1]}"
stdout, stderr = model_info(program_code, stan_model_name)
model_input_info = json.loads(stdout)
model_input_info
{'inputs': {'J': {'type': 'int', 'dimensions': 0},
  'y': {'type': 'real', 'dimensions': 1},
  'sigma': {'type': 'real', 'dimensions': 1}},
 'parameters': {'mu': {'type': 'real', 'dimensions': 0},
  'tau': {'type': 'real', 'dimensions': 0},
  'eta': {'type': 'real', 'dimensions': 1}},
 'transformed parameters': {'theta': {'type': 'real', 'dimensions': 1}},
 'generated quantities': {},
 'functions': [],
 'distributions': ['normal_lpdf']}

edit. Fix code

ahartikainen avatar Jun 14 '21 15:06 ahartikainen

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jun 18 '23 08:06 stale[bot]