Cadabra
Computer algebra system for field theory problems
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Combinatorics.hh
Go to the documentation of this file.
1 /*
2 
3  Cadabra: a field-theory motivated computer algebra system.
4  Copyright (C) 2001-2014 Kasper Peeters <kasper.peeters@phi-sci.com>
5 
6  This program is free software: you can redistribute it and/or
7  modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation, either version 3 of the
9  License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 /*
22  length vector
23  normal combinations: one element, value=total length.
24  normal permutations: n elements, each equal to 1.
25 
26 */
27 
28 #pragma once
29 
30 #include <vector>
31 #include <cassert>
32 #include <algorithm>
33 #include <iomanip>
34 #include <iostream>
35 #include <map>
36 
37 namespace combin {
38 
39 typedef std::vector<unsigned int> range_t;
40 typedef std::vector<range_t> range_vector_t;
41 typedef std::vector<int> weights_t;
42 
43 unsigned long factorial(unsigned int x);
45 long vector_sum(const std::vector<int>&);
47 unsigned long vector_prod(const std::vector<unsigned int>&);
49 unsigned long vector_prod_fact(const std::vector<unsigned int>&);
50 
51 bool operator==(const std::vector<unsigned int>&, const std::vector<unsigned int>&);
52 
54 long hash(const std::vector<unsigned int>&);
55 
56 template<class T>
58  public:
60  combinations_base(const std::vector<T>&);
61  virtual ~combinations_base();
62 
63  void permute(long start=-1, long end=-1);
64  virtual void clear();
65  virtual void clear_results();
66  unsigned int sum_of_sublengths() const;
67  void set_unit_sublengths();
68  unsigned int multiplier(const std::vector<T>&) const;
69  unsigned int total_permutations() const; // including the ones not stored
70 
72 
73  unsigned int block_length;
74  std::vector<unsigned int> sublengths;
76  std::vector<T> original;
78  std::vector<weights_t> weights;
79  std::vector<int> max_weights;
80  std::vector<weight_cond> weight_conditions;
81  unsigned int sub_problem_blocksize; // when non-zero, do permutations within
82 
83  protected:
84  virtual void vector_generated(const std::vector<unsigned int>&)=0;
85  virtual bool entry_accepted(unsigned int current) const;
86  std::vector<unsigned int> temparr;
87 
89  std::vector<int> current_weight;
90  private:
91  bool is_allowed_by_weight_constraints(unsigned int i);
92  bool final_weight_constraints_check() const;
93  void update_weights(unsigned int i);
94  void restore_weights(unsigned int i);
95  void nextstep(unsigned int current, unsigned int fromalgehad, unsigned int groupindex,
96  std::vector<bool> algehad);
97 
98 };
99 
100 template<class T>
101 class combinations : public combinations_base<T> {
102  public:
103  typedef typename std::vector<std::vector<T> > permuted_sets_t;
104  typedef typename permuted_sets_t::const_iterator const_iterator;
105 
106  combinations();
107  combinations(const std::vector<T>&);
108  virtual ~combinations();
109 
110  virtual void clear();
111  virtual void clear_results();
112  const std::vector<T>& operator[](unsigned int) const;
113  int ordersign(unsigned int) const;
114  unsigned int size() const;
115  unsigned int multiplier(unsigned int) const;
116 
117  protected:
118  virtual void vector_generated(const std::vector<unsigned int>&);
119 
120  private:
122 };
123 
124 template<class T>
126 
127 template<class T>
128 class symm_helper : public combinations_base<T> {
129  public:
131  virtual void clear();
132 
134  protected:
135  bool first_one;
137  virtual void vector_generated(const std::vector<unsigned int>&);
138 };
139 
140 template<class T>
142  public:
144  virtual void clear();
145 
147  protected:
148  bool first_one;
150  virtual void vector_generated(const std::vector<unsigned int>&);
151 };
152 
153 template<class T>
154 class symmetriser {
155  public:
156  symmetriser();
157  void apply_symmetry(long start=-1, long end=-1);
158 
159  std::vector<T> original;
160  unsigned int block_length;
161  std::vector<unsigned int> permute_blocks; // offset in unit elements! (not in blocks)
162  std::vector<T> value_permute;
164 
165  std::vector<unsigned int> sublengths; // refers to position within permute_blocks
166  range_vector_t input_asym; // as in combinations_base
167  range_vector_t sublengths_scattered; // sublengths, in original, but not connected.
168 
171  range_t values_to_locations(const std::vector<T>& values) const;
172 
173  const std::vector<T>& operator[](unsigned int) const;
174  int signature(unsigned int) const;
175  void set_multiplicity(unsigned int pos, int val);
176  unsigned int size() const;
177  void clear();
179  void collect();
181 
182  friend class symm_helper<T>;
183  friend class symm_val_helper<T>;
184  private:
187  unsigned int current_;
188  std::vector<std::vector<T> > originals;
189  std::vector<int> multiplicity;
190 };
191 
193  const range_vector_t& indv,
194  range_vector_t& target);
195 
196 template<class iterator1, class iterator2>
197 int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, int stepsize=1);
198 
199 template<class iterator1>
200 int ordersign(iterator1 b1, iterator1 e1);
201 
202 template<class T>
203 T fact(T x);
204 
205 template<class T>
206 std::ostream& operator<<(std::ostream& str, const symmetriser<T>& sym);
207 
208 
209 /*
210 I assume PI consists of the integers 1 to N.
211 It can be done with O(N) comparisons and transpositions of integers
212 in the list.
213 
214 sign:= 1;
215 for i from 1 to N do
216  while PI[i] <> i do
217  interchange PI[i] and PI[PI[i]];
218  sign:= -sign
219  od
220 od
221 */
222 
223 template<class iterator1, class iterator2>
224 int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, int stepsize)
225  {
226  int sign=1;
227  std::vector<bool> crossedoff(std::distance(b1,e1),false);
228  while(b1!=e1) {
229  int otherpos=0;
230  iterator2 it=b2;
231  while(it!=e2) {
232  if( (*it)==(*b1) && crossedoff[otherpos]==false) {
233  crossedoff[otherpos]=true;
234  break;
235  }
236  else {
237  if(!crossedoff[otherpos])
238  sign=-sign;
239  }
240  it+=stepsize;
241  ++otherpos;
242  }
243  b1+=stepsize;
244  }
245  return sign;
246  }
247 
248 //template<class iterator1, class iterator2, class comparator>
249 //int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, comparator cmp, int stepsize)
250 // {
251 // int sign=1;
252 // std::vector<bool> crossedoff(std::distance(b1,e1),false);
253 // while(b1!=e1) {
254 // int otherpos=0;
255 // iterator2 it=b2;
256 // while(it!=e2) {
257 // if(cmp((*it), (*b1)) && crossedoff[otherpos]==false) {
258 // crossedoff[otherpos]=true;
259 // break;
260 // }
261 // else {
262 // if(!crossedoff[otherpos])
263 // sign=-sign;
264 // }
265 // it+=stepsize;
266 // ++otherpos;
267 // }
268 // b1+=stepsize;
269 // }
270 // return sign;
271 // }
272 
273 template<class iterator1>
274 int ordersign(iterator1 b1, iterator1 e1)
275  {
276  std::vector<unsigned int> fil;
277  for(int k=0; k<distance(b1,e1); ++k)
278  fil.push_back(k);
279  return ordersign(fil.begin(), fil.end(), b1, e1);
280  }
281 
282 template<class T>
283 T fact(T x)
284  {
285  T ret=1;
286  assert(x>=0);
287  while(x!=0) { ret*=x--; }
288  return ret;
289  }
290 
291 
292 // Implementations
293 
294 template<class T>
296  : block_length(1), multiple_pick(false), sub_problem_blocksize(0)
297  {
298  }
299 
300 template<class T>
302  : block_length(1), original(oa), multiple_pick(false), sub_problem_blocksize(0)
303  {
304  }
305 
306 template<class T>
308  : combinations_base<T>()
309  {
310  }
311 
312 template<class T>
313 combinations<T>::combinations(const std::vector<T>& oa)
314  : combinations_base<T>(oa)
315  {
316  }
317 
318 template<class T>
320  {
321  }
322 
323 template<class T>
325  {
326  }
327 
328 template<class T>
329 void combinations<T>::vector_generated(const std::vector<unsigned int>& toadd)
330  {
331  ++this->vector_generated_called_;
332  if((this->start_==-1 || this->vector_generated_called_ >= this->start_) &&
333  (this->end_==-1 || this->vector_generated_called_ < this->end_)) {
334  std::vector<T> newone(toadd.size()*this->block_length);
335  for(unsigned int i=0; i<toadd.size(); ++i)
336  for(unsigned int bl=0; bl<this->block_length; ++bl)
337  newone[i*this->block_length+bl]=this->original[toadd[i]*this->block_length+bl];
338  storage.push_back(newone);
339  }
340  }
341 
342 template<class T>
343 bool combinations_base<T>::entry_accepted(unsigned int) const
344  {
345  return true;
346  }
347 
348 template<class T>
349 void combinations_base<T>::permute(long start, long end)
350  {
351  start_=start;
352  end_=end;
353  vector_generated_called_=-1;
354 
355  // Initialise weight handling.
356  current_weight.clear();
357  current_weight.resize(weights.size(), 0);
358  for(unsigned int i=0; i<weights.size(); ++i)
359  assert(weights[i].size() == original.size()/block_length);
360  if(weights.size()>0) {
361  if(weight_conditions.size()==0)
362  weight_conditions.resize(weights.size(), weight_equals);
363  else assert(weight_conditions.size()==weights.size());
364  }
365  else assert(weight_conditions.size()==0);
366 
367  // Sublength handling.
368  assert(sublengths.size()!=0);
369  unsigned int len=sum_of_sublengths();
370 
371  // Consistency checks.
372  assert(original.size()%block_length==0);
373  if(!multiple_pick)
374  assert(len*block_length<=original.size());
375 
376  for(unsigned int i=0; i<this->input_asym.size(); ++i)
377  std::sort(this->input_asym[i].begin(), this->input_asym[i].end());
378 
379  temparr=std::vector<unsigned int>(len/* *block_length*/);
380  std::vector<bool> algehad(original.size()/block_length,false);
381  nextstep(0,0,0,algehad);
382  }
383 
384 template<class T>
386  {
387  block_length=1;
388  sublengths.clear();
389  this->input_asym.clear();
390  original.clear();
391  weights.clear();
392  max_weights.clear();
393  weight_conditions.clear();
394  sub_problem_blocksize=0;
395  temparr.clear();
396  current_weight.clear();
397  }
398 
399 template<class T>
401  {
402  temparr.clear();
403  }
404 
405 template<class T>
407  {
408  storage.clear();
410  }
411 
412 template<class T>
414  {
415  storage.clear();
417  }
418 
419 template<class T>
420 const std::vector<T>& combinations<T>::operator[](unsigned int i) const
421  {
422  assert(i<storage.size());
423  return storage[i];
424  }
425 
426 template<class T>
427 unsigned int combinations<T>::size() const
428  {
429  return storage.size();
430  }
431 
432 template<class T>
434  {
435  unsigned int ret=0;
436  for(unsigned int i=0; i<sublengths.size(); ++i)
437  ret+=sublengths[i];
438  return ret;
439  }
440 
441 template<class T>
443  {
444  return vector_generated_called_+1;
445  }
446 
447 template<class T>
449  {
450  sublengths.clear();
451  for(unsigned int i=0; i<original.size()/block_length; ++i)
452  sublengths.push_back(1);
453  }
454 
455 template<class T>
456 int combinations<T>::ordersign(unsigned int num) const
457  {
458  assert(num<storage.size());
459  return combin::ordersign(storage[0].begin(), storage[0].end(),
460  storage[num].begin(), storage[num].end(), this->block_length);
461  }
462 
463 template<class T>
464 unsigned int combinations<T>::multiplier(unsigned int num) const
465  {
466  return combinations_base<T>::multiplier(this->storage[num]);
467  }
468 
469 template<class T>
470 unsigned int combinations_base<T>::multiplier(const std::vector<T>& stor) const
471  {
472  unsigned long numerator=1;
473  for(unsigned int i=0; i<this->input_asym.size(); ++i)
474  numerator*=fact(this->input_asym[i].size());
475 
476  unsigned long denominator=1;
477  for(unsigned int i=0; i<this->input_asym.size(); ++i) {
478  // for each input asym, and for each output asym, count
479  // the number of overlap elements.
480  unsigned int current=0;
481  for(unsigned int k=0; k<this->sublengths.size(); ++k) {
482  if(this->sublengths[k]>1) {
483  unsigned int overlap=0;
484  for(unsigned int slc=0; slc<this->sublengths[k]; ++slc) {
485  for(unsigned int j=0; j<this->input_asym[i].size(); ++j) {
486  unsigned int index=0;
487  while(!(stor[current]==this->original[index]))
488  ++index;
489  if(index==this->input_asym[i][j])
490  ++overlap;
491  }
492  ++current;
493  }
494  if(overlap>0)
495  denominator*=fact(overlap);
496  // FIXME: for each overlap thus found, divide out by a factor
497  // due to the fact that output asym ranges can overlap.
498 // well, that's not right either.
499  }
500  else ++current;
501  }
502  }
503 
504  return numerator/denominator;
505  }
506 
507 template<class T>
509  {
510  if(weights.size()==0) return true;
511  for(unsigned int cn=0; cn<current_weight.size(); ++cn) {
512  if(weight_conditions[cn]==weight_less)
513  if(current_weight[cn]+weights[cn][i] >= max_weights[cn])
514  return false;
515  }
516  return true;
517  }
518 
519 template<class T>
521  {
522  for(unsigned int cn=0; cn<current_weight.size(); ++cn) {
523  switch(weight_conditions[cn]) {
524  case weight_equals:
525  if(current_weight[cn]!=max_weights[cn])
526  return false;
527  break;
528  case weight_less:
529  break;
530  case weight_greater:
531  if(current_weight[cn]<=max_weights[cn])
532  return false;
533  break;
534  }
535  }
536  return true;
537  }
538 
539 template<class T>
541  {
542  if(weights.size()==0) return;
543  for(unsigned int cn=0; cn<current_weight.size(); ++cn)
544  current_weight[cn]+=weights[cn][i];
545  }
546 
547 template<class T>
549  {
550  if(weights.size()==0) return;
551  for(unsigned int cn=0; cn<current_weight.size(); ++cn)
552  current_weight[cn]-=weights[cn][i];
553  }
554 
555 template<class T>
556 void combinations_base<T>::nextstep(unsigned int current, unsigned int lowest_in_group, unsigned int groupindex,
557  std::vector<bool> algehad)
558  {
559  unsigned int grouplen=0;
560  for(unsigned int i=0; i<=groupindex; ++i)
561  grouplen+=sublengths[i];
562  if(current==grouplen) { // group is filled
563  ++groupindex;
564  if(groupindex==sublengths.size()) {
565  if(final_weight_constraints_check())
566  vector_generated(temparr);
567  return;
568  }
569  lowest_in_group=0;
570  }
571 
572  unsigned int starti=0, endi=original.size()/block_length;
573  if(sub_problem_blocksize>0) {
574  starti=current-current%sub_problem_blocksize;
575  endi=starti+sub_problem_blocksize;
576  }
577  for(unsigned int i=starti; i<endi; i++) {
578  if(!algehad[i] || multiple_pick) {
579  bool discard=false;
580  if(is_allowed_by_weight_constraints(i)) {
581  // handle input_asym
582  for(unsigned k=0; k<this->input_asym.size(); ++k) {
583  for(unsigned int kk=0; kk<this->input_asym[k].size(); ++kk) {
584  if(i==this->input_asym[k][kk]) {
585  unsigned int k2=kk;
586  while(k2!=0) {
587  --k2;
588  if(!algehad[this->input_asym[k][k2]]) {
589 // std::cout << "discarding " << std::endl;
590  discard=true;
591  break;
592  }
593  }
594  }
595  }
596  if(discard) break;
597  }
598  }
599  else discard=true;
600  if(!discard)
601  if(i+1>lowest_in_group) {
602  algehad[i]=true;
603  update_weights(i);
604  temparr[current]=i;
605 // for(unsigned bl=0; bl<block_length; ++bl)
606 // temparr[current*block_length+bl]=original[i*block_length+bl];
607  if(entry_accepted(current)) {
608  nextstep(current+1, i, groupindex, algehad);
609  }
610  algehad[i]=false;
611  restore_weights(i);
612  }
613  }
614  }
615  }
616 
617 template<class T>
619  : block_length(1), permutation_sign(1), sh_(*this), svh_(*this)
620  {
621  }
622 
623 template<class T>
625  {
626  original.clear();
627  block_length=1;
628  permute_blocks.clear();
629  value_permute.clear();
630  permutation_sign=1;
631  sublengths.clear();
632  input_asym.clear();
633  sublengths_scattered.clear();
634  originals.clear();
635  multiplicity.clear();
636  }
637 
638 template<class T>
640  {
641  std::cout << "collecting" << std::endl;
642  // Fill the hash map: entries which are equal have to sit in the same
643  // bin, but there may be other entries in that bin which still have to
644  // be separated.
645  std::multimap<long, unsigned int> hashmap;
646  for(unsigned int i=0; i<originals.size(); ++i)
647  hashmap.insert(std::pair<long, unsigned int>(hash(originals[i]), i));
648 
649  // Collect equal vectors.
650  std::multimap<long, unsigned int>::iterator it=hashmap.begin(), thisbin1, thisbin2, tmpit;
651  while(it!=hashmap.end()) {
652  long current_hash=it->first;
653  thisbin1=it;
654  while(thisbin1!=hashmap.end() && thisbin1->first==current_hash) {
655  thisbin2=thisbin1;
656  ++thisbin2;
657  while(thisbin2!=hashmap.end() && thisbin2->first==current_hash) {
658  if(originals[(*thisbin1).second]==originals[(*thisbin2).second]) {
659  multiplicity[(*thisbin1).second]+=multiplicity[(*thisbin2).second];
660  multiplicity[(*thisbin2).second]=0;
661  tmpit=thisbin2;
662  ++tmpit;
663  hashmap.erase(thisbin2);
664  thisbin2=tmpit;
665  }
666  else ++thisbin2;
667  }
668  ++thisbin1;
669  }
670  it=thisbin1;
671  }
672 
673  remove_multiplicity_zero();
674  }
675 
676 template<class T>
678  {
679  std::vector<std::vector<T> > new_originals;
680  std::vector<int> new_multiplicity;
681  for(unsigned int k=0; k<originals.size(); ++k) {
682  if(multiplicity[k]!=0) {
683  new_originals.push_back(originals[k]);
684  new_multiplicity.push_back(multiplicity[k]);
685  }
686  }
687  originals=new_originals;
688  multiplicity=new_multiplicity;
689  }
690 
691 
692 template<class T>
693 void symmetriser<T>::apply_symmetry(long start, long end)
694  {
695  unsigned int current_length=originals.size();
696  if(current_length==0) {
697  originals.push_back(original);
698  multiplicity.push_back(1);
699  current_length=1;
700  }
701 
702  // Some options are mutually exclusive.
703  assert(permute_blocks.size()>0 || value_permute.size()>0);
704  assert(sublengths.size()==0 || sublengths_scattered.size()==0);
705 
706  if(permute_blocks.size()==0) { // permute by value
707  assert(value_permute.size()!=0);
708 
709  if(input_asym.size()==0 && sublengths_scattered.size()==0) {
710  // When permuting by value, we can do the permutation once,
711  // and then figure out (see vector_generated of symm_val_helper),
712  // for each permutation which is already stored in the symmetriser,
713  // how the objects are moved.
714 
715  current_=current_length;
716  svh_.clear();
717  svh_.original=value_permute;
718  svh_.input_asym.clear();
719  svh_.sublengths=sublengths;
720  svh_.current_multiplicity=combin::vector_prod_fact(sublengths);
721  if(svh_.sublengths.size()==0)
722  svh_.set_unit_sublengths();
723 
724  svh_.permute(start, end);
725  // Since we do not divide by the number of permutations, we need
726  // to adjust the multiplicity of all the originals.
727  // for(unsigned int i=0; i<current_; ++i)
728 // multiplicity[i] *= svh_.current_multiplicity;
729  }
730  else {
731  // However, when there is input_asym or sublength_scattered
732  // are present, we cannot just do the permutation on the
733  // values and then put them into all existing sets, since the
734  // overlap of input_asym with the objects to be permuted will
735  // be different for every set. Therefore, we have to apply
736  // the permutation algorithm separately to each and every set
737  // which is already stored in the symmetriser. We convert
738  // the problem to a permute-by-location problem.
739 
740  for(unsigned int i=0; i<current_length; ++i) {
741  current_=i;
742  sh_.clear();
743  assert(sublengths.size()==0); // not yet implemented
744  std::vector<unsigned int> my_permute_blocks;
745 
746  // Determine the location of the values.
747  for(unsigned int k=0; k<value_permute.size(); ++k) {
748  for(unsigned int m=0; m<originals[i].size(); ++m) {
749  if(originals[i][m]==value_permute[k]) {
750  my_permute_blocks.push_back(m); // FIXME: non-unit block length?
751  break;
752  }
753  }
754  }
755 
756 // std::cout << "handling sublengths" << std::endl;
757  if(sublengths_scattered.size()>0) {
758  // Re-order my_permute_blocks in such a way that the objects which sit
759  // in one sublength_scattered range are consecutive. This does not make
760  // any difference for the sign.
761  sh_.sublengths.clear();
762  std::vector<unsigned int> reordered_permute_blocks;
763  for(unsigned int m=0; m<sublengths_scattered.size(); ++m) {
764  int overlap=0;
765  for(unsigned int mm=0; mm<sublengths_scattered[m].size(); ++mm) {
766 // std::cout << "trying to find " << sublengths_scattered[m][mm] << " " << std::flush;
767  std::vector<unsigned int>::iterator it=my_permute_blocks.begin();
768  while(it!=my_permute_blocks.end()) {
769  if((*it)==sublengths_scattered[m][mm]) {
770 // std::cout << " found " << std::endl;
771  reordered_permute_blocks.push_back(*it);
772  my_permute_blocks.erase(it);
773  ++overlap;
774  break;
775  }
776  ++it;
777  }
778 // std::cout << std::endl;
779  }
780  if(overlap>0)
781  sh_.sublengths.push_back(overlap);
782  }
783  std::vector<unsigned int>::iterator it=my_permute_blocks.begin();
784  while(it!=my_permute_blocks.end()) {
785  reordered_permute_blocks.push_back(*it);
786 // std::cout << "adding one" << std::endl;
787  sh_.sublengths.push_back(1);
788  ++it;
789  }
790  my_permute_blocks=reordered_permute_blocks;
791 // std::cout << "handled sublengths" << std::endl;
792  }
793 
794  // Put to-be-permuted data in originals.
795  for(unsigned int k=0; k<my_permute_blocks.size(); ++k) {
796  for(unsigned int kk=0; kk<block_length; ++kk) {
797  sh_.original.push_back(originals[i][my_permute_blocks[k]+kk]);
798  }
799  }
800 
801  combin::range_vector_t subprob_input_asym;
802  sh_.current_multiplicity=1;
803  if(input_asym.size()>0) {
804  // Make a proper input_asym which refers to object locations
805  // in the permute blocks array, rather than in the original
806  // array.
807  for(unsigned int k=0; k<input_asym.size(); ++k) {
808  range_t newrange;
809  for(unsigned int m=0; m<input_asym[k].size(); ++m) {
810  // search in my_permute_blocks
811  for(unsigned int kk=0; kk<my_permute_blocks.size(); ++kk)
812  if(my_permute_blocks[kk]==input_asym[k][m]) {
813  newrange.push_back(kk);
814  break;
815  }
816  }
817  if(newrange.size()>1) {
818  subprob_input_asym.push_back(newrange);
819  sh_.current_multiplicity*=fact(newrange.size());
820  }
821  }
822  }
823  if(sh_.sublengths.size()==0)
824  sh_.set_unit_sublengths();
825  sh_.current_multiplicity*=combin::vector_prod_fact(sh_.sublengths);
826 
827  // debugging
828 // std::cout << "my_permute_blocks: ";
829 // for(unsigned int ii=0; ii<my_permute_blocks.size(); ++ii)
830 // std::cout << my_permute_blocks[ii] << " ";
831 // std::cout << std::endl;
832 // std::cout << "sublengths: ";
833 // for(unsigned int ii=0; ii<sh_.sublengths.size(); ++ii)
834 // std::cout << sh_.sublengths[ii] << " ";
835 // std::cout << std::endl;
836 
837  // Debugging output:
838 // std::cout << sh_.current_multiplicity << " asym: ";
839 // if(subprob_input_asym.size()>0) {
840 // for(unsigned int k=0; k<subprob_input_asym[0].size(); ++k)
841 // std::cout << subprob_input_asym[0][k] << " ";
842 // std::cout << std::endl;
843 // std::cout << subprob_input_asym.size() << std::endl;
844 // }
845 // else std::cout << "no asym" << std::endl;
846 
847  permute_blocks=my_permute_blocks;
848  sh_.block_length=block_length;
849  sh_.input_asym=subprob_input_asym;
850  sh_.permute(start, end);
851 
852  // Since we do not divide by the number of permutations, we need
853  // to adjust the multiplicity of the original.
854  multiplicity[i]*=sh_.current_multiplicity;
855  permute_blocks.clear(); // restore just in case
856 // for(unsigned int m=0; m<originals.size(); ++m) {
857 // for(unsigned int mm=0; mm<originals[m].size(); ++mm)
858 // std::cout << originals[m][mm] << " ";
859 // std::cout << std::endl;
860 // }
861 // break;
862  }
863  }
864  }
865  else { // permute by location
866  assert(value_permute.size()==0);
867  assert(permute_blocks.size()>0);
868  // When permuting by location, we have to apply the permutation
869  // algorithm separately to each and every permutation which is
870  // already stored in the symmetriser.
871  for(unsigned int i=0; i<current_length; ++i) {
872  current_=i;
873  sh_.clear();
874  for(unsigned int k=0; k<permute_blocks.size(); ++k) {
875  for(unsigned int kk=0; kk<block_length; ++kk) {
876  sh_.original.push_back(originals[i][permute_blocks[k]+kk]);
877  }
878 // sh_.sublengths.push_back(1);
879  }
880  assert(sublengths.size()==0); // not yet implemented
881  // sh_.sublengths=sublengths;
882  if(sh_.sublengths.size()==0)
883  sh_.set_unit_sublengths();
884  sh_.block_length=block_length;
885  sh_.input_asym=input_asym;
886  sh_.permute(start, end);
887  }
888  }
889 
890  if(start!=-1) { // if start is not the first, have to erase the first
891  originals.erase(originals.begin());
892  multiplicity.erase(multiplicity.begin());
893  }
894  }
895 
896 template<class T>
897 const std::vector<T>& symmetriser<T>::operator[](unsigned int i) const
898  {
899  assert(i<originals.size());
900  return originals[i];
901  }
902 
903 template<class T>
904 unsigned int symmetriser<T>::size() const
905  {
906  return originals.size();
907  }
908 
909 template<class T>
910 range_t symmetriser<T>::values_to_locations(const std::vector<T>& values) const
911  {
912  range_t ret;
913  for(unsigned int i=0; i<values.size(); ++i) {
914 // std::cout << "finding " << values[i] << std::endl;
915  for(unsigned int j=0; j<value_permute.size(); ++j) {
916 // std::cout << value_permute[j] << " ";
917  if(value_permute[i]==value_permute[j]) {
918 // std::cout << "found" << std::endl;
919  ret.push_back(j);
920  break;
921  }
922 // std::cout << std::endl;
923  }
924  }
925  return ret;
926  }
927 
928 template<class T>
930  : current_multiplicity(1), first_one(true), owner_(tt)
931  {
932  }
933 
934 template<class T>
936  {
937  first_one=true;
939  }
940 
941 template<class T>
942 void symm_val_helper<T>::vector_generated(const std::vector<unsigned int>& vec)
943  {
944  ++this->vector_generated_called_;
945  if(first_one) {
946  first_one=false;
947  }
948  else {
949  if((this->start_==-1 || this->vector_generated_called_ >= this->start_) &&
950  (this->end_==-1 || this->vector_generated_called_ < this->end_)) {
951 
952  // Since we permuted by value, we can do this permutation in one
953  // shot on all previously generated sets.
954  for(unsigned int i=0; i<owner_.current_; ++i) {
955 // owner_.multiplicity[i] *= current_multiplicity;
956  owner_.originals.push_back(owner_.originals[i]);
957 
958  // Take care of the multiplicity & sign.
959  int multiplicity=owner_.multiplicity[i] * current_multiplicity;
960  if(owner_.permutation_sign==-1)
961  multiplicity*=ordersign(vec.begin(), vec.end());
962  owner_.multiplicity.push_back(multiplicity); //sign==1?true:false);
963 
964  // We now have to find the permuted objects in the larger
965  // "original" set, and re-order these appropriately.
966  unsigned int loc=owner_.originals.size()-1;
967  for(unsigned int j=0; j<vec.size(); ++j) {
968  for(unsigned int k=0; k<owner_.originals[i].size(); ++k) {
969  if(owner_.originals[i][k]==this->original[j]) {
970  owner_.originals[loc][k]=this->original[vec[j]];
971  break;
972  }
973  }
974  }
975  }
976  }
977  }
978  }
979 
980 template<class T>
982  : current_multiplicity(1), first_one(true), owner_(tt)
983  {
984  }
985 
986 template<class T>
988  {
989  first_one=true;
991  }
992 
993 template<class T>
994 int symmetriser<T>::signature(unsigned int i) const
995  {
996  assert(i<multiplicity.size());
997  return multiplicity[i]; //?1:-1;
998  }
999 
1000 template<class T>
1001 void symmetriser<T>::set_multiplicity(unsigned int i, int val)
1002  {
1003  assert(i<multiplicity.size());
1004  multiplicity[i]=val;
1005  }
1006 
1007 template<class T>
1008 void symm_helper<T>::vector_generated(const std::vector<unsigned int>& vec)
1009  {
1010  ++this->vector_generated_called_;
1011  if(first_one) {
1012  first_one=false;
1013  }
1014  else {
1015  if((this->start_==-1 || this->vector_generated_called_ >= this->start_) &&
1016  (this->end_==-1 || this->vector_generated_called_ < this->end_)) {
1017 
1018 // std::cout << "produced ";
1019 // for(unsigned int m=0; m<vec.size(); ++m)
1020  // std::cout << vec[m] << " ";
1021 // std::cout << std::endl;
1022 
1023 // owner_.multiplicity[owner_.current_] *= current_multiplicity;
1024  owner_.originals.push_back(owner_.originals[owner_.current_]);
1025  unsigned int siz=owner_.originals.size()-1;
1026 
1027  // Take care of the permutation sign.
1028  int multiplicity=owner_.multiplicity[owner_.current_] * current_multiplicity;
1029  if(owner_.permutation_sign==-1)
1030  multiplicity*=ordersign(vec.begin(), vec.end());
1031  owner_.multiplicity.push_back(multiplicity);
1032 
1033  for(unsigned int k=0; k<owner_.permute_blocks.size(); ++k) {
1034  for(unsigned int kk=0; kk<owner_.block_length; ++kk) {
1035  assert(owner_.permute_blocks[k]+kk<owner_.originals[0].size());
1036  owner_.originals[siz][owner_.permute_blocks[k]+kk]=
1037  owner_.originals[owner_.current_][owner_.permute_blocks[vec[k]]+kk];
1038  }
1039  }
1040  }
1041  }
1042  }
1043 
1044 template<class T>
1045 std::ostream& operator<<(std::ostream& str, const symmetriser<T>& sym)
1046  {
1047  for(unsigned int i=0; i<sym.size(); ++i) {
1048  for(unsigned int j=0; j<sym[i].size(); ++j) {
1049  str << sym[i][j] << " ";
1050  }
1051  str << " ";
1052  str.setf(std::ios::right, std::ios::adjustfield);
1053  str << std::setw(2) << sym.signature(i) << std::endl;
1054  }
1055  return str;
1056  }
1057 
1058 }
1059 
1060 
1061 
void nextstep(unsigned int current, unsigned int fromalgehad, unsigned int groupindex, std::vector< bool > algehad)
Definition: Combinatorics.hh:556
virtual void clear()
Definition: Combinatorics.hh:406
const std::vector< T > & operator[](unsigned int) const
Definition: Combinatorics.hh:897
virtual void vector_generated(const std::vector< unsigned int > &)
Definition: Combinatorics.hh:329
virtual ~combinations_base()
Definition: Combinatorics.hh:319
const std::vector< T > & operator[](unsigned int) const
Definition: Combinatorics.hh:420
long vector_generated_called_
Definition: Combinatorics.hh:88
range_vector_t sublengths_scattered
Definition: Combinatorics.hh:167
std::vector< std::vector< T > > permuted_sets_t
Definition: Combinatorics.hh:103
std::vector< weight_cond > weight_conditions
Definition: Combinatorics.hh:80
bool first_one
Definition: Combinatorics.hh:135
virtual void clear_results()
Definition: Combinatorics.hh:400
Definition: Combinatorics.hh:141
virtual bool entry_accepted(unsigned int current) const
Definition: Combinatorics.hh:343
virtual void vector_generated(const std::vector< unsigned int > &)
Definition: Combinatorics.hh:1008
Definition: Combinatorics.hh:71
Definition: Combinatorics.hh:125
std::vector< int > current_weight
Definition: Combinatorics.hh:89
int permutation_sign
Definition: Combinatorics.hh:163
symmetriser< T > & owner_
Definition: Combinatorics.hh:149
range_vector_t input_asym
Definition: Combinatorics.hh:75
permuted_sets_t::const_iterator const_iterator
Definition: Combinatorics.hh:104
unsigned long factorial(unsigned int x)
Definition: Combinatorics.cc:23
std::vector< unsigned int > sublengths
Definition: Combinatorics.hh:165
virtual void clear()
Definition: Combinatorics.hh:385
unsigned int block_length
Definition: Combinatorics.hh:160
Definition: Combinatorics.hh:128
weight_cond
Definition: Combinatorics.hh:71
std::vector< unsigned int > permute_blocks
Definition: Combinatorics.hh:161
int ordersign(unsigned int) const
Definition: Combinatorics.hh:456
std::vector< unsigned int > range_t
Definition: Combinatorics.hh:39
bool multiple_pick
Definition: Combinatorics.hh:77
symm_val_helper(symmetriser< T > &)
Definition: Combinatorics.hh:929
void permute(long start=-1, long end=-1)
Definition: Combinatorics.hh:349
Definition: Combinatorics.hh:71
unsigned int size() const
Definition: Combinatorics.hh:427
std::vector< std::vector< T > > originals
Definition: Combinatorics.hh:188
std::vector< T > value_permute
Definition: Combinatorics.hh:162
long vector_sum(const std::vector< int > &)
sum of elements
Definition: Combinatorics.cc:54
int current_multiplicity
Definition: Combinatorics.hh:133
std::vector< weights_t > weights
Definition: Combinatorics.hh:78
std::vector< unsigned int > sublengths
Definition: Combinatorics.hh:74
bool final_weight_constraints_check() const
Definition: Combinatorics.hh:520
void remove_multiplicity_zero()
Definition: Combinatorics.hh:677
symm_helper(symmetriser< T > &)
Definition: Combinatorics.hh:981
long hash(const std::vector< unsigned int > &)
compute a hash value for a vector of unsigned ints
Definition: Combinatorics.cc:88
virtual void clear()
Definition: Combinatorics.hh:935
virtual void clear_results()
Definition: Combinatorics.hh:413
long end_
Definition: Combinatorics.hh:88
std::vector< T > original
Definition: Combinatorics.hh:159
symm_helper< T > sh_
Definition: Combinatorics.hh:185
void update_weights(unsigned int i)
Definition: Combinatorics.hh:540
bool operator==(const std::vector< unsigned int > &, const std::vector< unsigned int > &)
Definition: Combinatorics.cc:78
unsigned int multiplier(const std::vector< T > &) const
Definition: Combinatorics.hh:470
unsigned long vector_prod_fact(const std::vector< unsigned int > &)
product of factorials of elements
Definition: Combinatorics.cc:70
unsigned int current_
Definition: Combinatorics.hh:187
symm_val_helper< T > svh_
Definition: Combinatorics.hh:186
T fact(T x)
Definition: Combinatorics.hh:283
permuted_sets_t storage
Definition: Combinatorics.hh:121
Definition: Combinatorics.hh:57
int k
Definition: passing.cc:4
int determine_intersection_ranges(const range_vector_t &prod, const range_vector_t &indv, range_vector_t &target)
Definition: Combinatorics.cc:30
combinations_base()
Definition: Combinatorics.hh:295
virtual void vector_generated(const std::vector< unsigned int > &)
Definition: Combinatorics.hh:942
void apply_symmetry(long start=-1, long end=-1)
Definition: Combinatorics.hh:693
symmetriser()
Definition: Combinatorics.hh:618
void collect()
Collect equal entries, and adjust the multiplier field accordingly.
Definition: Combinatorics.hh:639
std::vector< T > original
Definition: Combinatorics.hh:76
unsigned int sub_problem_blocksize
Definition: Combinatorics.hh:81
unsigned int size() const
Definition: Combinatorics.hh:904
bool first_one
Definition: Combinatorics.hh:148
void set_unit_sublengths()
Definition: Combinatorics.hh:448
unsigned int sum_of_sublengths() const
Definition: Combinatorics.hh:433
void set_multiplicity(unsigned int pos, int val)
Definition: Combinatorics.hh:1001
long start_
Definition: Combinatorics.hh:88
int current_multiplicity
Definition: Combinatorics.hh:146
int signature(unsigned int) const
Definition: Combinatorics.hh:994
std::vector< int > max_weights
Definition: Combinatorics.hh:79
combinations()
Definition: Combinatorics.hh:307
unsigned int block_length
Definition: Combinatorics.hh:73
std::vector< unsigned int > temparr
Definition: Combinatorics.hh:86
Definition: Combinatorics.hh:101
std::vector< range_t > range_vector_t
Definition: Combinatorics.hh:40
Definition: Combinatorics.hh:71
bool is_allowed_by_weight_constraints(unsigned int i)
Definition: Combinatorics.hh:508
std::vector< int > weights_t
Definition: Combinatorics.hh:41
unsigned long vector_prod(const std::vector< unsigned int > &)
product of elements
Definition: Combinatorics.cc:62
virtual ~combinations()
Definition: Combinatorics.hh:324
void restore_weights(unsigned int i)
Definition: Combinatorics.hh:548
symmetriser< T > & owner_
Definition: Combinatorics.hh:136
void clear()
Definition: Combinatorics.hh:624
unsigned int total_permutations() const
Definition: Combinatorics.hh:442
range_t values_to_locations(const std::vector< T > &values) const
Convert vectors of values to vectors of locations in the original (mainly useful to create input_asym...
Definition: Combinatorics.hh:910
unsigned int multiplier(unsigned int) const
Definition: Combinatorics.hh:464
virtual void vector_generated(const std::vector< unsigned int > &)=0
int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, int stepsize=1)
Definition: Combinatorics.hh:224
virtual void clear()
Definition: Combinatorics.hh:987
std::vector< int > multiplicity
Definition: Combinatorics.hh:189
range_vector_t input_asym
Definition: Combinatorics.hh:166