MUQ  0.4.3
SmolyakQuadrature.cpp
Go to the documentation of this file.
2 
4 
6 
7 #include <map>
8 #include <iostream>
9 
10 using namespace muq::Approximation;
11 using namespace muq::Utilities;
12 
13 SmolyakQuadrature::SmolyakQuadrature(unsigned int dim, std::shared_ptr<Quadrature> const& scalarRule) : SmolyakQuadrature(std::vector<std::shared_ptr<Quadrature>>(dim,scalarRule)){}
14 
15 
16 SmolyakQuadrature::SmolyakQuadrature(std::vector<std::shared_ptr<Quadrature>> const& scalarRulesIn) : Quadrature(scalarRulesIn.size()),
17  scalarRules(scalarRulesIn)
18 {}
19 
20 
21 void SmolyakQuadrature::Compute(unsigned int order)
22 {
23  Compute(order*Eigen::RowVectorXi::Ones(dim));
24 }
25 
26 void SmolyakQuadrature::Compute(Eigen::RowVectorXi const& orders)
27 {
28 
29  // Build the multiindex set.
30  std::shared_ptr<MultiIndexSet> multis = BuildMultis(orders);
31 
32  Compute(multis);
33 }
34 
35 
36 std::shared_ptr<MultiIndexSet> SmolyakQuadrature::BuildMultis(Eigen::RowVectorXi const& orders) const
37 {
38  // Use the minimum order in the vector to form a total order multiindex
39  int minOrder = orders.minCoeff();
40  assert(minOrder>=0);
41 
42  auto multis = MultiIndexFactory::CreateTotalOrder(dim,minOrder);
43 
44  // // Add other terms to get the right order
45  // for(int i=0; i<dim; ++i){
46  // for(int p=minOrder+1; p<=orders(i); ++p)
47  // {
48  // auto newMulti = std::make_shared<MultiIndex>(dim);
49  // newMulti->SetValue(i,p);
50  // multis += newMulti;
51  // }
52  // }
53 
54  return multis;
55 }
56 
57 
58 void SmolyakQuadrature::Compute(std::shared_ptr<MultiIndexSet> const& multis) {
59 
60  // Compute the weights caused by using a tensor product of quadrature rules directly
61  Eigen::VectorXd smolyWts = ComputeWeights(multis);
62 
63  auto tensorQuad = std::make_shared<FullTensorQuadrature>(scalarRules);
64 
65  // A map holding the unique quadrature points (keys) and weights (values)
66  std::map<Eigen::VectorXd, double, muq::Utilities::VectorLessThan<double>> quadParts;
67 
68  for(int i=0; i<multis->Size(); ++i)
69  {
70 
71  if(std::abs(smolyWts(i))>5.0*std::numeric_limits<double>::epsilon()){
72  Eigen::RowVectorXi multiVec = multis->IndexToMulti(i)->GetVector();
73 
74  tensorQuad->Compute(multiVec);
75 
76  auto& tensorPts = tensorQuad->Points();
77  auto& tensorWts = tensorQuad->Weights();
78 
79  // Add all the tensor product points to the map of Smolyak points
80  for(int ptInd = 0; ptInd<tensorPts.cols(); ++ptInd){
81 
82  auto iter = quadParts.find(tensorPts.col(ptInd));
83  if(iter!=quadParts.end()){
84  iter->second += smolyWts(i)*tensorWts(ptInd);
85  }else{
86  quadParts[tensorPts.col(ptInd)] = smolyWts(i)*tensorWts(ptInd);
87  }
88  }
89  }
90  }
91 
92  // Figure out how many nonzero weights we have
93  unsigned int numNz = 0;
94  double weightTol = 5.0*std::numeric_limits<double>::epsilon();
95  for(auto& keyVal : quadParts)
96  numNz += (std::abs(keyVal.second)>weightTol) ? 1.0 : 0.0;
97 
98  // Copy the unordered map, which has unique keys, into the Eigen matrix
99  pts.resize(dim,numNz);
100  wts.resize(numNz);
101  unsigned int ind = 0;
102  for(auto& part : quadParts){
103  if(std::abs(part.second)>weightTol){
104  pts.col(ind) = part.first;
105  wts(ind) = part.second;
106  ++ind;
107  }
108  }
109 }
110 
111 
112 void SmolyakQuadrature::UpdateWeights(unsigned int activeInd,
113  std::shared_ptr<MultiIndexSet> const& multis,
114  Eigen::VectorXd & multiWeights)
115 {
116  unsigned int dim = multis->GetMultiLength();
117  auto optMultis = MultiIndexFactory::CreateFullTensor(dim,1);
118 
119  auto& activeMulti = multis->IndexToMulti(activeInd);
120 
121  // This is the multiindex defining the Smolyak difference tensor product
122  auto& k = multis->IndexToMulti(activeInd);
123 
124  for(unsigned int j=0; j<optMultis->Size(); ++j){
125 
126  auto newMulti = MultiIndex::Copy(activeMulti);
127  double weightIncr = 1.0;
128 
129  // Loop over all the nonzero terms, which is where we have to decrement the order
130  for(auto it = optMultis->IndexToMulti(j)->GetNzBegin(); it != optMultis->IndexToMulti(j)->GetNzEnd(); ++it) {
131  if((it->second>0)&&(activeMulti->GetValue(it->first)>0)){
132  weightIncr *= -1;
133  newMulti->SetValue(it->first, activeMulti->GetValue(it->first)-1);
134  }else if(k->GetValue(it->first)==0){
135  weightIncr = 0.0;
136  }
137  }
138 
139  multiWeights(multis->MultiToIndex(newMulti)) += weightIncr;
140  }
141 }
142 
143 Eigen::VectorXd SmolyakQuadrature::ComputeWeights(std::shared_ptr<MultiIndexSet> const& multis)
144 {
145 
146  Eigen::VectorXd multiWeights = Eigen::VectorXd::Zero(multis->Size());
147 
148  for(unsigned int i = 0; i<multis->Size(); ++i) {
149  UpdateWeights(i, multis, multiWeights);
150  }
151 
152  return multiWeights;
153 }
Base class for multivariate quadrature rules. @detail An abstract class for computing nodes and weigh...
Definition: Quadrature.h:124
Computes static Smolyak quadrature rules for multivariate integration.
std::vector< std::shared_ptr< Quadrature > > scalarRules
SmolyakQuadrature(unsigned int dim, std::shared_ptr< Quadrature > const &scalarRule)
static void UpdateWeights(unsigned int activeInd, std::shared_ptr< muq::Utilities::MultiIndexSet > const &multis, Eigen::VectorXd &multiWeights)
virtual void Compute(unsigned int order) override
static Eigen::VectorXd ComputeWeights(std::shared_ptr< muq::Utilities::MultiIndexSet > const &multis)
std::shared_ptr< muq::Utilities::MultiIndexSet > BuildMultis(Eigen::RowVectorXi const &orders) const