Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adaptation Handler #80

Merged
merged 8 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ Kamil Skwarczynski <skwarczynskikamil@gmail.com> Kamil Skwarczynski <kamilskw@cd
# Henry Wallace
Henry Wallace <henryisrael08@gmail.com> henry-israel <henryisrael08@gmail.com>
Henry Wallace <henryisrael08@gmail.com> Henry Wallace <67589487+henry-wallace-phys@users.noreply.github.com>
Henry Wallace <henryisrael08@gmail.com> Henry Wallace <hwallace@linappserv6.pp.rhul.ac.uk>
Henry Wallace <henryisrael08@gmail.com> Henry Wallace <henry.wallace@rhul.ac.uk>
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,6 @@ if(NOT TARGET uninstall)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()

# KS: Configure the Doxygen input file, this is to ensure whenever we update MaCh3 version Doxyfile will have same version.
configure_file(${CMAKE_SOURCE_DIR}/cmake/Templates/Doxyfile.in ${CMAKE_SOURCE_DIR}/Doc/Doxyfile @ONLY)
13 changes: 13 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Security Policy

## Supported Versions

Security updates are applied only to the latest release.

## Reporting a Vulnerability

If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.

Please disclose it at [security advisory](https://github.com/mach3-software/mach3/security/advisories/new).

This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base.
2,292 changes: 2,292 additions & 0 deletions cmake/Templates/Doxyfile.in

Large diffs are not rendered by default.

231 changes: 231 additions & 0 deletions covariance/AdaptiveMCMCHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
#include "covariance/AdaptiveMCMCHandler.h"

namespace adaptive_mcmc{

// ********************************************
AdaptiveMCMCHandler::AdaptiveMCMCHandler() {
// ********************************************
start_adaptive_throw = 0;
start_adaptive_update = 0;
end_adaptive_update = 1;
adaptive_update_step = 1000;

par_means = {};
adaptive_covariance = nullptr;
}

// ********************************************
AdaptiveMCMCHandler::~AdaptiveMCMCHandler() {
// ********************************************
if(adaptive_covariance != nullptr) {
delete adaptive_covariance;
}
}


// ********************************************
void AdaptiveMCMCHandler::InitFromConfig(const YAML::Node& adapt_manager, const std::string& matrix_name_str, const int Npars) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given Npars won't change does it not make sense to make this a class attribute rather than calling it in every method?

// ********************************************
// setAdaptionDefaults();
if(GetFromManager<std::string>(adapt_manager["AdaptionOptions"]["Covariance"][matrix_name_str], "")==""){
MACH3LOG_WARN("Adaptive Settings not found for {}, this is fine if you don't want adaptive MCMC", matrix_name_str);
return;
}

// We"re going to grab this info from the YAML manager
if(GetFromManager<bool>(adapt_manager["AdaptionOptions"]["Covariance"][matrix_name_str]["DoAdaption"], false)) {
MACH3LOG_WARN("Not using adaption for {}", matrix_name_str);
return;
}

start_adaptive_throw = GetFromManager<int>(adapt_manager["AdaptionOptions"]["Settings"]["AdaptionStartThrow"], 10);
start_adaptive_update = GetFromManager<int>(adapt_manager["AdaptionOptions"]["Settings"]["AdaptionStartUpdate"], 0);
end_adaptive_update = GetFromManager<int>(adapt_manager["AdaptionOptions"]["Settings"]["AdaptionEndUpdate"], 10000);
adaptive_update_step = GetFromManager<int>(adapt_manager["AdaptionOptions"]["Settings"]["AdaptionUpdateStep"], 100);


// We also want to check for "blocks" by default all parameters "know" about each other
// but we can split the matrix into independent block matrices

// We"ll set a dummy variable here
auto matrix_blocks = GetFromManager<std::vector<std::vector<int>>>(adapt_manager["AdaptionOptions"]["Settings"][matrix_name_str]["AdaptionUpdateStep"], {{}});

SetAdaptiveBlocks(matrix_blocks, Npars);
}

// ********************************************
void AdaptiveMCMCHandler::CreateNewAdaptiveCovariance(const int Npars) {
// ********************************************
adaptive_covariance = new TMatrixDSym(Npars);
adaptive_covariance->Zero();
par_means = std::vector<double>(Npars, 0);
}


// ********************************************
void AdaptiveMCMCHandler::SetAdaptiveBlocks(std::vector<std::vector<int>> block_indices, const int Npars) {
// ********************************************
/*
* In order to adapt efficient we want to setup our throw matrix to be a serious of block-diagonal (ish) matrices
*
* To do this we set sub-block in the config by parameter index. For example having
* [[0,4],[4, 6]] in your config will set up two blocks one with all indices 0<=i<4 and the other with 4<=i<6
*/
// Set up block regions
adapt_block_matrix_indices = std::vector<int>(Npars, 0);

// Should also make a matrix of block sizes
adapt_block_sizes = std::vector<int>((int)block_indices.size()+1, 0);
adapt_block_sizes[0] = Npars;

if(block_indices.size()==0 || block_indices[0].size()==0) return;

// Now we loop over our blocks
for(int iblock=0; iblock<(int)block_indices.size(); iblock++){
// Loop over blocks in the block
for(int isubblock=0; isubblock<(int)block_indices[iblock].size()-1; isubblock+=2){
int block_lb = block_indices[iblock][isubblock];
int block_ub = block_indices[iblock][isubblock+1];

//std::cout<<block_lb<<" "<<block_ub<<std::endl;
if(block_lb > Npars || block_ub > Npars){
MACH3LOG_ERROR("Cannot set matrix block with edges {}, {} for matrix of size {}",
block_lb, block_ub, Npars);
throw MaCh3Exception(__FILE__, __LINE__);;
}
for(int ipar = block_lb; ipar < block_ub; ipar++){
adapt_block_matrix_indices[ipar] = iblock+1;
adapt_block_sizes[iblock+1] += 1;
adapt_block_sizes[0] -= 1;
}
}
}
}


// ********************************************
//HW: Truly adaptive MCMC!
void AdaptiveMCMCHandler::SaveAdaptiveToFile(const TString& outFileName, const TString& systematicName){
// ********************************************
TFile* outFile = new TFile(outFileName, "UPDATE");
if(outFile->IsZombie()){
MACH3LOG_ERROR("Couldn't find {}", outFileName);
throw;
}
TVectorD* outMeanVec = new TVectorD((int)par_means.size());
for(int i = 0; i < (int)par_means.size(); i++){
(*outMeanVec)(i) = par_means[i];
}
outFile->cd();
adaptive_covariance->Write(systematicName+"_postfit_matrix");
outMeanVec->Write(systematicName+"_mean_vec");
outFile->Close();
delete outMeanVec;
delete outFile;
}

// ********************************************
// HW : I would like this to be less painful to use!
// First things first we need setters
void AdaptiveMCMCHandler::SetThrowMatrixFromFile(const std::string& matrix_file_name,
const std::string& matrix_name,
const std::string& means_name,
bool& use_adaptive,
const int Npars) {
// ********************************************
// Lets you set the throw matrix externally
// Open file
std::unique_ptr<TFile>matrix_file(new TFile(matrix_file_name.c_str()));
use_adaptive = true;

if(matrix_file->IsZombie()){
MACH3LOG_ERROR("Couldn't find {}", matrix_file_name);
throw;
}

// Next we grab our matrix
adaptive_covariance = static_cast<TMatrixDSym*>(matrix_file->Get(matrix_name.c_str()));
if(!adaptive_covariance){
MACH3LOG_ERROR("Couldn't find {} in {}", matrix_name, matrix_file_name);
throw;
}

// Finally we grab the means vector
TVectorD* means_vector = static_cast<TVectorD*>(matrix_file->Get(means_name.c_str()));

// This is fine to not exist!
if(means_vector){
// Yay our vector exists! Let's loop and fill it
// Should check this is done
if(means_vector->GetNrows()){
MACH3LOG_ERROR("External means vec size ({}) != matrix size ({})", means_vector->GetNrows(), Npars);
throw MaCh3Exception(__FILE__, __LINE__);
}

par_means = std::vector<double>(Npars);
for(int i = 0; i < Npars; i++){
par_means[i] = (*means_vector)(i);
}
MACH3LOG_INFO("Found Means in External File, Will be able to adapt");
}
// Totally fine if it doesn't exist, we just can't do adaption
else{
// We don't need a means vector, set the adaption=false
MACH3LOG_WARN("Cannot find means vector in {}, therefore I will not be able to adapt!", matrix_file_name);
use_adaptive = false;
}

matrix_file->Close();
MACH3LOG_INFO("Set up matrix from external file");
}


// ********************************************
void AdaptiveMCMCHandler::UpdateAdaptiveCovariance(const std::vector<double>& _fCurrVal, const int steps_post_burn, const int Npars) {
// ********************************************
std::vector<double> par_means_prev = par_means;

#ifdef MULTITHREAD
#pragma omp parallel for
#endif
for(int iRow = 0; iRow < Npars; iRow++) {
par_means[iRow] = (_fCurrVal[iRow]+par_means[iRow]*steps_post_burn)/(steps_post_burn+1);
}

//Now we update the covariances using cov(x,y)=E(xy)-E(x)E(y)
#ifdef MULTITHREAD
#pragma omp parallel for
#endif
for(int irow = 0; irow < Npars; irow++){
int block = adapt_block_matrix_indices[irow];
// int scale_factor = 5.76/double(adapt_block_sizes[block]);
for(int icol = 0; icol <= irow; icol++){
double cov_val=0;
// Not in the same blocks
if(adapt_block_matrix_indices[icol] == block){
// Calculate Covariance for block
// https://projecteuclid.org/journals/bernoulli/volume-7/issue-2/An-adaptive-Metropolis-algorithm/bj/1080222083.full
cov_val = (*adaptive_covariance)(irow, icol)*Npars/5.6644;
cov_val += par_means_prev[irow]*par_means_prev[icol]; //First we remove the current means
cov_val = (cov_val*steps_post_burn+_fCurrVal[irow]*_fCurrVal[icol])/(steps_post_burn+1); //Now get mean(iRow*iCol)
cov_val -= par_means[icol]*par_means[irow];
cov_val*=5.6644/Npars;
}
(*adaptive_covariance)(icol, irow) = cov_val;
(*adaptive_covariance)(irow, icol) = cov_val;
}
}
}

// ********************************************
void AdaptiveMCMCHandler::Print() {
// ********************************************
MACH3LOG_INFO("Adaptive MCMC Info:");
MACH3LOG_INFO("Throwing from New Matrix from Step : {}", start_adaptive_throw);
MACH3LOG_INFO("Adaption Matrix Start Update : {}", start_adaptive_update);
MACH3LOG_INFO("Adaption Matrix Ending Updates : {}", end_adaptive_update);
MACH3LOG_INFO("Steps Between Updates : {}", adaptive_update_step);
}


} //end adaptive_mcmc
84 changes: 84 additions & 0 deletions covariance/AdaptiveMCMCHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#pragma once

