SundanceCombinatorialUtils.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                             Sundance
00005 //                 Copyright 2011 Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Kevin Long (kevin.long@ttu.edu)
00038 // 
00039 
00040 /* @HEADER@ */
00041 
00042 
00043 #include "SundanceCombinatorialUtils.hpp"
00044 #include "SundanceIntVec.hpp"
00045 #include "PlayaExceptions.hpp"
00046 #include "PlayaTabs.hpp"
00047 #include "SundanceOut.hpp"
00048 #include <algorithm>
00049 #include <iterator>
00050 #include <iostream>
00051 
00052 
00053 namespace Sundance
00054 {
00055 using namespace Teuchos;
00056 using std::endl;
00057 
00058 Array<Array<int> > partitionInteger(int n)
00059 {
00060   typedef Array<int> Aint;
00061   typedef Array<Array<int> > AAint;
00062   static Array<Array<Array<int> > > rtn =
00063     tuple<AAint>(
00064       tuple<Aint>(tuple(1)), 
00065       tuple<Aint>(tuple(2), tuple(1, 1)),
00066       tuple<Aint>(
00067         tuple(3), 
00068         tuple(2, 1), 
00069         tuple(1, 1, 1)),
00070       tuple<Aint>(
00071         tuple(4), 
00072         tuple(3, 1), 
00073         tuple(2, 2),
00074         tuple(2, 1, 1), 
00075         tuple(1,1,1,1)),
00076       tuple<Aint>(
00077         tuple(5), 
00078         tuple(4, 1), 
00079         tuple(3, 2), 
00080         tuple(3, 1, 1), 
00081         tuple(2, 2, 1), 
00082         tuple(2, 1, 1, 1), 
00083         tuple(1, 1, 1, 1, 1)
00084         ));
00085   TEUCHOS_TEST_FOR_EXCEPTION(n<1 || n>5, std::runtime_error, 
00086     "case n=" << n << " not implemented in partitionInteger()");
00087   return rtn[n-1];
00088 }
00089 
00090 
00091 bool nextNum(Array<int>& digits, const Array<int>& radix)
00092 {
00093   /* See Knuth TAOCP vol 4 fascicle 2, algorithm M */
00094   int n = digits.size();
00095   int j = n-1;
00096   while(j >= 0)
00097   {
00098     if (digits[j]==(radix[j]-1)) 
00099     {
00100       digits[j] = 0;
00101       j--;
00102     }
00103     else
00104     {
00105       digits[j]++;
00106       return true;
00107     }
00108   }
00109   return false;
00110 }
00111 
00112 void weightedPartitions(int n, const Array<int>& w, 
00113   Array<Array<int> >& parts)
00114 {
00115   int S = w.size();
00116   for (int i=0; i<S; i++) 
00117   {
00118     TEUCHOS_TEST_FOR_EXCEPT(w[i] <= 0);
00119   }
00120 
00121   Array<Array<int> > trial(S);
00122   Array<int> radix(S);
00123   for (int i=0; i<S; i++)
00124   {
00125     trial[i].resize(n/w[i]+1);
00126     for (int j=0; j<trial[i].size(); j++)
00127     {
00128       trial[i][j] = j;
00129     }
00130     radix[i] = trial[i].size();
00131   }
00132 
00133   bool workLeft = true;
00134   Array<int> index(S, 0);
00135   while (workLeft)
00136   {
00137     Array<int> vals(S);
00138     int count = 0;
00139     for (int i=0; i<S; i++) 
00140     {
00141       vals[i] = trial[i][index[i]];
00142       count += w[i]*vals[i];
00143     }
00144     if (count==n)
00145     {
00146       parts.append(vals);
00147     }
00148     workLeft = nextNum(index, radix);
00149   }
00150 }
00151 
00152 void weightedOrderedPartitions(const IntVec& v, const Array<int>& w,
00153   Array<Array<IntVec> >& parts)
00154 {
00155   int D = v.size();
00156   int S = w.size();
00157   Array<int> radix(D);
00158 
00159   Array<Array<Array<int> > > nParts(D);
00160   for (int i=0; i<D; i++)
00161   {
00162     weightedPartitions(v[i], w, nParts[i]);
00163     radix[i] = nParts[i].size();
00164     if (radix[i]==0) radix[i] = 1;
00165   }
00166 
00167   bool workLeft = true;
00168   Array<int> index(D, 0);
00169   while (workLeft)
00170   {
00171     Array<IntVec> L(S, D);
00172     for (int i=0; i<D; i++) 
00173     {
00174       for (int j=0; j<S; j++) 
00175       {
00176         if (nParts[i].size()==0) L[i][j] = 0;
00177         else L[j][i] = nParts[i][index[i]][j];
00178       }
00179     }
00180     /* test ordering */
00181     bool accept = true;
00182     for (int i=0; i<S; i++)
00183     {
00184       if (L[i].abs()==0) {accept = false; break;}
00185       if (i>0 && !(L[i-1] < L[i]))  {accept = false; break;}
00186     }
00187     if (accept) 
00188     {
00189       parts.append(L);
00190     }
00191     workLeft = nextNum(index, radix);
00192   }
00193   
00194 }
00195 
00196 
00197 void pSet(const IntVec& lambda, const IntVec& nu, int s,
00198   Array<Array<IntVec> >& K, Array<Array<IntVec> >& L)
00199 {
00200   Array<Array<IntVec> > KParts;
00201   lambda.getPartitions(s, KParts);
00202 
00203   for (int i=0; i<KParts.size(); i++)
00204   {
00205     const Array<IntVec>& kPart = KParts[i];
00206     Array<int> w(s);
00207     for (int j=0; j<s; j++) w[j] = kPart[j].abs();
00208     Array<Array<IntVec> > LParts;
00209     weightedOrderedPartitions(nu, w, LParts);
00210     for (int j=0; j<LParts.size(); j++)
00211     {
00212       K.append(kPart);
00213       L.append(LParts[j]);
00214     }
00215   }
00216 
00217 }
00218 
00219 
00220 
00221 Array<Array<Array<int> > > compositions(int n)
00222 {
00223   Array<Array<Array<int> > > q(n);
00224 
00225   Array<Array<int> > x = partitionInteger(n);
00226 
00227   Array<Array<int> > p;
00228   for (int m=0; m<x.size(); m++)
00229   {
00230     Array<int> tmp;
00231     Array<int> y = x[m];
00232     std::sort(y.begin(), y.end());
00233     tmp.resize(y.size());
00234     std::copy(y.begin(), y.end(), tmp.begin());
00235     p.append(tmp);
00236     while (std::next_permutation(y.begin(), y.end())) 
00237     { 
00238       tmp.resize(y.size());
00239       std::copy(y.begin(), y.end(), tmp.begin());
00240       p.append(tmp);
00241     }
00242   }
00243 
00244   for (int i=0; i<p.size(); i++)
00245   {
00246     q[p[i].size()-1].append(p[i]);
00247   }
00248 
00249   return q;
00250 }
00251 
00252 void restrictedCompositions(int n, int len, Array<Array<int> >& rComps)
00253 {
00254   rComps = nonNegCompositions(n, len);
00255 }
00256 
00257 Array<Array<int> > nonNegCompositions(int n, int J)
00258 {
00259   /* find all partitions */
00260   Array<Array<int> > parts = partitionInteger(n);
00261     
00262   /* find the partitions into J or fewer terms */
00263   Array<Array<int> > jParts;
00264   for (int i=0; i<parts.size(); i++)
00265   {
00266     if (parts[i].size() <= J) jParts.append(parts[i]);
00267   }
00268 
00269   /* Pad with zeros until all remaining partitions have size=J */
00270   for (int i=0; i<jParts.size(); i++)
00271   {
00272     for (int j=jParts[i].size(); j<J; j++)
00273     {
00274       jParts[i].append(0);
00275     }
00276   }
00277 
00278   /* form all permutations */
00279   Array<Array<int> > all;
00280   for (int i=0; i<jParts.size(); i++)
00281   {
00282     Array<int> tmp;
00283     Array<int> y = jParts[i];
00284     std::sort(y.begin(), y.end());
00285     tmp.resize(y.size());
00286     std::copy(y.begin(), y.end(), tmp.begin());
00287     all.append(tmp);
00288     while (std::next_permutation(y.begin(), y.end())) 
00289     { 
00290       tmp.resize(y.size());
00291       std::copy(y.begin(), y.end(), tmp.begin());
00292       all.append(tmp);
00293     }
00294   }
00295 
00296   return all;
00297 }
00298 
00299 
00300   
00301 Set<Pair<MultiSet<int> > >
00302 loadPartitions(int x, int n, 
00303   const MultiSet<int>& left, 
00304   const MultiSet<int>& right)
00305 {
00306   Set<Pair<MultiSet<int> > > rtn;
00307   for (int i=0; i<n; i++)
00308   {
00309     MultiSet<int> L = left;
00310     MultiSet<int> R = right;
00311 
00312     for (int j=0; j<n; j++) 
00313     {
00314       if (j < i) L.put(x);
00315       else R.put(x);
00316     }
00317     rtn.put(Pair<MultiSet<int> >(L, R));
00318     rtn.put(Pair<MultiSet<int> >(R, L));
00319   }
00320   return rtn;
00321 }
00322 
00323 
00324 Set<Pair<MultiSet<int> > >
00325 binaryPartition(const MultiSet<int>& m)
00326 {
00327   Set<Pair<MultiSet<int> > > tmp1;
00328 
00329 
00330   Map<int, int> counts = countMap(m);
00331     
00332   for (Map<int, int>::const_iterator 
00333          i=counts.begin(); i!=counts.end(); i++)
00334   {
00335     int x = i->first;
00336     int n = i->second;
00337     if (tmp1.size()==0)
00338     {
00339       MultiSet<int> L;
00340       MultiSet<int> R;
00341       tmp1 = loadPartitions(x, n, L, R);
00342     }
00343     else
00344     {
00345       Set<Pair<MultiSet<int> > > tmp2;
00346       for (Set<Pair<MultiSet<int> > >::const_iterator
00347              j=tmp1.begin(); j!=tmp1.end(); j++)
00348       {
00349         MultiSet<int> L = j->first();
00350         MultiSet<int> R = j->second();
00351         Set<Pair<MultiSet<int> > > t 
00352           = loadPartitions(x, n, L, R);
00353         tmp2.merge(t);
00354       }
00355       tmp1 = tmp2;
00356     }
00357   }
00358 
00359 #ifdef BLAH
00360   Set<SortedPair<MultiSet<int> > > rtn;
00361   for (Set<Pair<MultiSet<int> > >::const_iterator
00362          j=tmp1.begin(); j!=tmp1.end(); j++)
00363   {
00364     rtn.put(SortedPair<MultiSet<int> >(j->first(), j->second()));
00365   }
00366 #endif
00367 
00368     
00369   return tmp1;
00370 }
00371 
00372 
00373 
00374 Set<MultiSet<MultiSet<int> > >
00375 multisetPartitions(const MultiSet<int>& m)
00376 {
00377   Set<MultiSet<MultiSet<int> > > rtn;
00378   int mSize = m.size();
00379   if (m.size()==0) return rtn;
00380   if (m.size()==1) return makeSet(makeMultiSet(m));
00381   rtn.put(makeMultiSet(m));
00382 
00383   Set<Pair<MultiSet<int> > > 
00384     twoParts = binaryPartition(m);
00385 
00386   for (Set<Pair<MultiSet<int> > >::const_iterator 
00387          i=twoParts.begin(); i!=twoParts.end(); i++)
00388   {
00389     MultiSet<int> L = i->first();
00390     MultiSet<int> R = i->second();
00391     if ((int) L.size() == mSize || (int) R.size() == mSize) continue;
00392     if ((int) L.size() > 0 && (int) R.size() > 0) rtn.put(makeMultiSet(L, R));
00393 
00394     Array<MultiSet<MultiSet<int> > > lParts;
00395     Array<MultiSet<MultiSet<int> > > rParts;
00396     if (L.size() > 0)
00397     {
00398       lParts = multisetPartitions(L).elements();
00399     }
00400     if (R.size() > 0)
00401     {
00402       rParts = multisetPartitions(R).elements();
00403     }
00404     for (int j=0; j<lParts.size(); j++)
00405     {
00406       for (int k=0; k<rParts.size(); k++)
00407       {
00408         const MultiSet<MultiSet<int> >& a = lParts[j];
00409         const MultiSet<MultiSet<int> >& b = rParts[k];
00410         MultiSet<MultiSet<int> > combined;
00411         for (MultiSet<MultiSet<int> >::const_iterator 
00412                x=a.begin(); x!=a.end(); x++)
00413         {
00414           combined.put(*x);
00415         }
00416         for (MultiSet<MultiSet<int> >::const_iterator 
00417                x=b.begin(); x!=b.end(); x++)
00418         {
00419           combined.put(*x);
00420         }
00421         rtn.put(combined);
00422       }
00423     }
00424   }
00425   return rtn;
00426 }
00427 
00428 
00429 Map<int, int> countMap(const MultiSet<int>& m)
00430 {
00431   Map<int, int> rtn;
00432   for (MultiSet<int>::const_iterator i=m.begin(); i!=m.end(); i++)
00433   {
00434     if (rtn.containsKey(*i)) rtn[*i]++;
00435     else rtn.put(*i, 1);
00436   }
00437   return rtn;
00438 }
00439 
00440 
00441 Array<Array<int> > indexCombinations(const Array<int>& s)
00442 {
00443 
00444   Array<int> D(s.size(), 0);
00445   Array<int> C(s.size(), -1);
00446 
00447   int p=1;
00448   for (int k=1; k<=s.size(); k++)
00449   {
00450     D[s.size()-k] = p;
00451     p = p*s[s.size() - k];
00452   }
00453   Array<Array<int> > rtn(p);
00454 
00455   for (int i=0; i<p; i++)
00456   {
00457     for (int j=0; j<s.size(); j++)
00458     {
00459       if ( (i % D[j])==0 )
00460       {
00461         C[j] = (C[j]+1) % s[j];
00462       }
00463     }
00464     rtn[i] = C;
00465   }
00466   return rtn;
00467 }
00468 
00469 
00470 Array<Array<Array<int> > > binnings(const MultiSet<int>& mu, int n)
00471 {
00472   int N = mu.size();
00473   Array<Array<int> > c = compositions(N)[n-1];
00474   Array<Array<Array<int> > > rtn;
00475 
00476   for (int i=0; i<c.size(); i++)
00477   {
00478     Array<Array<Array<int> > > a = indexArrangements(mu, c[i]);
00479     for (int j=0; j<a.size(); j++)
00480     {
00481       rtn.append(a[j]);
00482     }
00483   }
00484   return rtn;
00485 }
00486 
00487 
00488 
00489 Array<Array<Array<int> > > indexArrangements(const MultiSet<int>& mu,
00490   const Array<int> & k) 
00491 {
00492   int nBins = k.size();
00493     
00494   int M = 0;
00495   for (int i=0; i<nBins; i++)
00496   {
00497     M += k[i];
00498   }
00499 
00500   Array<int> I;
00501   for (MultiSet<int>::const_iterator iter=mu.begin(); iter!=mu.end(); iter++)
00502   {
00503     I.append(*iter);
00504   }
00505 
00506   Array<Array<Array<int> > > rtn;
00507     
00508   do
00509   {
00510     Array<Array<int> > bins(nBins);
00511     int count = 0;
00512     for (int i=0; i<nBins; i++)
00513     {
00514       for (int j=0; j<k[i]; j++)
00515       {
00516         bins[i].append(I[count++]);
00517       }
00518     }
00519     rtn.append(bins);
00520   }
00521   while (std::next_permutation(I.begin(), I.end()));
00522   return rtn;
00523     
00524 }
00525 
00526 
00527 Set<MultiSet<int> > multisetSubsets(const MultiSet<int>& x)
00528 {
00529   /* We'll generate the subsets by traversing them in bitwise order.
00530    * For a multiset having N elements, there are up to 2^N subsets each
00531    * of which can be described by a N-bit number with the i-th
00532    * bit indicating whether the i-th element is in the subset. Note that
00533    * with a multiset, repetitions can occur so we need to record the
00534    * results in a Set object to eliminate duplicates. 
00535    */
00536 
00537   /* Make an indexable array of the elements. This will be convenient
00538    * because we'll need to access the i-th element after reading
00539    * the i-th bit. */
00540   Array<int> elements = x.elements();
00541 
00542   /* Compute the maximum number of subsets. This number will be reached
00543    * only in the case of no repetitions. */
00544   int n = elements.size();
00545   int maxNumSubsets = pow2(n);
00546     
00547   Set<MultiSet<int> > rtn;
00548     
00549     
00550   /* Loop over subsets in bitwise order. We start the count at 1 
00551      to avoid including the empty subset */
00552   for (int i=1; i<maxNumSubsets; i++)
00553   {
00554     Array<int> bits = bitsOfAnInteger(i, n);
00555     MultiSet<int> ms;
00556     for (int j=0; j<n; j++) 
00557     {
00558       if (bits[j] == 1) ms.put(elements[j]);
00559     }
00560     rtn.put(ms);
00561   }
00562   return rtn;
00563 }
00564 
00565 
00566 Array<Array<MultiSet<int> > > multisetCompositions(int s,
00567   const MultiSet<int>& x)
00568 {
00569   Set<MultiSet<MultiSet<int> > > parts = multisetPartitions(x);
00570 
00571   Array<Array<MultiSet<int> > > rtn;
00572 
00573   typedef Set<MultiSet<MultiSet<int> > >::const_iterator iter;
00574   for (iter i=parts.begin(); i!=parts.end(); i++)
00575   {
00576     if ((int) i->size()!=s) continue;
00577     Array<MultiSet<int> > y = i->elements();
00578     Array<MultiSet<int> > tmp(y.size());
00579     std::sort(y.begin(), y.end());
00580     std::copy(y.begin(), y.end(), tmp.begin());
00581     rtn.append(tmp);
00582     while (std::next_permutation(y.begin(), y.end())) 
00583     { 
00584       tmp.resize(y.size());
00585       std::copy(y.begin(), y.end(), tmp.begin());
00586       rtn.append(tmp);
00587     }
00588   }
00589   return rtn;
00590 }
00591 
00592 Array<Array<int> > distinctIndexTuples(int m, int n)
00593 {
00594   Array<Array<int> > rtn;
00595   Array<int> cur(m);
00596   for (int i=0; i<m; i++) cur[i] = i;
00597   if (m==1) 
00598   {
00599     for (int i=0; i<n; i++) rtn.append(tuple(i));
00600     return rtn;
00601   }
00602 
00603   while(cur[0] < (n-m)+1)
00604   {
00605     rtn.append(cur);
00606     for (int i=(m-1); i>=0; i--)
00607     {
00608       if (cur[i] < (n-1)) 
00609       {
00610         cur[i]++;
00611         bool overflow = false;
00612         for (int j=i+1; j<m; j++) 
00613         {
00614           cur[j] = cur[j-1]+1;
00615           if (cur[j] >= n) overflow = true;
00616         }
00617         if (overflow) continue;
00618         else break;
00619       }
00620     }
00621   }
00622   return rtn;
00623 }
00624   
00625 Array<int> bitsOfAnInteger(int x, int n)
00626 {
00627   TEUCHOS_TEST_FOR_EXCEPTION(x >= pow2(n), std::logic_error,
00628     "Invalid input to bitsOfAnIteger");
00629                      
00630   Array<int> rtn(n);
00631     
00632   int r = x;
00633   for (int b=n-1; b>=0; b--)
00634   {
00635     rtn[b] = r/pow2(b);
00636     r = r - rtn[b]*pow2(b);
00637   }
00638   return rtn;
00639 }
00640 
00641 
00642 
00643 
00644 
00645 int pow2(int n)
00646 {
00647   static Array<int> p2(1,1);
00648 
00649   if ((int) n >= p2.size())
00650   {
00651     int oldN = p2.size(); 
00652     for (int i=oldN; i<=n; i++) p2.push_back(p2[i-1]*2);
00653   }
00654     
00655   return p2[n];
00656 }
00657 }
00658 
00659 
00660 
00661   
00662 
00663 
00664 
00665 
00666 

Site Contact