MUQ  0.4.3
MultiIndexSet.cpp
Go to the documentation of this file.
3 
4 #include <algorithm>
5 
6 using namespace muq::Utilities;
7 using namespace std;
8 
9 std::shared_ptr<MultiIndexSet> muq::Utilities::operator+=( std::shared_ptr<MultiIndexSet> x,
10  std::shared_ptr<MultiIndexSet> y)
11 {
12  (*x)+=(*y);
13  return x;
14 }
15 
16 std::shared_ptr<MultiIndexSet> muq::Utilities::operator+=( std::shared_ptr<MultiIndexSet> x,
17  std::shared_ptr<MultiIndex> y)
18 {
19  (*x)+=y;
20  return x;
21 }
22 
23 MultiIndexSet::MultiIndexSet(const unsigned dimIn,
24  shared_ptr<MultiIndexLimiter> limiterIn) : maxOrders(Eigen::VectorXi::Zero(dimIn)),
25  dim(dimIn),
26  limiter(limiterIn)
27 {
28 };
29 
30 void MultiIndexSet::SetLimiter(std::shared_ptr<MultiIndexLimiter> const& limiterIn){
31 
32  // first, make sure no active terms in the set currently obey the new limiter.
33  // If a term is inactive, remove all edges tied to it
34  for(int globalInd=0; globalInd<allMultis.size(); ++globalInd)
35  {
36  if(IsActive(globalInd)){
37  if(!limiterIn->IsFeasible(allMultis.at(globalInd))){
38  std::stringstream msg;
39  msg << "Invalid limiter passed to MultiIndexSet::SetLimiter. The active multi-index, ";
40  msg << allMultis.at(globalInd)->GetVector() << ", is not valid with the new limiter.\n";
41  throw std::invalid_argument(msg.str());
42  }
43  }else{
44 
45  if(!limiterIn->IsFeasible(allMultis.at(globalInd))){
46  for(int inNode : inEdges[globalInd])
47  outEdges[inNode].erase(globalInd);
48  inEdges[globalInd].clear();
49  }
50  }
51  }
52 
53  // copy the limiter
54  limiter = limiterIn;
55 }
56 
57 std::shared_ptr<MultiIndexSet> MultiIndexSet::CloneExisting(std::shared_ptr<MultiIndexSet> const& original)
58 {
59  auto output = make_shared<MultiIndexSet>(original->dim, original->limiter);
60 
61  output->active2global = original->active2global;
62  output->outEdges = original->outEdges;
63  output->inEdges = original->inEdges;
64  output->maxOrders = original->maxOrders;
65  output->allMultis = original->allMultis;
66 
67  return output;
68 }
69 
70 // Eigen::MatrixXu MultiIndexSet::GetAllMultiIndices() const
71 // {
72 //
73 // Eigen::MatrixXu output(active2local.size(), dim);
74 // for(int i=0; i<active2local.size(); ++i){
75 // auto multi = pool->at(local2global[active2local[i]]);
76 // int multiDim = multi->GetDimension();
77 // output.row(i).head(multiDim) = multi->GetMulti();
78 // }
79 //
80 // return output;
81 // }
82 
83 int MultiIndexSet::MultiToIndex(std::shared_ptr<MultiIndex> const& input) const{
84 
85  auto localIter = multi2global.find(input);
86 
87  if(localIter!=multi2global.end()){
88  return global2active[localIter->second];
89  }else{
90  return -1;
91  }
92 }
93 
94 
95 int MultiIndexSet::AddMulti(std::shared_ptr<MultiIndex> const& newMulti)
96 {
97  allMultis.push_back(newMulti);
98 
99  int globalInd = allMultis.size() - 1;
100  multi2global[newMulti] = globalInd;
101 
102  global2active.push_back(-1);
103 
104  inEdges.push_back(std::set<int>());
105  outEdges.push_back(std::set<int>());
106 
107  assert(allMultis.size() == global2active.size());
108 
109  AddForwardNeighbors(globalInd,false);
110  AddBackwardNeighbors(globalInd, false);
111 
112  return globalInd;
113 }
114 
118 int MultiIndexSet::AddActive(std::shared_ptr<MultiIndex> const& newNode)
119 {
120  int globalInd = AddInactive(newNode);
121 
122  if(globalInd>=0){
123 
124  Activate(globalInd);
125  return global2active[globalInd];
126 
127  }else{
128  return -1;
129  }
130 }
131 
132 
133 
134 int MultiIndexSet::AddInactive(std::shared_ptr<MultiIndex> const& newNode)
135 {
136  auto iter = multi2global.find(newNode);
137 
138  if(iter!=multi2global.end()){
139 
140  return iter->second;
141 
142  }else if(limiter->IsFeasible(newNode)){
143 
144  return AddMulti(newNode);
145 
146  }else{
147 
148  return -1;
149  }
150 }
151 
152 bool MultiIndexSet::IsActive(std::shared_ptr<MultiIndex> const& multiIndex) const
153 {
154  auto iter = multi2global.find(multiIndex);
155 
156  if(iter!=multi2global.end()){
157  return IsActive(iter->second);
158  }else{
159  return false;
160  }
161 }
162 
163 bool MultiIndexSet::IsActive(unsigned int globalIndex) const
164 {
165  return global2active[globalIndex] >= 0;
166 }
167 
168 bool MultiIndexSet::IsAdmissible(unsigned int globalIndex) const
169 {
170  auto& multi = allMultis.at(globalIndex);
171 
172  if(!limiter->IsFeasible(multi))
173  return false;
174 
175  if(IsActive(globalIndex))
176  return true;
177 
178  // count the number of input edges that are coming from active indices
179  int numAdmiss = 0;
180  for(int inNode : inEdges.at(globalIndex)){
181  if(IsActive(inNode))
182  numAdmiss++;
183  }
184 
185  if(numAdmiss==multi->nzInds.size()){
186  return true;
187  }else{
188  return false;
189  }
190 }
191 
192 bool MultiIndexSet::IsAdmissible(std::shared_ptr<MultiIndex> const& multiIndex) const
193 {
194  auto iter = multi2global.find(multiIndex);
195  if(iter==multi2global.end()){
196  return false;
197  }else{
198  return IsAdmissible(iter->second);
199  }
200 }
201 
202 
203 bool MultiIndexSet::IsExpandable(unsigned int activeIndex) const
204 {
205  // an index is expandable when at least one forward neighbor is admissible but not active (i.e. outedge)
206 
207  // loop through the outgoing edges for this node
208  for(int nextInd : outEdges[active2global.at(activeIndex)]){
209  if(!IsActive(nextInd)&&IsAdmissible(nextInd))
210  return true;
211  }
212  return false;
213 }
214 
215 void MultiIndexSet::Activate(int globalIndex)
216 {
217 
218  // the index is already in the global set, if the value is non-negative, it is also active and we don't need to do anything
219  if(global2active.at(globalIndex)<0)
220  {
221  auto& newNode = allMultis.at(globalIndex);
222 
223  // now add the index to the active set
224  active2global.push_back(globalIndex);
225 
226  int newActiveInd = active2global.size()-1;
227 
228  global2active.at(globalIndex) = newActiveInd;
229 
230  // update the maximum order
231  for(auto pair : newNode->nzInds)
232  maxOrders(pair.first) = std::max<unsigned>(maxOrders(pair.first),pair.second);
233 
234  AddForwardNeighbors(globalIndex,true);
235  AddBackwardNeighbors(globalIndex,true);
236  }
237 }
238 
239 void MultiIndexSet::Activate(std::shared_ptr<MultiIndex> const& multiIndex)
240 {
241  auto iter = multi2global.find(multiIndex);
242 
243  assert(iter!=multi2global.end());
244  assert(IsAdmissible(iter->second));
245 
246  Activate(iter->second);
247 }
248 
249 void MultiIndexSet::AddForwardNeighbors(unsigned int globalIndex, bool addInactive)
250 {
251 
252  Eigen::RowVectorXi base = allMultis.at(globalIndex)->GetVector();
253 
254  shared_ptr<MultiIndex> newNode;
255  for(unsigned int i=0; i<base.size(); ++i)
256  {
257  base(i)++;
258 
259  newNode = make_shared<MultiIndex>(base);
260 
261  if(limiter->IsFeasible(newNode)){
262 
263  auto iter = multi2global.find(newNode);
264 
265  if(iter!=multi2global.end()){
266  inEdges.at(iter->second).insert(globalIndex);
267  outEdges.at(globalIndex).insert(iter->second);
268  }else if(addInactive){
269  AddInactive(newNode);
270  }
271  }
272  base(i)--;
273  }
274 }
275 
276 std::vector<shared_ptr<MultiIndex>> MultiIndexSet::GetAdmissibleForwardNeighbors(unsigned int activeIndex)
277 {
278  unsigned int globalInd = active2global.at(activeIndex);
279 
280  vector<shared_ptr<MultiIndex>> output;
281  for( auto neighbor : outEdges[globalInd])
282  {
283  if(IsAdmissible(neighbor))
284  output.push_back(allMultis.at(neighbor));
285  }
286 
287  return output;
288 }
289 
290 std::vector<unsigned int> MultiIndexSet::GetFrontier() const {
291 
292  std::vector<unsigned int> frontierInds;
293 
294  for(unsigned int activeInd = 0; activeInd<active2global.size(); ++activeInd) {
295  if(IsExpandable(activeInd))
296  frontierInds.push_back(activeInd);
297  }
298 
299  return frontierInds;
300 }
301 
302 std::vector<unsigned int> MultiIndexSet::GetStrictFrontier() const
303 {
304  std::vector<unsigned int> frontierInds;
305 
306  for(unsigned int activeInd = 0; activeInd<active2global.size(); ++activeInd) {
307  // loop over all the forward neighbors
308  unsigned int globalInd = active2global.at(activeInd);
309 
310  bool isStrict = true;
311  for( auto neighbor : outEdges[globalInd])
312  isStrict = isStrict && (!IsActive(neighbor));
313 
314  if(isStrict)
315  frontierInds.push_back(activeInd);
316  }
317 
318  return frontierInds;
319 }
320 
321 std::vector<unsigned int> MultiIndexSet::GetBackwardNeighbors(unsigned int activeIndex) const
322 {
323  unsigned int globalInd = active2global.at(activeIndex);
324 
325  std::vector<unsigned int> output;
326  for(auto neighbor : inEdges[globalInd])
327  output.push_back(global2active.at(neighbor));
328 
329  return output;
330 }
331 
332 std::vector<unsigned int> MultiIndexSet::GetBackwardNeighbors(std::shared_ptr<MultiIndex> const& multiIndex) const
333 {
334  auto iter = multi2global.find(multiIndex);
335 
336  assert(iter!=multi2global.end());
337 
338  unsigned int globalInd = iter->second;
339  std::vector<unsigned int> output;
340  for(auto neighbor : inEdges[globalInd])
341  output.push_back(global2active.at(neighbor));
342 
343  return output;
344 }
345 
346 
347 unsigned int MultiIndexSet::NumActiveForward(unsigned int activeInd) const
348 {
349  unsigned int globalInd = active2global.at(activeInd);
350 
351  unsigned int numActive = 0;
352  for( auto neighbor : outEdges[globalInd])
353  {
354  if(IsActive(neighbor))
355  numActive++;
356  }
357  return numActive;
358 }
359 
360 unsigned int MultiIndexSet::NumForward(unsigned int activeInd) const
361 {
362  unsigned int globalInd = active2global.at(activeInd);
363  return outEdges[globalInd].size();
364 }
365 
366 void MultiIndexSet::AddBackwardNeighbors(unsigned int globalIndex, bool addInactive)
367 {
368  Eigen::RowVectorXi base = allMultis.at(globalIndex)->GetVector();
369 
370  shared_ptr<MultiIndex> newNode;
371  for(unsigned int i=0; i<base.size(); ++i)
372  {
373  if(base(i)>0){
374 
375  base(i)--;
376 
377  newNode = make_shared<MultiIndex>(base);
378 
379  if(limiter->IsFeasible(newNode)){
380  auto iter = multi2global.find(newNode);
381 
382  if(iter!=multi2global.end()){
383  outEdges.at(iter->second).insert(globalIndex);
384  inEdges.at(globalIndex).insert(iter->second);
385  }else if(addInactive){
386  AddInactive(newNode);
387  }
388  }
389  base(i)++;
390  }
391  }
392 }
393 
394 std::vector<unsigned> MultiIndexSet::Expand(unsigned int activeIndex)
395 {
396  if(activeIndex >= active2global.size()){
397  std::stringstream msg;
398  msg << "Invalid index passed to MultiIndexSet::Expand. A value of " << activeIndex << " was passed to the function, but only " << active2global.size() << " active components exist in the set.\n";
399  throw std::out_of_range(msg.str());
400  }
401 
402  vector<unsigned> newIndices;
403  unsigned globalIndex = active2global.at(activeIndex);
404 
405  // loop through the forward neighbors of this index
406  std::set<int> tempSet = outEdges.at(globalIndex);
407  for(int neighbor : tempSet)
408  {
409  if(IsAdmissible(neighbor)&&(!IsActive(neighbor))){
410  Activate(neighbor);
411  newIndices.push_back(global2active.at(neighbor));
412  }
413  }
414 
415  // return the vector of newly activated indices
416  return newIndices;
417 }
418 
419 std::vector<unsigned> MultiIndexSet::ForciblyExpand(unsigned int const activeIndex)
420 {
421  assert(activeIndex<active2global.size());
422 
423  vector<unsigned> newIndices;
424  unsigned globalIndex = active2global.at(activeIndex);
425 
426  // loop through the forward neighbors of this index
427  std::set<int>& tempSet = outEdges.at(globalIndex);
428  for(int neighbor : tempSet)
429  ForciblyActivate(neighbor,newIndices);
430 
431  // return the vector of newly activated indices
432  return newIndices;
433 
434 }
435 
436 void MultiIndexSet::ForciblyActivate(int globalIndex, std::vector<unsigned> &newIndices){
437 
438 
439  if(!IsActive(globalIndex)){
440 
441  // make the node active and add inactive neighbors if necessary, this also updates the edges and enables the loop below
442  Activate(globalIndex);
443  newIndices.push_back(global2active.at(globalIndex));
444 
445  // now, fill in all of the previous neighbors
446  std::set<int>& tempSet = inEdges.at(globalIndex);
447  for(int ind : tempSet)
448  ForciblyActivate(ind,newIndices);
449 
450  }
451 }
452 
453 std::vector<unsigned> MultiIndexSet::ForciblyActivate(std::shared_ptr<MultiIndex> const& multiIndex){
454 
455  assert(limiter->IsFeasible(multiIndex));
456 
457  auto iter = multi2global.find(multiIndex);
458  vector<unsigned int> newIndices;
459 
460  // if we found the multiindex and it is active, there is nothing to do
461  if(iter!=multi2global.end()){
462  ForciblyActivate(iter->second,newIndices);
463  }else{
464  // Add the new index as an active node
465  int newGlobalInd = AddInactive(multiIndex);
466  ForciblyActivate(newGlobalInd,newIndices);
467  }
468 
469  return newIndices;
470 }
471 
473 {
474  Union(rhs);
475  return *this;
476 }
477 
479 {
480  int oldTerms = Size();
481 
482  for(int i = 0; i < rhs.allMultis.size(); ++i) {
483 
484  auto newMulti = rhs.allMultis.at(i);
485  if(limiter->IsFeasible(newMulti)){
486  if(rhs.global2active[i]<0){
487  AddInactive(newMulti);
488  }else{
489  AddActive(newMulti);
490  }
491  }
492  }
493 
494  return Size() - oldTerms;
495 }
496 
497 MultiIndexSet& MultiIndexSet::operator+=(std::shared_ptr<MultiIndex> const& rhs)
498 {
499  AddActive(rhs);
500  return *this;
501 }
502 
503 
504 void MultiIndexSet::ToHDF5(std::string filename, std::string dsetName) const
505 {
507  ToHDF5(fout, dsetName);
508 }
509 
510 
511 void MultiIndexSet::ToHDF5(muq::Utilities::H5Object &group, std::string dsetName) const
512 {
513 
514  unsigned int numTerms = Size();
515  unsigned int dim = GetMultiLength();
516 
517  // Create a dataset
518  auto dset = group.CreateDataset<int>(dsetName, numTerms, dim);
519 
520  // Store each multiindex as a row in the dataset
521  for(unsigned int i=0; i<numTerms; ++i)
522  dset.row(i) = this->IndexToMulti(i)->GetVector();
523 }
524 
525 
526 std::shared_ptr<MultiIndexSet> MultiIndexSet::FromHDF5(std::string filename, std::string dsetName)
527 {
529  return MultiIndexSet::FromHDF5(fin[dsetName]);
530 }
531 
532 std::shared_ptr<MultiIndexSet> MultiIndexSet::FromHDF5(muq::Utilities::H5Object &dset)
533 {
534  unsigned int numTerms = dset.rows();
535  unsigned int dim = dset.cols();
536 
537  // Create an empty set
538  auto output = std::make_shared<MultiIndexSet>(dim);
539 
540  // Add all the terms from the HDF5 file
541  for(unsigned int i=0; i<numTerms; ++i){
542  auto multi = std::make_shared<MultiIndex>(dset.row(i));
543  output->AddActive(multi);
544  }
545 
546  return output;
547 }
H5Object & CreateDataset(std::string const &setName, unsigned int rows, unsigned int cols=0)
Definition: H5Object.h:145
BlockDataset row(unsigned row) const
Definition: H5Object.cpp:183
unsigned cols() const
Definition: H5Object.cpp:234
unsigned rows() const
Definition: H5Object.cpp:225
A class for holding, sorting, and adapting sets of multiindices.
Definition: MultiIndexSet.h:65
std::vector< std::shared_ptr< MultiIndex > > allMultis
virtual bool IsActive(std::shared_ptr< MultiIndex > const &multiIndex) const
Return true if the multiIndex is active.
virtual bool IsExpandable(unsigned int activeIndex) const
Return true if one of the forward neighbors of index is admissible but not active.
virtual MultiIndexSet & operator+=(const MultiIndexSet &rhs)
Add another set of multiindices to this one.
virtual std::vector< unsigned > Expand(unsigned int activeIndex)
virtual unsigned int Size() const
std::shared_ptr< MultiIndexLimiter > limiter
static std::shared_ptr< MultiIndexSet > FromHDF5(std::string filename, std::string dsetName="/multiiindices")
Loads a multiindex set from an HDF5 file.
static std::shared_ptr< MultiIndexSet > CloneExisting(std::shared_ptr< MultiIndexSet > const &original)
NOTE: does not perform a deep copy of the multiindices themselves, only pointers to the multiindices.
virtual int Union(const MultiIndexSet &rhs)
Add all terms in rhs to this instance.
virtual unsigned int NumActiveForward(unsigned int activeInd) const
Returns the number of active forward neighbors.
virtual void SetLimiter(std::shared_ptr< MultiIndexLimiter > const &limiterIn)
virtual unsigned int NumForward(unsigned int activeInd) const
Returns the number of forward neighbors (active or inactive)
std::vector< std::set< int > > inEdges
virtual std::vector< unsigned int > GetStrictFrontier() const
virtual std::vector< unsigned int > GetFrontier() const
virtual unsigned int GetMultiLength() const
void AddBackwardNeighbors(unsigned int globalIndex, bool addInactive)
std::vector< std::set< int > > outEdges
std::map< std::shared_ptr< MultiIndex >, unsigned int, MultiPtrComp > multi2global
std::vector< int > global2active
virtual std::vector< unsigned > ForciblyActivate(std::shared_ptr< MultiIndex > const &multiIndex)
virtual int MultiToIndex(std::shared_ptr< MultiIndex > const &input) const
virtual void Activate(std::shared_ptr< MultiIndex > const &multiIndex)
void ToHDF5(std::string filename, std::string dsetName="/multiindices") const
Saves the multiindex set to a group in an HDF5 file.
int AddInactive(std::shared_ptr< MultiIndex > const &newNode)
int AddMulti(std::shared_ptr< MultiIndex > const &newMulti)
void AddForwardNeighbors(unsigned int globalIndex, bool addInactive)
virtual bool IsAdmissible(std::shared_ptr< MultiIndex > const &multiIndex) const
Determines whether the input multiIndex is currently admissible.
virtual std::vector< unsigned > ForciblyExpand(unsigned int const activeIndex)
virtual int AddActive(std::shared_ptr< MultiIndex > const &newNode)
virtual std::shared_ptr< MultiIndex > const & IndexToMulti(unsigned activeIndex) const
virtual std::vector< std::shared_ptr< MultiIndex > > GetAdmissibleForwardNeighbors(unsigned int activeIndex)
virtual std::vector< unsigned int > GetBackwardNeighbors(unsigned int activeIndex) const
std::vector< unsigned > active2global
std::shared_ptr< MultiIndexSet > operator+=(std::shared_ptr< MultiIndexSet > x, std::shared_ptr< MultiIndexSet > y)
H5Object OpenFile(std::string const &filename)
Open an HDF5 file and return the root object.
Definition: H5Object.cpp:321