std::map<STM::ParName, double> Metropolis::do_sample(int n, bool saveDeviance) // n is the number of samples to take // returns a map of acceptance rates keyed by parameter name { // shuffle the order of parameters std::vector<STM::ParName> parNames (parameters.active_names()); std::random_shuffle(parNames.begin(), parNames.end(), [this](int n){ return gsl_rng_uniform_int(rng.get(), n); }); std::map<STM::ParName, int> numAccepted; for(const auto & par : parNames) numAccepted[par] = 0; for(int i = 0; i < n; i++) { for(int j = 0; j < thinSize; j++) { // step through each parameter for(const auto & par : parNames) { STM::ParPair proposal = propose_parameter(par); numAccepted[par] += select_parameter(proposal); } } parameters.increment(); currentSamples.push_back(parameters.current_state()); if(saveDeviance) sampleDeviance.push_back(std::pair<double, int>(-2 * currentLL, 1)); // if desired, some debugging output if(outputLevel >= EngineOutputLevel::Verbose) { std::cerr << " iteration " << parameters.iteration() - 1 << " posterior probability: " << currentPosteriorProb << " likelihood: " << currentLL << "\n"; if(outputLevel >= EngineOutputLevel::ExtraVerbose) { std::ios_base::fmtflags oldflags = std::cerr.flags(); std::streamsize oldprecision = std::cerr.precision(); std::cerr << std::fixed << std::setprecision(3) << " "; STM::ParMap st = parameters.current_state(); int coln = 0; for(auto pa : st) { std::cerr << std::setw(6) << pa.first << std::setw(8) << pa.second; if(++coln >= 7) { std::cerr << "\n "; coln = 0; } } std::cerr << std::endl; std::cerr.flags (oldflags); std::cerr.precision (oldprecision); } } } std::map<STM::ParName, double> acceptanceRates; for(const auto & par : parNames) acceptanceRates[par] = double(numAccepted[par]) / (n*thinSize); return acceptanceRates; }
void Metropolis::regression_adapt(int numSteps, int stepSize) { std::vector<STM::ParName> parNames (parameters.names()); std::map<STM::ParName, std::map<std::string, double *> > regressionData; for(const auto & par : parNames) { regressionData[par]["log_variance"] = new double [numSteps]; regressionData[par]["variance"] = new double [numSteps]; regressionData[par]["acceptance"] = new double [numSteps]; } for(int i = 0; i < numSteps; i++) { // compute acceptance rates for the current variance term parameters.set_acceptance_rates(do_sample(stepSize)); for(const auto & par : parNames) { // save regression data for each parameter regressionData[par]["log_variance"][i] = std::log(parameters.sampler_variance(par)); regressionData[par]["variance"][i] = parameters.sampler_variance(par); regressionData[par]["acceptance"][i] = parameters.acceptance_rate(par); // choose new variances at random for each parameter; drawn from a gamma with mean 2.38 and sd 2 parameters.set_sampler_variance(par, gsl_ran_gamma(rng.get(), 1.4161, 1.680672)); } } // perform regression for each parameter and clean up for(const auto & par : parNames) { // first compute the correlation for variance and log_variance, use whichever is higher double corVar = gsl_stats_correlation(regressionData[par]["variance"], 1, regressionData[par]["acceptance"], 1, numSteps); double corLogVar = gsl_stats_correlation(regressionData[par]["log_variance"], 1, regressionData[par]["acceptance"], 1, numSteps); double beta0, beta1, cov00, cov01, cov11, sumsq, targetVariance; if(corVar >= corLogVar) { gsl_fit_linear(regressionData[par]["variance"], 1, regressionData[par]["acceptance"], 1, numSteps, &beta0, &beta1, &cov00, &cov01, &cov11, &sumsq); targetVariance = (parameters.optimal_acceptance_rate() - beta0)/beta1; } else { gsl_fit_linear(regressionData[par]["log_variance"], 1, regressionData[par]["acceptance"], 1, numSteps, &beta0, &beta1, &cov00, &cov01, &cov11, &sumsq); targetVariance = std::exp((parameters.optimal_acceptance_rate() - beta0)/beta1); } parameters.set_sampler_variance(par, targetVariance); delete [] regressionData[par]["log_variance"]; delete [] regressionData[par]["variance"]; delete [] regressionData[par]["acceptance"]; } }
QString ScriptAdapterGenerator::funCodeGenerator(const QString& filtername,const RichParameterSet& set) const { QString code; code += "function (" + parNames(set) + ")\n"; code += "{\n"; code += "\tvar tmpRichPar = new IRichParameterSet();\n"; code += "\tif (!_initParameterSet(\""+ filtername + "\",tmpRichPar)) return false;\n"; for(int ii = 0; ii < set.paramList.size();++ii) code += "\ttmpRichPar.set" + set.paramList[ii]->val->typeName() + "(\"" + set.paramList[ii]->name + "\",arguments[" + QString::number(ii) + "]);\n"; code += "\treturn _applyFilter(\"" + filtername + "\",tmpRichPar);\n"; code += "};\n"; return code; }
void Metropolis::auto_adapt() { if(outputLevel >= EngineOutputLevel::Normal) { std::cerr << timestamp() << " Starting automatic adaptation" << std::endl; } std::vector<STM::ParName> parNames (parameters.names()); // disable thinning for the adaptation phase int oldThin = thinSize; thinSize = 1; regression_adapt(10, 100); // use the first two loops to try a regression approach int nLoops = 2; while(nLoops < minAdaptationLoops or ((not parameters.adapted()) and nLoops < maxAdaptationLoops)) { nLoops++; parameters.set_acceptance_rates(do_sample(adaptationSampleSize)); for(const auto & par : parNames) { double ratio; if(parameters.acceptance_rate(par) == 0) ratio = 1e-2; else ratio = parameters.acceptance_rate(par) / parameters.optimal_acceptance_rate(); parameters.set_sampler_variance(par, ratio*parameters.sampler_variance(par)); } if(outputLevel >= EngineOutputLevel::Talkative) { std::cerr << "\n " << timestamp() << " iter " << parameters.iteration() << "\n"; parameters.print_adaptation(isatty(fileno(stderr)), 2); // std::cerr << " " << parameters.str_acceptance_rates(isatty(fileno(stderr))) << "\n"; // std::cerr << " sampler variance:\n"; // std::cerr << " " << parameters.str_sampling_variance(isatty(fileno(stderr))) << std::endl; } currentSamples.clear(); if(saveResumeData) serialize_all(); } parameters.reset(); // adaptation samples are not included in the burnin period if(outputLevel >= EngineOutputLevel::Normal) { std::cerr << timestamp() << " Adaptation completed successfully" << std::endl; } thinSize = oldThin; }
QString ScriptAdapterGenerator::funCodeGenerator( const QString& filterName,MLXMLPluginInfo& xmlInfo ) const { QString code; QString names = parNames(filterName,xmlInfo); code += "function (" + names + ")\n"; code += "{\n"; MLXMLPluginInfo::XMLMapList mplist = xmlInfo.filterParametersExtendedInfo(filterName); if (names.indexOf(optName()) != -1) { QString defValues; for(int ii = 0;ii < mplist.size();++ii) { MLXMLPluginInfo::XMLMap mp = mplist[ii]; if (mp[MLXMLElNames::paramIsImportant] == "false") defValues += mp[MLXMLElNames::paramName] + " : " + mp[MLXMLElNames::paramDefExpr] + ", "; } code += "\t" + optName() + " = __mergeOptions(" + optName() + ",{" + defValues + "});\n"; } code += "\tvar environ = new Env;\n"; QString ariet = xmlInfo.filterAttribute(filterName,MLXMLElNames::filterArity); bool isSingle = (ariet == MLXMLElNames::singleMeshArity); //if is singleMeshAriety i have to jump the first argument because is the meshID int arg = (int) isSingle; for(int ii = 0; ii < mplist.size();++ii) { MLXMLPluginInfo::XMLMap mp = mplist[ii]; bool isenum = false; QString num = QString::number(ii); QString values = mp[MLXMLElNames::paramType]; if (values.contains(MLXMLElNames::enumType)) { QRegExp rem(MLXMLElNames::enumType + " \\{"); values.remove(rem); rem.setPattern("\\}"); values.remove(rem); MLXMLPluginInfo::XMLMap valuesMap = MLXMLPluginInfo::mapFromString(values,QRegExp("\\|"),QRegExp("\\:")); code += "\tfunction enumfun_" + num + "()\n\t{\t\n"; for(MLXMLPluginInfo::XMLMap::iterator it = valuesMap.begin();it != valuesMap.end();++it) { code += "\t\tthis[\"" + it.key() + "\"] = " + it.value() + ";\n"; code += "\t\tthis[parseInt(" + it.value() + ")] = \"" + it.key() + "\";\n"; } code += "\t}\n"; code += "\tfunction get_" + num + "(ff,ii)\n\t{\t\n"; code += "\t\tif (typeof(ii) == \"number\") return ff[ff[ii]];\n"; code += "\t\telse if (typeof(ii) == \"string\") return ff[ii];\n"; code += "\t\t\telse return undefined;\n"; code += "\t}\n"; code += "\tvar enumtype_" + num + " = new enumfun_" + num + "();\n"; isenum = true; } if (mp[MLXMLElNames::paramIsImportant] == "true") { QString argument = "arguments[" + QString::number(arg) + "]"; if (isenum) { code += "\tvar argenum_" + num + " = get_" + num + "(enumtype_" + num + "," + argument + ");\n"; code += "\tenviron.insertExpressionBinding(\"" + mp[MLXMLElNames::paramName] + "\",argenum_" + num + ");\n"; } else //code += "\tprint(" + argument + ");\n"; code += "\tenviron.insertExpressionBinding(\"" + mp[MLXMLElNames::paramName] + "\"," + argument + ");\n"; ++arg; } else { if (isenum) { //code += "\tvar argenum_" + num + " = enumtype_" + num + "[" + argument + "];\n"; code += "\tvar " + mp[MLXMLElNames::paramName] + " = get_" + num + "(enumtype_" + num + "," + optName() + "." + /*mp[MLXMLElNames::paramType] + "_" +*/ mp[MLXMLElNames::paramName] + ");\n"; code += "\tenviron.insertExpressionBinding(\"" + mp[MLXMLElNames::paramName] + "\", " + mp[MLXMLElNames::paramName] + ");\n"; } else { code += "\tvar " + mp[MLXMLElNames::paramName] + " = " + optName() + "." + /*mp[MLXMLElNames::paramType] + "_" +*/ mp[MLXMLElNames::paramName] + ";\n"; code += "\tenviron.insertExpressionBinding(\"" + mp[MLXMLElNames::paramName] + "\", " + mp[MLXMLElNames::paramName] + ");\n"; } } } code += "\tvar environWrap = new EnvWrap(environ);\n"; if (isSingle) { code += "\tvar oldInd=" + meshDocVarName() + ".setCurrent(" + meshID() + ");\n"; code += "\tif (oldInd == -1) return false;\n"; } code += "\tvar result = _applyFilter(\"" + filterName + "\",environWrap);\n"; if (isSingle) code += "\t" +meshDocVarName() + ".setCurrent(oldInd);\n"; code += "\treturn result;\n"; code += "};\n"; return code; }