def test_stanc_exception(self): model_code = 'parameters {real z;} model {z ~ no_such_distribution();}' assertRaisesRegex = self.assertRaisesRegexp if PY2 else self.assertRaisesRegex with assertRaisesRegex(ValueError, 'unknown distribution'): stanc(model_code=model_code) with assertRaisesRegex(ValueError, 'unknown distribution'): StanModel(model_code=model_code)
def test_stanc_exception(self): model_code = 'parameters {real z;} model {z ~ no_such_distribution();}' assertRaisesRegex = self.assertRaisesRegexp if PY2 else self.assertRaisesRegex # distribution not found error with assertRaisesRegex(ValueError, r'Probability function must end in _lpdf or _lpmf\. Found'): stanc(model_code=model_code) with assertRaisesRegex(ValueError, r'Probability function must end in _lpdf or _lpmf\. Found'): StanModel(model_code=model_code)
def test_stanc_exception(self): model_code = 'parameters {real z;} model {z ~ no_such_distribution();}' assertRaisesRegex = self.assertRaisesRegexp if PY2 else self.assertRaisesRegex # distribution not found error with assertRaisesRegex( ValueError, r'Probability function must end in _lpdf or _lpmf\. Found'): stanc(model_code=model_code) with assertRaisesRegex( ValueError, r'Probability function must end in _lpdf or _lpmf\. Found'): StanModel(model_code=model_code)
def test_stanc_exception_semicolon(self): model_code = """ parameters { real z real y } model { z ~ normal(0, 1); y ~ normal(0, 1);} """ assertRaisesRegex = self.assertRaisesRegexp if PY2 else self.assertRaisesRegex with assertRaisesRegex(ValueError, 'Failed to parse'): stanc(model_code=model_code) with assertRaisesRegex(ValueError, 'Failed to parse'): StanModel(model_code=model_code)
def test_stanc_exception_semicolon(self): model_code = """ parameters { real z real y } model { z ~ normal(0, 1); y ~ normal(0, 1);} """ assertRaisesRegex = self.assertRaisesRegexp if PY2 else self.assertRaisesRegex with assertRaisesRegex(ValueError, 'Parser expecting: ";"'): stanc(model_code=model_code) with assertRaisesRegex(ValueError, 'Parser expecting: ";"'): StanModel(model_code=model_code)
def test_stanc(): model_code = 'parameters {real y;} model {y ~ normal(0,1);}' result = stanc(model_code=model_code) print(result.keys()) assert result.keys() == {"status", "model_cppname", "cppcode", "model_name", "model_code"} assert result['cppcode'].startswith("// Code generated by Stan ")
def build_model(stan_folder, model_name, model_code, verbose_compile): code_hash = hashlib.sha1(model_code.encode('utf-8')).hexdigest() model_filename = os.path.join(stan_folder, model_name + "_" + code_hash) if os.path.exists(model_filename): print('STAN: cached model found; loading') f = open(model_filename, 'rb') sm = pk.load(f) f.close() else: if not os.path.exists(stan_folder): os.mkdir(stan_folder) print('STAN: no cached model found; building') try: stanc_ret = pystan.stanc(model_code=model_code) stanc_ret['cppcode'] = load_modified_cpp_code( stan_folder, model_name, model_code) sm = pystan.StanModel(stanc_ret=stanc_ret, verbose=verbose_compile) except: print( 'Compiling failed. Did you make sure to modify the weighted_[model_name]_[code_hash].cpp file to handle weighted data?' ) raise f = open(model_filename, 'wb') pk.dump(sm, f) f.close() return sm
def test_stanc(self): model_code = 'parameters {real y;} model {y ~ normal(0,1);}' result = stanc(model_code=model_code) assert sorted(result.keys()) == sorted( {"status", "model_cppname", "cppcode", "model_name", "model_code"}) assert result['cppcode'].startswith("// Code generated by Stan ") self.assertEqual(result['status'], 0)
def test_stanc_2_includes(self): model_code = 'parameters {\n#include external1.stan\n#include external2.stan\n} model {\ny ~ normal(0,1);\nz ~ normal(0,1);}' testdata_path = os.path.join(os.path.dirname(__file__), 'data', "") result = stanc(model_code=model_code, include_paths=[testdata_path]) desired = sorted({"status", "model_cppname", "cppcode", "model_name", "model_code", "include_paths"}) self.assertEqual(sorted(result.keys()), desired) self.assertEqual(result['status'], 0)
def test_stanc(self): model_code = 'parameters {real y;} model {y ~ normal(0,1);}' result = stanc(model_code=model_code) desired = sorted({"status", "model_cppname", "cppcode", "model_name", "model_code"}) self.assertEqual(sorted(result.keys()), desired) self.assertTrue(result['cppcode'].startswith("// Code generated by Stan ")) self.assertEqual(result['status'], 0)
def test_stanc_2_includes(self): model_code = 'parameters {\n#include external1.stan\n#include external2.stan\n} model {\ny ~ normal(0,1);\nz ~ normal(0,1);}' testdata_path = os.path.join(os.path.dirname(__file__), 'data', "") result = stanc(model_code=model_code, include_paths=[testdata_path]) desired = sorted({ "status", "model_cppname", "cppcode", "model_name", "model_code", "include_paths" }) self.assertEqual(sorted(result.keys()), desired) self.assertEqual(result['status'], 0)
def test_stanc(self): model_code = 'parameters {real y;} model {y ~ normal(0,1);}' result = stanc(model_code=model_code) desired = sorted({ "status", "model_cppname", "cppcode", "model_name", "model_code", "include_paths" }) self.assertEqual(sorted(result.keys()), desired) self.assertTrue( result['cppcode'].startswith("// Code generated by Stan ")) self.assertEqual(result['status'], 0)
def get_model(model_name): """Get a StanModel object, checking first in local cache and recompiling if necessary.""" cachefile = os.path.join(config.modelcache, '{}.pkl'.format(model_name)) # Check if package exists, get model code. with _include_path() as incpth, _model_file(model_name) as modelfile: model_stanc = pystan.stanc(file=modelfile, include_paths=[incpth], model_name=model_name) # Check if cached file exists and load it model = None if os.path.isfile(cachefile): try: with open(cachefile, 'rb') as f: model = pickle.load(f) except pickle.UnpicklingError: os.remove(cachefile) # Bad file, remove # If cache file did not exist or is from an old model, recompile and cache if (model is None) or (model.model_cppcode != model_stanc['cppcode']): model = pystan.StanModel(stanc_ret=model_stanc) os.makedirs(config.modelcache, exist_ok=True) with open(cachefile, 'wb') as f: pickle.dump(model, f, protocol=pickle.HIGHEST_PROTOCOL) return model
def test_stan_model_from_file(self): bernoulli_model_code = """ data { int<lower=0> N; int<lower=0,upper=1> y[N]; } parameters { real<lower=0,upper=1> theta; } model { for (n in 1:N) y[n] ~ bernoulli(theta); } """ bernoulli_data = {'N': 10, 'y': [0, 1, 0, 0, 0, 0, 0, 0, 0, 1]} temp_dir = tempfile.mkdtemp() temp_fn = os.path.join(temp_dir, 'modelcode.stan') with io.open(temp_fn, 'wt') as outfile: outfile.write(bernoulli_model_code) code = stanc(file=temp_fn)['model_code'] fit = stan(model_code=code, data=bernoulli_data) extr = fit.extract(permuted=True) assert -7.9 < np.mean(extr['lp__']) < -7.0 assert 0.1 < np.mean(extr['theta']) < 0.4 assert 0.01 < np.var(extr['theta']) < 0.02 # permuted=False extr = fit.extract(permuted=False) assert extr.shape == (1000, 4, 2) assert 0.1 < np.mean(extr[:, 0, 0]) < 0.4 # permuted=True extr = fit.extract('lp__', permuted=True) assert -7.9 < np.mean(extr['lp__']) < -7.0 extr = fit.extract('theta', permuted=True) assert 0.1 < np.mean(extr['theta']) < 0.4 assert 0.01 < np.var(extr['theta']) < 0.02 extr = fit.extract('theta', permuted=False) assert extr['theta'].shape == (1000, 4) assert 0.1 < np.mean(extr['theta'][:, 0]) < 0.4 fit = stan(file=temp_fn, data=bernoulli_data) extr = fit.extract(permuted=True) assert -7.9 < np.mean(extr['lp__']) < -7.0 assert 0.1 < np.mean(extr['theta']) < 0.4 assert 0.01 < np.var(extr['theta']) < 0.02 # permuted=False extr = fit.extract(permuted=False) assert extr.shape == (1000, 4, 2) assert 0.1 < np.mean(extr[:, 0, 0]) < 0.4 # permuted=True extr = fit.extract('lp__', permuted=True) assert -7.9 < np.mean(extr['lp__']) < -7.0 extr = fit.extract('theta', permuted=True) assert 0.1 < np.mean(extr['theta']) < 0.4 assert 0.01 < np.var(extr['theta']) < 0.02 extr = fit.extract('theta', permuted=False) assert extr['theta'].shape == (1000, 4) assert 0.1 < np.mean(extr['theta'][:, 0]) < 0.4 os.remove(temp_fn)
def test_utf8(self): model_code = 'parameters {real y;} model {y ~ normal(0,1);}' result = stanc(model_code=model_code) self.assertEqual(sorted(result.keys()), self.desired) self.assertTrue(result['cppcode'].startswith("// Code generated by Stan ")) self.assertEqual(result['status'], 0)
def test_utf8_inprogramcode(self): model_code = u'parameters {real ö;\n} model {ö ~ normal(0,1);}' assertRaisesRegex = self.assertRaisesRegexp if PY2 else self.assertRaisesRegex with assertRaisesRegex(ValueError, 'Failed to parse Stan model .*'): stanc(model_code=model_code)
def test_stanc_exception(): model_code = 'parameters {real z;} model {y ~ no_such_distribution();}' result = stanc(model_code=model_code) assert result['status'] == -1
def test_stan_model_from_file(self): bernoulli_model_code = """ data { int<lower=0> N; int<lower=0,upper=1> y[N]; } parameters { real<lower=0,upper=1> theta; } model { for (n in 1:N) y[n] ~ bernoulli(theta); } """ bernoulli_data = {'N': 10, 'y': [0, 1, 0, 0, 0, 0, 0, 0, 0, 1]} temp_dir = tempfile.mkdtemp() temp_fn = os.path.join(temp_dir, 'modelcode.stan') with io.open(temp_fn, 'wt') as outfile: outfile.write(bernoulli_model_code) code = stanc(file=temp_fn)['model_code'] fit = stan(model_code=code, data=bernoulli_data) extr = fit.extract(permuted=True) assert -7.9 < np.mean(extr['lp__']) < -7.0 assert 0.1 < np.mean(extr['theta']) < 0.4 assert 0.01 < np.var(extr['theta']) < 0.02 # permuted=False extr = fit.extract(permuted=False) assert extr.shape == (1000, 4, 2) assert 0.1 < np.mean(extr[:, 0, 0]) < 0.4 # permuted=True extr = fit.extract('lp__', permuted=True) assert -7.9 < np.mean(extr['lp__']) < -7.0 extr = fit.extract('theta', permuted=True) assert 0.1 < np.mean(extr['theta']) < 0.4 assert 0.01 < np.var(extr['theta']) < 0.02 extr = fit.extract('theta', permuted=False) assert extr.shape == (1000, 4, 2) assert 0.1 < np.mean(extr[:, 0, 0]) < 0.4 fit = stan(file=temp_fn, data=bernoulli_data) extr = fit.extract(permuted=True) assert -7.9 < np.mean(extr['lp__']) < -7.0 assert 0.1 < np.mean(extr['theta']) < 0.4 assert 0.01 < np.var(extr['theta']) < 0.02 # permuted=False extr = fit.extract(permuted=False) assert extr.shape == (1000, 4, 2) assert 0.1 < np.mean(extr[:, 0, 0]) < 0.4 # permuted=True extr = fit.extract('lp__', permuted=True) assert -7.9 < np.mean(extr['lp__']) < -7.0 extr = fit.extract('theta', permuted=True) assert 0.1 < np.mean(extr['theta']) < 0.4 assert 0.01 < np.var(extr['theta']) < 0.02 extr = fit.extract('theta', permuted=False) assert extr.shape == (1000, 4, 2) assert 0.1 < np.mean(extr[:, 0, 0]) < 0.4 os.remove(temp_fn)
def stan(self, line, cell): ''' Allow jupyter notebook cells to output stan code to file and compile it using stanc compiler in your path or pystan.stanc if no compiler is found in path. Output of compile is stored in "_stan_model object" or in an <object name> specified in -v <object_name> (e.g %%stan -f test.stan -v test) %%stan - Saves the cell code to a string. The code string can be accessed via _stan_model.model_code or <object_name>.model_code (if you specify -v <object_name> option) %%stan -f <stan_file_name> - Saves the cell code to a file specified in <stan_file_name>. The file name can also be accessed in _stan_model.model_file or in <object_name>.model_file (if you specify -v <object_name> option) %%stan -v <object_name> [default: _stan_model] stan magic currently outputs a StanMagicOutput object in default _stan_model object. -v allows you to specify an alternate compile output object name, so that you can use specified object name instead of "_stan_model". This is useful if you have multiple %%stan model cells. Cuurently the output object exposes 3 attributes (model_name, model_code, model_file) [_stan_model | <object_name>].model_file -> Name of stan_file [_stan_model | <object_name>].model_name -> Name of stan model [None] [_stan_model | <object_name>].model_code -> Model code %%stan -f <stan_file_name> --save_only - Saves the cell code to a file specified in <stan_file_name>. Skips compile step %%stan -f <stan_file_name> -o <cpp_file_name> - Saves the cell code to a file specified in <stan_file_name> and outputs the compiled cpp file to the file name specified by <cpp_file_name> %% stan -f <stan_file_name> --allow_undefined - passes the --allow_undefined argument to stanc compiler %%stan --stanc <stanc_compiler> [default: stanc in $PATH or pystan.stanc] - Saves the cell code to a file specified in <stan_file_name> and compiles using the stan compiler specified in <stanc_compiler>. Optionally, if you specify --stanc pystan, it uses pystan.stanc compiler. If you want to use specific stanc compiler use this option (e.g %%stan -f binom.stan --stanc "~/cmdstan-2.16.0/bin/stanc") ''' _stan_vars = {} __stan_code_str__ = None __stan_file__ = None __model_name__ = None ip = get_ipython() args = shlex.split(line.strip()) options = { k: True if v.startswith('-') else v for k, v in zip(args, args[1:] + ["--"]) if k.startswith('-') } source_filename = options.get('-f', None) output_filename = options.get('-o', None) variable_name = options.get('-v', '_stan_model') allow_undefined = options.get('--allow_undefined', False) save_only = options.get('--save_only', False) if save_only is True: if source_filename is None: print("Need to specify stan file name (-f) for --save_only") return else: with open(source_filename, 'w') as f: f.write(cell) _stan_vars['stan_file'] = source_filename print( "File {0} saved..Skipping Compile".format(source_filename)) return compiler_location = options.get('--stanc', check_program('stanc')) if not (isinstance(compiler_location, str)): print("Pls specify a location for stanccompiler or \ specify '--stanc pystan' to use pystan.stanc compiler") return temp_dir = tempfile.gettempdir() if compiler_location is None or compiler_location == 'pystan': print("Using pystan.stanc compiler..") else: print("Using stanc compiler: ", compiler_location) # We define the source and executable filenames. if source_filename is None: temp_name = str(uuid.uuid4()) source_filename = os.path.join(temp_dir,'anon_' + \ temp_name + '.stan') output_filename = os.path.join(temp_dir,'anon_' + temp_name + \ '_model.cpp') model_name = 'anon_' + temp_name + '_model' __stan_code_str__ = cell __stan_file__ = None __model_name__ = None else: __stan_file = source_filename model_name = source_filename.split('.') if len(model_name) > 1: model_name = '_'.join(model_name[:-1]) else: model_name = ''.join(model_name) model_name = model_name + '_model' __stan_code_str__ = cell __stan_file__ = source_filename __model_name__ = model_name with open(source_filename, 'w') as f: f.write(cell) if compiler_location is None or compiler_location == 'pystan': try: import pystan as _pystan try: out = _pystan.stanc(source_filename, verbose=True) except Exception as e: print(e) return except ImportError: print( "Ensure stan command line (stanc) is installed and in your \ PATH or pystan is installed or specify compiler path using --stanc \ (e.g. %% stan -f model.stan --stanc ./bin/stanc") return else: compile_str = compiler_location if output_filename is not None: compile_str = compile_str + ' --o=' + output_filename else: compile_str = compile_str + ' --o=' + \ os.path.join(temp_dir,str(uuid.uuid4()) +'.cpp') if allow_undefined is True: compile_str = compile_str + ' --allow_undefined ' compile_str = compile_str + ' ' + source_filename print(compile_str) compile_output = ip.getoutput(compile_str) print('\n'.join(compile_output)) _stan_vars[variable_name] = StanMagicOutput(__model_name__, __stan_code_str__, __stan_file__) ip.user_global_ns[variable_name] = _stan_vars[variable_name] print_compile_success(variable_name, __stan_file__, __model_name__, __stan_code_str__)
print(" ") print("Init:") print(fit.get_inits()[0]) print(fit.get_inits()[1]) print(" ") print("Adaptation:") print(fit.get_adaptation_info()[0]) print(fit.get_adaptation_info()[1]) print(" ") print("Chain 1, Draw 1-3") print(list(res[:3, 0, :])) print(" ") print("Chain 2, Draw 1-3") print(list(res[:3, 1, :])) print("\n AS NUMPY") print("Chain 1, Draw 1-3") print(res[:3, 0, :]) print(" ") print("Chain 2, Draw 1-3") print(res[:3, 1, :]) print(" ") print(" ### C++ code ###") print(pystan.stanc("Stan-models/8schools.stan")["cppcode"])
pooled_parameters = """ parameters { vector[2] beta; real<lower=0> sigma; } """ pooled_model = """ model { y ~ normal(beta[1] + beta[2] * x, sigma); } """ pooled_data_dict = {'N': len(log_cbo), 'x': final.controller, 'y': log_cbo} compiled_model = pystan.stanc(model_code=pooled_data + pooled_parameters + pooled_model) model = pystan.StanModel(stanc_ret=compiled_model) pooled_fit = model.sampling(data=pooled_data_dict, iter=1000, chains=2) pooled_sample = pooled_fit.extract(permuted=True) b0, m0 = pooled_sample['beta'].T.mean(1) # plt.scatter(final.controller, log_cbo) import seaborn as sns ax = sns.violinplot(final.controller, log_cbo) xvals = np.linspace(-0.2, 1.2) # here "0" means "not controller" which is a bit different from the original paper ax.plot(xvals, m0*xvals+b0, 'r--') # unpooled *change 10 to 120 in production* unpooled_model = """data { int<lower=0> N;