// MaCh3 Includes
#include "manager/MaCh3Logger.h"
#include "manager/manager.h"
#include "covariance/CovarianceUtils.h"

namespace adaptive_mcmc{

/// @brief Contains information about adaptive covariance matrix
/// @see An adaptive Metropolis algorithm, H.Haario et al., 2001 for more info!
///@details struct encapsulating all adaptive MCMC information
class AdaptiveMCMCHandler{
public:

/// @brief Constructor
AdaptiveMCMCHandler();

/// @brief Destructor
~AdaptiveMCMCHandler();

/// @brief Print all class members
void Print();

/// @brief Read initial values from config file
/// @param adapt_manager Config file from which we update matrix
void InitFromConfig(const YAML::Node& adapt_manager, const std::string& matrix_name_str, const int Npars);

/// @brief If we don't have a covariance matrix to start from for adaptive tune we need to make one!
void CreateNewAdaptiveCovariance(const int Npars);

/// @brief HW: sets adaptive block matrix
/// @param block_indices Values for sub-matrix blocks
void SetAdaptiveBlocks(std::vector<std::vector<int>> block_indices, const int Npars);

/// @brief HW: Save adaptive throw matrix to file
void SaveAdaptiveToFile(const TString& outFileName, const TString& systematicName);

/// @brief sets throw matrix from a file
/// @param matrix_file_name name of file matrix lives in
/// @param matrix_name name of matrix in file
/// @param means_name name of means vec in file
void SetThrowMatrixFromFile(const std::string& matrix_file_name,
const std::string& matrix_name,
const std::string& means_name,
bool& use_adaptive,
const int Npars);




/// @brief Method to update adaptive MCMC
/// @see https://projecteuclid.org/journals/bernoulli/volume-7/issue-2/An-adaptive-Metropolis-algorithm/bj/1080222083.full
/// @param _fCurrVal Value of each parameter necessary for updating throw matrix
void UpdateAdaptiveCovariance(const std::vector<double>& _fCurrVal, const int steps_post_burn, const int Npars);

/// Meta variables related to adaption run time
/// When do we start throwing
int start_adaptive_throw;

/// When do we stop update the adaptive matrix
int start_adaptive_update;

/// Steps between changing throw matrix
int end_adaptive_update;

/// Steps between changing throw matrix
int adaptive_update_step;

/// Indices for block-matrix adaption
std::vector<int> adapt_block_matrix_indices;

/// Size of blocks for adaption
std::vector<int> adapt_block_sizes;

// Variables directedly linked to adaption
/// Mean values for all parameters
std::vector<double> par_means;

/// Full adaptive covariance matrix
TMatrixDSym* adaptive_covariance;
};

} // adaptive_mcmc namespace
3 changes: 2 additions & 1 deletion covariance/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ set(HEADERS
covarianceBase.h
covarianceOsc.h
covarianceXsec.h
adaptiveMCMCStruct.h
AdaptiveMCMCHandler.h
)

add_library(Covariance SHARED
ThrowParms.cpp
covarianceBase.cpp
covarianceOsc.cpp
covarianceXsec.cpp
AdaptiveMCMCHandler.cpp
)

set_target_properties(Covariance PROPERTIES
Expand Down
4 changes: 0 additions & 4 deletions covariance/CovarianceUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,19 @@
#include "TMatrixDSym.h"
#include "TVectorT.h"
#include "TVectorD.h"
#include "TCanvas.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TTree.h"
#include "TFile.h"
#include "TAxis.h"
#include "TRandom3.h"
#include "TMath.h"
#include "math.h"
#include "TDecompChol.h"
#include "TStopwatch.h"
#include "TMatrix.h"
#include "TMatrixDSymEigen.h"
#include "TMatrixDEigen.h"
#include "TDecompSVD.h"


#ifdef MULTITHREAD
#include "omp.h"
#endif
Expand Down
Loading
Loading