https://mooseframework.inl.gov
LMC.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 #ifdef MOOSE_LIBTORCH_ENABLED
10 
11 #include "LMC.h"
12 #include "MooseRandom.h"
13 #include "MathUtils.h"
14 
15 registerMooseObject("StochasticToolsApp", LMC);
16 
19 {
21  params.addClassDescription("Covariance function for multioutput Gaussian Processes based on the "
22  "Linear Model of Coregionalization (LMC).");
23  params.addParam<unsigned int>(
24  "num_latent_funcs", 1., "The number of latent functions for the expansion of the outputs.");
25  params.makeParamRequired<unsigned int>("num_outputs");
26  params.makeParamRequired<std::vector<UserObjectName>>("covariance_functions");
27  return params;
28 }
29 
30 LMC::LMC(const InputParameters & parameters)
31  : CovarianceFunctionBase(parameters),
32  _num_expansion_terms(getParam<unsigned int>("num_latent_funcs"))
33 {
34  // We use a random number generator to obtain the initial guess for the
35  // hyperparams
36  MooseRandom generator_latent;
37  generator_latent.seed(0, 1980);
38 
39  // First add and initialize the a A coefficients in the (aa^T+lambda*I) matrix
40  for (const auto exp_i : make_range(_num_expansion_terms))
41  {
42  const std::string a_coeff_name = "acoeff_" + std::to_string(exp_i);
43  std::vector<Real> acoeff_values(_num_outputs);
44  for (const auto out_i : make_range(_num_outputs))
45  acoeff_values[out_i] = 3.0 * generator_latent.rand(0) + 1.0;
46  auto & acoeff_vector = addVectorRealHyperParameter(a_coeff_name, acoeff_values, true);
47  _a_coeffs.push_back(&acoeff_vector);
48  }
49 
50  // Then add and initialize the lambda coefficients in the (aa^T+lambda*I) matrix
51  for (const auto exp_i : make_range(_num_expansion_terms))
52  {
53  const std::string lambda_name = "lambda_" + std::to_string(exp_i);
54  std::vector<Real> lambda_values(_num_outputs);
55  for (const auto out_i : make_range(_num_outputs))
56  lambda_values[out_i] = 3.0 * generator_latent.rand(0) + 1.0;
57  auto & lambda_vector = addVectorRealHyperParameter(lambda_name, lambda_values, true);
58  _lambdas.push_back(&lambda_vector);
59  }
60 }
61 
62 void
64  const torch::Tensor & x,
65  const torch::Tensor & xp,
66  const bool is_self_covariance) const
67 {
68  const auto options = x.options().dtype(at::kDouble);
69  // Create temporary vectors for constructing the covariance matrix
70  torch::Tensor K_params = torch::zeros({x.sizes()[0], xp.sizes()[0]}, options);
71  torch::Tensor B = torch::zeros({_num_outputs, _num_outputs}, options);
72  K = torch::zeros({x.sizes()[0] * _num_outputs, xp.sizes()[0] * _num_outputs}, options);
73  torch::Tensor K_working;
74 
75  // For every expansion term we add the contribution to the covariance matrix
76  for (const auto exp_i : make_range(_num_expansion_terms))
77  {
78  _covariance_functions[exp_i]->computeCovarianceMatrix(K_params, x, xp, is_self_covariance);
79  computeBMatrix(B, exp_i);
80  K_working = torch::kron(B, K_params);
81  K += K_working;
82  }
83 }
84 
85 bool
86 LMC::computedKdhyper(torch::Tensor & dKdhp,
87  const torch::Tensor & x,
88  const std::string & hyper_param_name,
89  unsigned int ind) const
90 {
91  // Early return in the paramter name is longer than the expected [name] prefix.
92  // We prefix the parameter names with the name of the covariance function.
93  if (name().length() + 1 > hyper_param_name.length())
94  return false;
95 
96  // Strip the prefix from the given parameter name
97  const std::string name_without_prefix = hyper_param_name.substr(name().length() + 1);
98 
99  // Check if the parameter is tunable
100  if (_tunable_hp.find(hyper_param_name) != _tunable_hp.end())
101  {
102  const std::string acoeff_prefix = "acoeff_";
103  const std::string lambda_prefix = "lambda_";
104 
105  // Allocate storage for the factors of the total gradient matrix
106  const auto options = x.options().dtype(at::kDouble);
107  torch::Tensor dBdhp = torch::zeros({_num_outputs, _num_outputs}, options);
108  torch::Tensor K_params = torch::zeros({x.sizes()[0], x.sizes()[0]}, options);
109 
110  if (name_without_prefix.find(acoeff_prefix) != std::string::npos)
111  {
112  // Automatically grab the expansion index
113  const int number = std::stoi(name_without_prefix.substr(acoeff_prefix.length()));
114  computeAGradient(dBdhp, number, ind);
115  _covariance_functions[number]->computeCovarianceMatrix(K_params, x, x, true);
116  }
117  else if (name_without_prefix.find(lambda_prefix) != std::string::npos)
118  {
119  // Automatically grab the expansion index
120  const int number = std::stoi(name_without_prefix.substr(lambda_prefix.length()));
121  computeLambdaGradient(dBdhp, number, ind);
122  _covariance_functions[number]->computeCovarianceMatrix(K_params, x, x, true);
123  }
124  dKdhp = torch::kron(dBdhp, K_params);
125  return true;
126  }
127  else
128  {
129  // Allocate storage for the matrix factors
130  const auto options = x.options().dtype(at::kDouble);
131  torch::Tensor B_tmp = torch::zeros({_num_outputs, _num_outputs}, options);
132  torch::Tensor B = torch::zeros({_num_outputs, _num_outputs}, options);
133  torch::Tensor dKdhp_sub = torch::zeros({x.sizes()[0], x.sizes()[0]}, options);
134 
135  // First, check the dependent covariances
136  bool found = false;
137  for (const auto dependent_covar : _covariance_functions)
138  if (!found)
139  found = dependent_covar->computedKdhyper(dKdhp_sub, x, hyper_param_name, ind);
140 
141  if (!found)
142  mooseError("Hyperparameter ", hyper_param_name, "not found!");
143 
144  // Then we compute the output covariance
145  for (const auto exp_i : make_range(_num_expansion_terms))
146  {
147  computeBMatrix(B_tmp, exp_i);
148  B += B_tmp;
149  }
150 
151  dKdhp = torch::kron(B, dKdhp_sub);
152 
153  return true;
154  }
155 
156  return false;
157 }
158 
159 void
160 LMC::computeBMatrix(torch::Tensor & Bmat, const unsigned int exp_i) const
161 {
162  const auto & a_coeffs = *_a_coeffs[exp_i];
163  const auto & lambda_coeffs = *_lambdas[exp_i];
164  Bmat = torch::outer(a_coeffs, a_coeffs) + torch::diag(lambda_coeffs);
165 }
166 
167 void
168 LMC::computeAGradient(torch::Tensor & grad,
169  const unsigned int exp_i,
170  const unsigned int index) const
171 {
172  const auto & a_coeffs = *_a_coeffs[exp_i];
173  mooseAssert(cast_int<int64_t>(index) < a_coeffs.numel(), "Incorrect LMC coefficient index.");
174  auto basis = torch::zeros_like(a_coeffs);
175  const auto index_tensor =
176  torch::tensor({cast_int<int64_t>(index)},
177  torch::TensorOptions().dtype(torch::kLong).device(a_coeffs.device()));
178  basis.index_fill_(0, index_tensor, 1.0);
179  grad = torch::outer(basis, a_coeffs) + torch::outer(a_coeffs, basis);
180 }
181 
182 void
184  const unsigned int exp_i,
185  const unsigned int index) const
186 {
187  mooseAssert(index < _num_outputs, "Incorrect LMC lambda index.");
188  auto basis = torch::zeros_like(*_lambdas[exp_i]);
189  const auto index_tensor =
190  torch::tensor({cast_int<int64_t>(index)},
191  torch::TensorOptions().dtype(torch::kLong).device(_lambdas[exp_i]->device()));
192  basis.index_fill_(0, index_tensor, 1.0);
193  grad = torch::diag(basis);
194 }
195 
196 #endif
std::unordered_set< std::string > _tunable_hp
list of tunable hyper-parameters
bool computedKdhyper(torch::Tensor &dKdhp, const torch::Tensor &x, const std::string &hyper_param_name, unsigned int ind) const override
Redirect dK/dhp for hyperparameter "hp".
Definition: LMC.C:86
const unsigned int _num_expansion_terms
The number of expansion terms in the output ovariance matrix.
Definition: LMC.h:67
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
static const std::string K
Definition: NS.h:174
void seed(std::size_t i, unsigned int seed)
LMC(const InputParameters &parameters)
Definition: LMC.C:30
std::vector< CovarianceFunctionBase * > _covariance_functions
Vector of pointers to the dependent covariance functions.
Base class for covariance functions that are used in Gaussian Processes.
registerMooseObject("StochasticToolsApp", LMC)
static InputParameters validParams()
static InputParameters validParams()
Definition: LMC.C:18
std::vector< const torch::Tensor * > _lambdas
Definition: LMC.h:73
const std::string & name() const
const unsigned int _num_outputs
The number of outputs this covariance function is used to describe.
const std::vector< double > x
std::string grad(const std::string &var)
Definition: NS.h:92
void computeAGradient(torch::Tensor &grad, const unsigned int exp_i, const unsigned int index) const
Computes the gradient of $B$ with respect to the entries in $a_i$ in the following expression: $B = ...
Definition: LMC.C:168
void computeBMatrix(torch::Tensor &Bmat, const unsigned int exp_i) const
Computes the covariance matrix for the outputs (using the latent coefficients) We use a $B = a_i a_i...
Definition: LMC.C:160
void computeLambdaGradient(torch::Tensor &grad, const unsigned int exp_i, const unsigned int index) const
Computes the gradient of $B$ with respect to the entries in $lambda_i$ in the following expression: $...
Definition: LMC.C:183
void computeCovarianceMatrix(torch::Tensor &K, const torch::Tensor &x, const torch::Tensor &xp, const bool is_self_covariance) const override
Generates the Covariance Matrix given two sets of points in the parameter space.
Definition: LMC.C:63
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
void makeParamRequired(const std::string &name)
void addClassDescription(const std::string &doc_string)
torch::Tensor & addVectorRealHyperParameter(const std::string &name, const std::vector< Real > &value, const bool is_tunable)
Register a vector hyperparameter to this covariance function.
Real rand(std::size_t i)
std::vector< const torch::Tensor * > _a_coeffs
The vectors in the $B = a_i a_i^T + diag(lambda_i)$ expansion.
Definition: LMC.h:72
Covariance function for multi-output Gaussian Processes based on the linear model of coregionalizatio...
Definition: LMC.h:19
void ErrorVector unsigned int