MUQ  0.4.3
BasisExpansion.cpp
Go to the documentation of this file.
2 
4 
7 
10 using namespace muq::Approximation;
11 using namespace muq::Utilities;
12 
13 BasisExpansion::BasisExpansion(std::vector<std::shared_ptr<IndexedScalarBasis>> const& basisCompsIn,
14  bool coeffInput) :
15  BasisExpansion(basisCompsIn,
16  MultiIndexFactory::CreateTotalOrder(basisCompsIn.size(),0))
17 {
18 }
19 
20 BasisExpansion::BasisExpansion(std::vector<std::shared_ptr<IndexedScalarBasis>> const& basisCompsIn,
21  std::shared_ptr<muq::Utilities::MultiIndexSet> multisIn,
22  bool coeffInput) :
23  BasisExpansion(basisCompsIn,
24  multisIn,
25  Eigen::MatrixXd::Zero(1,multisIn->Size()))
26 {
27 };
28 
29 BasisExpansion::BasisExpansion(std::vector<std::shared_ptr<IndexedScalarBasis>> const& basisCompsIn,
30  std::shared_ptr<muq::Utilities::MultiIndexSet> multisIn,
31  Eigen::MatrixXd const& coeffsIn,
32  bool coeffInput) :
33  ModPiece(GetInputSizes(multisIn, coeffsIn, coeffInput), GetOutputSizes(multisIn, coeffsIn)),
34  basisComps(basisCompsIn),
35  multis(multisIn),
36  coeffs(coeffsIn)
37 {
38  assert(basisComps.size() == multis->GetMultiLength());
39  assert(multis->Size() == coeffs.cols());
40 }
41 
42 Eigen::VectorXi BasisExpansion::GetInputSizes(std::shared_ptr<muq::Utilities::MultiIndexSet> multisIn,
43  Eigen::MatrixXd const& coeffsIn,
44  bool coeffInput)
45 {
46  Eigen::VectorXi output;
47  if(coeffInput){
48  output.resize(2);
49  output(0) = multisIn->GetMultiLength();
50  output(1) = coeffsIn.cols()*coeffsIn.rows();
51  }else{
52  output.resize(1);
53  output(0) = multisIn->GetMultiLength();
54  }
55  return output;
56 }
57 
58 Eigen::VectorXi BasisExpansion::GetOutputSizes(std::shared_ptr<muq::Utilities::MultiIndexSet> multisIn,
59  Eigen::MatrixXd const& coeffsIn)
60 {
61  return coeffsIn.rows() * Eigen::VectorXi::Ones(1);
62 }
63 
64 
65 Eigen::VectorXd BasisExpansion::GetAllTerms(Eigen::VectorXd const& x) const{
66 
67  // Get the maximum orders
68  Eigen::VectorXi maxOrders = multis->GetMaxOrders();
69 
70  // Evaluate each dimension up to the maximum order
71  std::vector<std::vector<double>> uniEvals(basisComps.size());
72  assert(uniEvals.size() == maxOrders.size());
73 
74  for(int i=0; i<uniEvals.size(); ++i){
75  uniEvals.at(i).resize(maxOrders(i)+1);
76  for(int j=0; j<=maxOrders(i); ++j){
77  uniEvals.at(i).at(j) = basisComps.at(i)->BasisEvaluate(j, x(i));
78  }
79  }
80 
81  // Now that we have all the univariate terms evaluated, evaluate the expansion
82  Eigen::VectorXd allTerms = Eigen::VectorXd::Ones(multis->Size());
83  for(int i=0; i<multis->Size(); ++i){
84 
85  for(auto it = multis->at(i)->GetNzBegin(); it != multis->at(i)->GetNzEnd(); ++it)
86  allTerms(i) *= uniEvals.at(it->first).at(it->second);
87  }
88 
89  return allTerms;
90 }
91 
92 Eigen::MatrixXd BasisExpansion::GetAllDerivs(Eigen::VectorXd const& x) const{
93 
94  // Get the maximum orders
95  Eigen::VectorXi maxOrders = multis->GetMaxOrders();
96 
97  // Evaluate each dimension up to the maximum order
98  std::vector<std::vector<double>> uniEvals(basisComps.size());
99  std::vector<std::vector<double>> uniDerivs(basisComps.size());
100  assert(uniEvals.size() == maxOrders.size());
101 
102  for(int i=0; i<uniEvals.size(); ++i){
103  uniEvals.at(i).resize(maxOrders(i)+1);
104  uniDerivs.at(i).resize(maxOrders(i)+1);
105 
106  for(int j=0; j<=maxOrders(i); ++j){
107  uniEvals.at(i).at(j) = basisComps.at(i)->BasisEvaluate(j, x(i));
108  uniDerivs.at(i).at(j) = basisComps.at(i)->DerivativeEvaluate(j, 1, x(i));
109  }
110  }
111 
112  // Now that we have all the univariate terms evaluated, evaluate the expansion
113  Eigen::MatrixXd allDerivs = Eigen::MatrixXd::Ones(multis->Size(),x.size());
114  for(int i=0; i<multis->Size(); ++i){
115 
116  // Loop over each dimension
117  for(int j=0; j<x.size(); ++j){
118  if(multis->at(i)->GetValue(j)==0){
119  allDerivs(i,j) = 0;
120  }else{
121  for(auto it = multis->at(i)->GetNzBegin(); it != multis->at(i)->GetNzEnd(); ++it){
122 
123  if(it->first == j){
124  allDerivs(i,j) *= uniDerivs.at(it->first).at(it->second);
125  }else{
126  allDerivs(i,j) *= uniEvals.at(it->first).at(it->second);
127  }
128 
129  }
130  }
131  }
132  }
133 
134  return allDerivs;
135 }
136 
137 std::vector<Eigen::MatrixXd> BasisExpansion::GetHessians(Eigen::VectorXd const& x) const{
138 
139  // Get the maximum orders
140  Eigen::VectorXi maxOrders = multis->GetMaxOrders();
141 
142  // Evaluate each dimension up to the maximum order
143  std::vector<std::vector<double>> uniEvals(basisComps.size());
144  std::vector<std::vector<double>> uniD1(basisComps.size()); // first derivatives
145  std::vector<std::vector<double>> uniD2(basisComps.size()); // second derivatives
146 
147  assert(uniEvals.size() == maxOrders.size());
148 
149  for(int i=0; i<uniEvals.size(); ++i){
150  uniEvals.at(i).resize(maxOrders(i)+1);
151  uniD1.at(i).resize(maxOrders(i)+1);
152  uniD2.at(i).resize(maxOrders(i)+1);
153 
154  for(int j=0; j<=maxOrders(i); ++j){
155  uniEvals.at(i).at(j) = basisComps.at(i)->BasisEvaluate(j, x(i));
156  uniD1.at(i).at(j) = basisComps.at(i)->DerivativeEvaluate(j, 1, x(i));
157  uniD2.at(i).at(j) = basisComps.at(i)->DerivativeEvaluate(j, 2, x(i));
158  }
159  }
160 
161  std::vector<Eigen::MatrixXd> hessians(coeffs.rows(), Eigen::MatrixXd::Zero(x.size(),x.size()));
162 
163  // Loop over each term in the expansion
164  for(int i=0; i<multis->Size(); ++i){
165 
166  // Loop over each dimension
167  for(int j=0; j<x.size(); ++j){
168  for(int k=0; k<=j; ++k){
169  if((multis->at(i)->GetValue(j)!=0) && ((multis->at(i)->GetValue(k)!=0))){
170 
171  double tempVal = 1.0;
172 
173  for(auto it = multis->at(i)->GetNzBegin(); it != multis->at(i)->GetNzEnd(); ++it){
174 
175  if((j==k) && (it->first == j)){
176  tempVal *= uniD2.at(it->first).at(it->second);
177  }else if((it->first == j)||(it->first == k)){
178  tempVal *= uniD1.at(it->first).at(it->second);
179  }else{
180  tempVal *= uniEvals.at(it->first).at(it->second);
181  }
182  }
183 
184  // Add the results into each of the hessians matrices
185  for(int kk=0; kk<coeffs.rows(); ++kk)
186  hessians.at(kk)(j,k) += coeffs(kk,i)*tempVal;
187  }
188  }
189  }
190  }
191 
192  // make sure all the hessians are symmetric
193  for(int kk=0; kk<coeffs.rows(); ++kk)
194  hessians.at(kk).triangularView<Eigen::Upper>() = hessians.at(kk).triangularView<Eigen::Lower>().transpose();
195 
196  return hessians;
197 
198 }
199 
200 void BasisExpansion::ProcessCoeffs(Eigen::VectorXd const& newCoeffs)
201 {
202  assert(newCoeffs.size() == coeffs.rows()*coeffs.cols());
203 
204  Eigen::Map<const Eigen::MatrixXd> coeffMap(newCoeffs.data(), coeffs.rows(), coeffs.cols());
205 
206  coeffs = coeffMap;
207 }
208 
209 
211 
212  Eigen::VectorXd const& x = inputs.at(0);
213  if(inputs.size()>1)
214  ProcessCoeffs(inputs.at(1));
215 
216  // Compute the output
217  outputs.resize(1);
218  outputs.at(0) = (coeffs*GetAllTerms(x)).eval();
219 }
220 
221 void BasisExpansion::JacobianImpl(unsigned int const wrtOut,
222  unsigned int const wrtIn,
224 {
225  assert(wrtOut==0);
226 
227  Eigen::VectorXd const& x = inputs.at(0);
228  if(inputs.size()>1)
229  ProcessCoeffs(inputs.at(1));
230 
231  if(wrtIn==0){
232  jacobian = Eigen::MatrixXd(coeffs*GetAllDerivs(x));
233  }else if(wrtIn==1){
234  jacobian = Eigen::MatrixXd(GetAllTerms(x).transpose().replicate(coeffs.rows(),1));
235  }
236 }
237 
238 
239 Eigen::MatrixXd BasisExpansion::SecondDerivative(unsigned outputDim,
240  unsigned derivDim1,
241  unsigned derivDim2,
242  Eigen::VectorXd const& x,
243  Eigen::MatrixXd const& newCoeffs)
244 {
245  SetCoeffs(newCoeffs);
246  return SecondDerivative(outputDim, derivDim1, derivDim2, x);
247 }
248 
249 Eigen::MatrixXd BasisExpansion::SecondDerivative(unsigned outputDim,
250  unsigned derivDim1,
251  unsigned derivDim2,
252  Eigen::VectorXd const& x)
253 {
254  if((derivDim1==0) && (derivDim2==1)){
255  return GetAllDerivs(x).transpose();
256  }else if((derivDim1==1) && (derivDim2==0)){
257  return GetAllDerivs(x);
258  }else if(derivDim1==0){
259  return GetHessians(x).at(outputDim);
260  }else{
261  return Eigen::MatrixXd::Zero(coeffs.cols(), coeffs.cols());
262  }
263 }
264 
265 
266 Eigen::MatrixXd BasisExpansion::GetCoeffs() const{
267  return coeffs;
268 }
269 
270 void BasisExpansion::SetCoeffs(Eigen::MatrixXd const& allCoeffs){
271  assert(coeffs.rows()==allCoeffs.rows());
272  assert(coeffs.cols()==allCoeffs.cols());
273  coeffs = allCoeffs;
274 }
275 
276 Eigen::MatrixXd BasisExpansion::BuildVandermonde(Eigen::MatrixXd const& evalPts) const
277 {
278  Eigen::MatrixXd vand(evalPts.cols(), NumTerms());
279 
280  for(int i=0; i<evalPts.cols(); ++i)
281  vand.row(i) = GetAllTerms(evalPts.col(i)).transpose();
282 
283  return vand;
284 }
285 
286 
287 Eigen::MatrixXd BasisExpansion::BuildDerivMatrix(Eigen::MatrixXd const& evalPts, int wrtDim) const
288 {
289  Eigen::MatrixXd output(evalPts.cols(), NumTerms());
290 
291  for(int i=0; i<evalPts.cols(); ++i)
292  output.row(i) = GetAllDerivs(evalPts.col(i)).col(wrtDim).transpose();
293 
294  return output;
295 }
296 
297 
298 void BasisExpansion::ToHDF5(std::string filename, std::string groupName) const
299 {
301  ToHDF5(fout[groupName]);
302 }
303 
305 {
306  multis->ToHDF5(group, "/multiindices");
307  auto dset = group.CreateDataset<double>("/coefficients", coeffs.rows(), coeffs.cols());
308  dset = coeffs;
309 
310  // Create a vector of scalar basis names
311  std::vector<std::string> type_strs;
313  for(auto& basis : basisComps){
314  bool matchFound = false;
315 
316  // Find the corresponding entry in the constructor map to get the name
317  for(auto const& pair : nameMap){
318  std::shared_ptr<IndexedScalarBasis> testBasis = pair.second();
319 
320  if(GetTypeName(testBasis)==GetTypeName(basis)){
321  matchFound = true;
322  type_strs.push_back(pair.first);
323  }
324  }
325  assert(matchFound);
326  }
327 
328  group.attrs["basis_types"] = muq::Utilities::StringUtilities::Combine(type_strs);
329  group.attrs["inputSizes"] = inputSizes;
330  group.attrs["expansion_type"] = "Generic";
331 }
332 
333 std::shared_ptr<BasisExpansion> BasisExpansion::FromHDF5(std::string filename, std::string groupName)
334 {
336  return BasisExpansion::FromHDF5(fin[groupName]);
337 }
338 
339 std::shared_ptr<BasisExpansion> BasisExpansion::FromHDF5(muq::Utilities::H5Object &group)
340 {
341 
342  Eigen::VectorXi inputSizes = group.attrs["inputSizes"];
343  bool coeffInput = (inputSizes.size() > 1);
344 
345  std::vector<std::string> scalarBasisNames = muq::Utilities::StringUtilities::Split(std::string(group.attrs["basis_types"]));
346  std::vector<std::shared_ptr<IndexedScalarBasis>> scalarBases;
347  for(auto& name : scalarBasisNames)
348  scalarBases.push_back( IndexedScalarBasis::Construct(name));
349 
350  auto mset = MultiIndexSet::FromHDF5(group["/multiindices"]);
351  Eigen::MatrixXd coeffs = group["/coefficients"];
352 
353  std::string expansionType = group.attrs["expansion_type"];
354  if(expansionType=="PCE"){
355  return std::make_shared<PolynomialChaosExpansion>(scalarBases, mset, coeffs);
356  }else{
357  return std::make_shared<BasisExpansion>(scalarBases, mset, coeffs, coeffInput);
358  }
359 }
Class for defining expansions of basis functions defined by a MultiIndexSet and collection of IndexSc...
std::vector< Eigen::MatrixXd > GetHessians(Eigen::VectorXd const &x) const
void ProcessCoeffs(Eigen::VectorXd const &newCoeffs)
Eigen::VectorXd GetAllTerms(Eigen::VectorXd const &x) const
virtual void JacobianImpl(unsigned int const wrtIn, unsigned int const wrtOut, muq::Modeling::ref_vector< Eigen::VectorXd > const &inputs) override
Eigen::MatrixXd BuildDerivMatrix(Eigen::MatrixXd const &evalPts, int wrtDim) const
std::shared_ptr< muq::Utilities::MultiIndexSet > multis
static std::shared_ptr< BasisExpansion > FromHDF5(std::string filename, std::string groupName="/")
Loads an expansion from an HDF5 file.
Eigen::MatrixXd BuildVandermonde(Eigen::MatrixXd const &evalPts) const
virtual unsigned NumTerms() const
static Eigen::VectorXi GetOutputSizes(std::shared_ptr< muq::Utilities::MultiIndexSet > multisIn, Eigen::MatrixXd const &coeffsIn)
BasisExpansion(std::vector< std::shared_ptr< IndexedScalarBasis >> const &basisCompsIn, bool coeffInput=false)
Eigen::MatrixXd GetCoeffs() const
Eigen::MatrixXd GetAllDerivs(Eigen::VectorXd const &x) const
Eigen::MatrixXd SecondDerivative(unsigned outputDim, unsigned wrtDim1, unsigned wrtDim2, Eigen::VectorXd const &evalPt, Eigen::MatrixXd const &coeffs)
static Eigen::VectorXi GetInputSizes(std::shared_ptr< muq::Utilities::MultiIndexSet > multisIn, Eigen::MatrixXd const &coeffsIn, bool coeffInput)
std::vector< std::shared_ptr< IndexedScalarBasis > > basisComps
virtual void EvaluateImpl(muq::Modeling::ref_vector< Eigen::VectorXd > const &inputs) override
void SetCoeffs(Eigen::MatrixXd const &allCoeffs)
virtual void ToHDF5(std::string filename, std::string groupName="/") const
Saves the expansion to group in an HDF5 file.
static std::shared_ptr< IndexedScalarBasis > Construct(std::string const &polyName)
static std::shared_ptr< ScalarBasisMapType > GetScalarBasisMap()
Eigen::MatrixXd jacobian
Definition: ModPiece.h:506
const Eigen::VectorXi inputSizes
Definition: ModPiece.h:469
std::vector< Eigen::VectorXd > outputs
Definition: ModPiece.h:503
std::string name
A unique name for this WorkPiece. Defaults to <ClassName>_<id>
Definition: WorkPiece.h:583
AttributeList attrs
Definition: H5Object.h:205
H5Object & CreateDataset(std::string const &setName, unsigned int rows, unsigned int cols=0)
Definition: H5Object.h:145
A factory class with static methods for generating MultiIndexSets.
std::vector< std::reference_wrapper< const T > > ref_vector
A vector of references to something ...
Definition: WorkPiece.h:37
std::string Combine(std::vector< std::string > strs, char delim=',')
Combine a vector of strings with a specified delimiter. The opposite of Split.
std::vector< std::string > Split(std::string str, char delim=',')
Split a string into parts based on a particular character delimiter. Also Strips whitespace from part...
std::string GetTypeName(PointerType const &ptr)
Definition: Demangler.h:15
H5Object OpenFile(std::string const &filename)
Open an HDF5 file and return the root object.
Definition: H5Object.cpp:321