1 /** @file expairseq.cpp
3 * GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #ifdef EXPAIRSEQ_USE_HASHTAB
27 #error "!!!!!!!!TODO: expair_needs_further_processing not yet implemented for hashtabs, sorry. A.F."
28 #endif // def EXPAIRSEQ_USE_HASHTAB
37 bool operator()(epp const & lh, epp const & rh) const
39 return (*lh).is_less(*rh);
44 // default constructor, destructor, copy constructor assignment operator and helpers
49 expairseq::expairseq(expairseq const & other)
51 debugmsg("expairseq copy constructor",LOGLEVEL_CONSTRUCT);
55 expairseq const & expairseq::operator=(expairseq const & other)
57 debugmsg("expairseq operator=",LOGLEVEL_ASSIGNMENT);
67 void expairseq::copy(expairseq const & other)
71 overall_coeff=other.overall_coeff;
72 #ifdef EXPAIRSEQ_USE_HASHTAB
74 hashtabsize=other.hashtabsize;
76 hashmask=other.hashmask;
77 hashtab.resize(hashtabsize);
78 epvector::const_iterator osb=other.seq.begin();
79 for (unsigned i=0; i<hashtabsize; ++i) {
81 for (epplist::const_iterator cit=other.hashtab[i].begin();
82 cit!=other.hashtab[i].end(); ++cit) {
83 hashtab[i].push_back(seq.begin()+((*cit)-osb));
89 #endif // def EXPAIRSEQ_USE_HASHTAB
96 expairseq::expairseq(ex const & lh, ex const & rh) : basic(TINFO_EXPAIRSEQ)
98 debugmsg("expairseq constructor from ex,ex",LOGLEVEL_CONSTRUCT);
99 construct_from_2_ex(lh,rh);
100 ASSERT(is_canonical());
103 expairseq::expairseq(exvector const & v) : basic(TINFO_EXPAIRSEQ)
105 debugmsg("expairseq constructor from exvector",LOGLEVEL_CONSTRUCT);
106 construct_from_exvector(v);
107 ASSERT(is_canonical());
111 expairseq::expairseq(epvector const & v, bool do_not_canonicalize) :
112 basic(TINFO_EXPAIRSEQ)
114 debugmsg("expairseq constructor from epvector",LOGLEVEL_CONSTRUCT);
115 if (do_not_canonicalize) {
117 #ifdef EXPAIRSEQ_USE_HASHTAB
118 combine_same_terms(); // to build hashtab
119 #endif // def EXPAIRSEQ_USE_HASHTAB
121 construct_from_epvector(v);
123 ASSERT(is_canonical());
127 expairseq::expairseq(epvector const & v, ex const & oc) :
128 basic(TINFO_EXPAIRSEQ), overall_coeff(oc)
130 debugmsg("expairseq constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
131 construct_from_epvector(v);
132 ASSERT(is_canonical());
135 expairseq::expairseq(epvector * vp, ex const & oc) :
136 basic(TINFO_EXPAIRSEQ), overall_coeff(oc)
138 debugmsg("expairseq constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
140 construct_from_epvector(*vp);
142 ASSERT(is_canonical());
146 // functions overriding virtual functions from bases classes
151 basic * expairseq::duplicate() const
153 debugmsg("expairseq duplicate",LOGLEVEL_DUPLICATE);
154 return new expairseq(*this);
157 bool expairseq::info(unsigned inf) const
159 return basic::info(inf);
162 int expairseq::nops() const
164 if (overall_coeff.is_equal(default_overall_coeff())) {
170 ex expairseq::op(int const i) const
172 if (unsigned(i)<seq.size()) {
173 return recombine_pair_to_ex(seq[i]);
175 ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
176 return overall_coeff;
179 ex & expairseq::let_op(int const i)
181 throw(std::logic_error("let_op not defined for expairseq and derived classes (add,mul,...)"));
184 ex expairseq::eval(int level) const
186 if ((level==1)&&(flags & status_flags::evaluated)) {
190 epvector * vp=evalchildren(level);
195 return (new expairseq(vp,overall_coeff))
196 ->setflag(status_flags::dynallocated |
197 status_flags::evaluated );
200 ex expairseq::evalf(int level) const
202 return thisexpairseq(evalfchildren(level),overall_coeff);
205 ex expairseq::normal(lst &sym_lst, lst &repl_lst, int level) const
207 ex n=thisexpairseq(normalchildren(level),overall_coeff);
208 return n.bp->basic::normal(sym_lst,repl_lst,level);
211 ex expairseq::subs(lst const & ls, lst const & lr) const
213 epvector * vp=subschildren(ls,lr);
217 return thisexpairseq(vp,overall_coeff);
222 int expairseq::compare_same_type(basic const & other) const
224 ASSERT(is_of_type(other, expairseq));
225 expairseq const & o=static_cast<expairseq const &>(const_cast<basic &>(other));
229 // compare number of elements
230 if (seq.size() != o.seq.size()) {
231 return (seq.size()<o.seq.size()) ? -1 : 1;
234 // compare overall_coeff
235 cmpval=overall_coeff.compare(o.overall_coeff);
236 if (cmpval!=0) return cmpval;
238 //if (seq.size()==0) return 0; // empty expairseq's are equal
240 #ifdef EXPAIRSEQ_USE_HASHTAB
241 ASSERT(hashtabsize==o.hashtabsize);
242 if (hashtabsize==0) {
243 #endif // def EXPAIRSEQ_USE_HASHTAB
244 epvector::const_iterator cit1=seq.begin();
245 epvector::const_iterator cit2=o.seq.begin();
246 epvector::const_iterator last1=seq.end();
247 epvector::const_iterator last2=o.seq.end();
249 for (; (cit1!=last1)&&(cit2!=last2); ++cit1, ++cit2) {
250 cmpval=(*cit1).compare(*cit2);
251 if (cmpval!=0) return cmpval;
258 #ifdef EXPAIRSEQ_USE_HASHTAB
261 // compare number of elements in each hashtab entry
262 for (unsigned i=0; i<hashtabsize; ++i) {
263 unsigned cursize=hashtab[i].size();
264 if (cursize != o.hashtab[i].size()) {
265 return (cursize < o.hashtab[i].size()) ? -1 : 1;
269 // compare individual (sorted) hashtab entries
270 for (unsigned i=0; i<hashtabsize; ++i) {
271 unsigned sz=hashtab[i].size();
273 epplist const & eppl1=hashtab[i];
274 epplist const & eppl2=o.hashtab[i];
275 epplist::const_iterator it1=eppl1.begin();
276 epplist::const_iterator it2=eppl2.begin();
277 while (it1!=eppl1.end()) {
278 cmpval=(*(*it1)).compare(*(*it2));
279 if (cmpval!=0) return cmpval;
287 #endif // def EXPAIRSEQ_USE_HASHTAB
290 bool expairseq::is_equal_same_type(basic const & other) const
292 expairseq const & o=dynamic_cast<expairseq const &>(const_cast<basic &>(other));
294 // compare number of elements
295 if (seq.size() != o.seq.size()) return false;
297 // compare overall_coeff
298 if (!overall_coeff.is_equal(o.overall_coeff)) return false;
300 #ifdef EXPAIRSEQ_USE_HASHTAB
301 // compare number of elements in each hashtab entry
302 if (hashtabsize!=o.hashtabsize) {
303 cout << "this:" << endl;
305 cout << "other:" << endl;
306 other.printtree(cout,0);
309 ASSERT(hashtabsize==o.hashtabsize);
311 if (hashtabsize==0) {
312 #endif // def EXPAIRSEQ_USE_HASHTAB
313 epvector::const_iterator cit1=seq.begin();
314 epvector::const_iterator cit2=o.seq.begin();
315 epvector::const_iterator last1=seq.end();
317 while (cit1!=last1) {
318 if (!(*cit1).is_equal(*cit2)) return false;
324 #ifdef EXPAIRSEQ_USE_HASHTAB
327 for (unsigned i=0; i<hashtabsize; ++i) {
328 if (hashtab[i].size() != o.hashtab[i].size()) return false;
331 // compare individual sorted hashtab entries
332 for (unsigned i=0; i<hashtabsize; ++i) {
333 unsigned sz=hashtab[i].size();
335 epplist const & eppl1=hashtab[i];
336 epplist const & eppl2=o.hashtab[i];
337 epplist::const_iterator it1=eppl1.begin();
338 epplist::const_iterator it2=eppl2.begin();
339 while (it1!=eppl1.end()) {
340 if (!(*(*it1)).is_equal(*(*it2))) return false;
348 #endif // def EXPAIRSEQ_USE_HASHTAB
351 unsigned expairseq::return_type(void) const
353 return return_types::noncommutative_composite;
356 unsigned expairseq::calchash(void) const
358 unsigned v=golden_ratio_hash(tinfo());
359 epvector::const_iterator last=seq.end();
360 for (epvector::const_iterator cit=seq.begin(); cit!=last; ++cit) {
361 #ifndef EXPAIRSEQ_USE_HASHTAB
362 v=rotate_left_31(v); // rotation would spoil commutativity
363 #endif // ndef EXPAIRSEQ_USE_HASHTAB
364 v ^= (*cit).rest.gethash();
367 v ^= overall_coeff.gethash();
370 // store calculated hash value only if object is already evaluated
371 if (flags & status_flags::evaluated) {
372 setflag(status_flags::hash_calculated);
379 ex expairseq::expand(unsigned options) const
381 epvector * vp=expandchildren(options);
385 return thisexpairseq(vp,overall_coeff);
389 // new virtual functions which can be overridden by derived classes
394 ex expairseq::thisexpairseq(epvector const & v,ex const & oc) const
396 return expairseq(v,oc);
399 ex expairseq::thisexpairseq(epvector * vp, ex const & oc) const
401 return expairseq(vp,oc);
404 expair expairseq::split_ex_to_pair(ex const & e) const
406 return expair(e,exONE());
409 expair expairseq::combine_ex_with_coeff_to_pair(ex const & e,
412 ASSERT(is_ex_exactly_of_type(c,numeric));
417 expair expairseq::combine_pair_with_coeff_to_pair(expair const & p,
420 ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
421 ASSERT(is_ex_exactly_of_type(c,numeric));
423 return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
426 ex expairseq::recombine_pair_to_ex(expair const & p) const
428 return lst(p.rest,p.coeff);
431 bool expairseq::expair_needs_further_processing(epp it)
436 ex expairseq::default_overall_coeff(void) const
441 void expairseq::combine_overall_coeff(ex const & c)
443 ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
444 ASSERT(is_ex_exactly_of_type(c,numeric));
445 overall_coeff = ex_to_numeric(overall_coeff).add_dyn(ex_to_numeric(c));
448 void expairseq::combine_overall_coeff(ex const & c1, ex const & c2)
450 ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
451 ASSERT(is_ex_exactly_of_type(c1,numeric));
452 ASSERT(is_ex_exactly_of_type(c2,numeric));
453 overall_coeff = ex_to_numeric(overall_coeff).
454 add_dyn(ex_to_numeric(c1).mul(ex_to_numeric(c2)));
457 bool expairseq::can_make_flat(expair const & p) const
464 // non-virtual functions in this class
467 void expairseq::construct_from_2_ex_via_exvector(ex const & lh, ex const & rh)
473 construct_from_exvector(v);
474 #ifdef EXPAIRSEQ_USE_HASHTAB
475 ASSERT((hashtabsize==0)||(hashtabsize>=minhashtabsize));
476 ASSERT(hashtabsize==calc_hashtabsize(seq.size()));
477 #endif // def EXPAIRSEQ_USE_HASHTAB
480 void expairseq::construct_from_2_ex(ex const & lh, ex const & rh)
482 if (lh.bp->tinfo()==tinfo()) {
483 if (rh.bp->tinfo()==tinfo()) {
484 #ifdef EXPAIRSEQ_USE_HASHTAB
485 unsigned totalsize=ex_to_expairseq(lh).seq.size()+
486 ex_to_expairseq(rh).seq.size();
487 if (calc_hashtabsize(totalsize)!=0) {
488 construct_from_2_ex_via_exvector(lh,rh);
490 #endif // def EXPAIRSEQ_USE_HASHTAB
491 construct_from_2_expairseq(ex_to_expairseq(lh),
492 ex_to_expairseq(rh));
493 #ifdef EXPAIRSEQ_USE_HASHTAB
495 #endif // def EXPAIRSEQ_USE_HASHTAB
498 #ifdef EXPAIRSEQ_USE_HASHTAB
499 unsigned totalsize=ex_to_expairseq(lh).seq.size()+1;
500 if (calc_hashtabsize(totalsize)!=0) {
501 construct_from_2_ex_via_exvector(lh,rh);
503 #endif // def EXPAIRSEQ_USE_HASHTAB
504 construct_from_expairseq_ex(ex_to_expairseq(lh),rh);
505 #ifdef EXPAIRSEQ_USE_HASHTAB
507 #endif // def EXPAIRSEQ_USE_HASHTAB
510 } else if (rh.bp->tinfo()==tinfo()) {
511 #ifdef EXPAIRSEQ_USE_HASHTAB
512 unsigned totalsize=ex_to_expairseq(rh).seq.size()+1;
513 if (calc_hashtabsize(totalsize)!=0) {
514 construct_from_2_ex_via_exvector(lh,rh);
516 #endif // def EXPAIRSEQ_USE_HASHTAB
517 construct_from_expairseq_ex(ex_to_expairseq(rh),lh);
518 #ifdef EXPAIRSEQ_USE_HASHTAB
520 #endif // def EXPAIRSEQ_USE_HASHTAB
524 #ifdef EXPAIRSEQ_USE_HASHTAB
525 if (calc_hashtabsize(2)!=0) {
526 construct_from_2_ex_via_exvector(lh,rh);
530 #endif // def EXPAIRSEQ_USE_HASHTAB
532 if (is_ex_exactly_of_type(lh,numeric)) {
533 if (is_ex_exactly_of_type(rh,numeric)) {
534 combine_overall_coeff(lh);
535 combine_overall_coeff(rh);
537 combine_overall_coeff(lh);
538 seq.push_back(split_ex_to_pair(rh));
541 if (is_ex_exactly_of_type(rh,numeric)) {
542 combine_overall_coeff(rh);
543 seq.push_back(split_ex_to_pair(lh));
545 expair p1=split_ex_to_pair(lh);
546 expair p2=split_ex_to_pair(rh);
548 int cmpval=p1.rest.compare(p2.rest);
550 p1.coeff=ex_to_numeric(p1.coeff).add_dyn(ex_to_numeric(p2.coeff));
551 if (!ex_to_numeric(p1.coeff).is_zero()) {
552 // no further processing is necessary, since this
553 // one element will usually be recombined in eval()
570 void expairseq::construct_from_2_expairseq(expairseq const & s1,
571 expairseq const & s2)
573 combine_overall_coeff(s1.overall_coeff);
574 combine_overall_coeff(s2.overall_coeff);
576 epvector::const_iterator first1=s1.seq.begin();
577 epvector::const_iterator last1=s1.seq.end();
578 epvector::const_iterator first2=s2.seq.begin();
579 epvector::const_iterator last2=s2.seq.end();
581 seq.reserve(s1.seq.size()+s2.seq.size());
583 bool needs_further_processing=false;
585 while (first1!=last1 && first2!=last2) {
586 int cmpval=(*first1).rest.compare((*first2).rest);
589 numeric const & newcoeff=ex_to_numeric((*first1).coeff).
590 add(ex_to_numeric((*first2).coeff));
591 if (!newcoeff.is_zero()) {
592 seq.push_back(expair((*first1).rest,newcoeff));
593 if (expair_needs_further_processing(seq.end()-1)) {
594 needs_further_processing = true;
599 } else if (cmpval<0) {
600 seq.push_back(*first1);
603 seq.push_back(*first2);
608 while (first1!=last1) {
609 seq.push_back(*first1);
612 while (first2!=last2) {
613 seq.push_back(*first2);
617 if (needs_further_processing) {
620 construct_from_epvector(v);
624 void expairseq::construct_from_expairseq_ex(expairseq const & s,
627 combine_overall_coeff(s.overall_coeff);
628 if (is_ex_exactly_of_type(e,numeric)) {
629 combine_overall_coeff(e);
634 epvector::const_iterator first=s.seq.begin();
635 epvector::const_iterator last=s.seq.end();
636 expair p=split_ex_to_pair(e);
638 seq.reserve(s.seq.size()+1);
641 bool needs_further_processing=false;
643 // merge p into s.seq
644 while (first!=last) {
645 int cmpval=(*first).rest.compare(p.rest);
648 numeric const & newcoeff=ex_to_numeric((*first).coeff).
649 add(ex_to_numeric(p.coeff));
650 if (!newcoeff.is_zero()) {
651 seq.push_back(expair((*first).rest,newcoeff));
652 if (expair_needs_further_processing(seq.end()-1)) {
653 needs_further_processing = true;
659 } else if (cmpval<0) {
660 seq.push_back(*first);
670 // while loop exited because p was pushed, now push rest of s.seq
671 while (first!=last) {
672 seq.push_back(*first);
676 // while loop exited because s.seq was pushed, now push p
680 if (needs_further_processing) {
683 construct_from_epvector(v);
687 void expairseq::construct_from_exvector(exvector const & v)
689 // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
690 // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
691 // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
692 // (same for (+,*) -> (*,^)
695 #ifdef EXPAIRSEQ_USE_HASHTAB
696 combine_same_terms();
699 combine_same_terms_sorted_seq();
700 #endif // def EXPAIRSEQ_USE_HASHTAB
703 void expairseq::construct_from_epvector(epvector const & v)
705 // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
706 // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
707 // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
708 // (same for (+,*) -> (*,^)
711 #ifdef EXPAIRSEQ_USE_HASHTAB
712 combine_same_terms();
715 combine_same_terms_sorted_seq();
716 #endif // def EXPAIRSEQ_USE_HASHTAB
721 void expairseq::make_flat(exvector const & v)
723 exvector::const_iterator cit, citend = v.end();
725 // count number of operands which are of same expairseq derived type
726 // and their cumulative number of operands
730 while (cit!=citend) {
731 if (cit->bp->tinfo()==tinfo()) {
733 noperands+=ex_to_expairseq(*cit).seq.size();
738 // reserve seq and coeffseq which will hold all operands
739 seq.reserve(v.size()+noperands-nexpairseqs);
741 // copy elements and split off numerical part
743 while (cit!=citend) {
744 if (cit->bp->tinfo()==tinfo()) {
745 expairseq const & subseqref=ex_to_expairseq(*cit);
746 combine_overall_coeff(subseqref.overall_coeff);
747 epvector::const_iterator cit_s=subseqref.seq.begin();
748 while (cit_s!=subseqref.seq.end()) {
749 seq.push_back(*cit_s);
753 if (is_ex_exactly_of_type(*cit,numeric)) {
754 combine_overall_coeff(*cit);
756 seq.push_back(split_ex_to_pair(*cit));
763 cout << "after make flat" << endl;
764 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
765 (*cit).printraw(cout);
772 void expairseq::make_flat(epvector const & v)
774 epvector::const_iterator cit, citend = v.end();
776 // count number of operands which are of same expairseq derived type
777 // and their cumulative number of operands
781 while (cit!=citend) {
782 if (cit->rest.bp->tinfo()==tinfo()) {
784 noperands+=ex_to_expairseq((*cit).rest).seq.size();
789 // reserve seq and coeffseq which will hold all operands
790 seq.reserve(v.size()+noperands-nexpairseqs);
792 // copy elements and split off numerical part
794 while (cit!=citend) {
795 if ((cit->rest.bp->tinfo()==tinfo())&&can_make_flat(*cit)) {
796 expairseq const & subseqref=ex_to_expairseq((*cit).rest);
797 combine_overall_coeff(ex_to_numeric(subseqref.overall_coeff),
798 ex_to_numeric((*cit).coeff));
799 epvector::const_iterator cit_s=subseqref.seq.begin();
800 while (cit_s!=subseqref.seq.end()) {
801 seq.push_back(expair((*cit_s).rest,
802 ex_to_numeric((*cit_s).coeff).mul_dyn(ex_to_numeric((*cit).coeff))));
803 //seq.push_back(combine_pair_with_coeff_to_pair(*cit_s,
808 if ((*cit).is_numeric_with_coeff_1()) {
809 combine_overall_coeff((*cit).rest);
810 //if (is_ex_exactly_of_type((*cit).rest,numeric)) {
811 // combine_overall_coeff(recombine_pair_to_ex(*cit));
820 epvector * expairseq::bubblesort(epvector::iterator itbegin, epvector::iterator itend)
822 unsigned n=itend-itbegin;
824 epvector * sp=new epvector;
827 epvector::iterator last=itend-1;
828 for (epvector::iterator it1=itbegin; it1!=last; ++it1) {
829 for (epvector::iterator it2=it1+1; it2!=itend; ++it2) {
830 if ((*it2).rest.compare((*it1).rest)<0) {
836 sp->push_back(*last);
840 epvector * expairseq::mergesort(epvector::iterator itbegin, epvector::iterator itend)
842 unsigned n=itend-itbegin;
845 epvector * sp=new epvector;
846 sp->push_back(*itbegin);
850 if (n<16) return bubblesort(itbegin, itend);
853 epvector * s1p=mergesort(itbegin, itbegin+m);
854 epvector * s2p=mergesort(itbegin+m, itend);
856 epvector * sp=new epvector;
857 sp->reserve(s1p->size()+s2p->size());
859 epvector::iterator first1=s1p->begin();
860 epvector::iterator last1=s1p->end();
862 epvector::iterator first2=s2p->begin();
863 epvector::iterator last2=s2p->end();
865 while (first1 != last1 && first2 != last2) {
866 if ((*first1).rest.compare((*first2).rest)<0) {
867 sp->push_back(*first1);
870 sp->push_back(*first2);
875 if (first1 != last1) {
876 while (first1 != last1) {
877 sp->push_back(*first1);
881 while (first2 != last2) {
882 sp->push_back(*first2);
894 void expairseq::canonicalize(void)
897 sort(seq.begin(),seq.end(),expair_is_less());
899 sort(seq.begin(),seq.end(),expair_is_less_old());
901 if (is_ex_exactly_of_type((*(seq.begin())).rest,numeric)) {
902 sort(seq.begin(),seq.end(),expair_is_less());
904 epvector::iterator last_numeric=seq.end();
907 } while (is_ex_exactly_of_type((*last_numeric).rest,numeric));
909 sort(last_numeric,seq.end(),expair_is_less());
915 epvector * sorted_seqp=mergesort(seq.begin(),seq.end());
916 epvector::iterator last=sorted_seqp->end();
917 epvector::iterator it2=seq.begin();
918 for (epvector::iterator it1=sorted_seqp->begin(); it1!=last; ++it1, ++it2) {
925 cout << "after canonicalize" << endl;
926 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
927 (*cit).printraw(cout);
934 void expairseq::combine_same_terms_sorted_seq(void)
936 bool needs_further_processing=false;
938 // combine same terms, drop term with coeff 0
940 epvector::iterator itin1=seq.begin();
941 epvector::iterator itin2=itin1+1;
942 epvector::iterator itout=itin1;
943 epvector::iterator last=seq.end();
944 // must_copy will be set to true the first time some combination is possible
945 // from then on the sequence has changed and must be compacted
946 bool must_copy=false;
947 while (itin2!=last) {
948 if ((*itin1).rest.compare((*itin2).rest)==0) {
949 (*itin1).coeff=ex_to_numeric((*itin1).coeff).
950 add_dyn(ex_to_numeric((*itin2).coeff));
951 if (expair_needs_further_processing(itin1)) {
952 needs_further_processing = true;
956 if (!ex_to_numeric((*itin1).coeff).is_zero()) {
966 if (!ex_to_numeric((*itin1).coeff).is_zero()) {
973 seq.erase(itout,last);
978 cout << "after combine" << endl;
979 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
980 (*cit).printraw(cout);
986 if (needs_further_processing) {
989 construct_from_epvector(v);
993 #ifdef EXPAIRSEQ_USE_HASHTAB
995 unsigned expairseq::calc_hashtabsize(unsigned sz) const
998 unsigned nearest_power_of_2 = 1 << log2(sz);
999 // if (nearest_power_of_2 < maxhashtabsize/hashtabfactor) {
1000 // size=nearest_power_of_2*hashtabfactor;
1001 size=nearest_power_of_2/hashtabfactor;
1002 if (size<minhashtabsize) return 0;
1003 ASSERT(hashtabsize<=0x8000000U); // really max size due to 31 bit hashing
1004 // hashtabsize must be a power of 2
1005 ASSERT((1U << log2(size))==size);
1009 unsigned expairseq::calc_hashindex(ex const & e) const
1011 // calculate hashindex
1012 unsigned hash=e.gethash();
1014 if (is_a_numeric_hash(hash)) {
1017 hashindex=hash & hashmask;
1018 // last hashtab entry is reserved for numerics
1019 if (hashindex==hashmask) hashindex=0;
1021 ASSERT(hashindex>=0);
1022 ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
1026 void expairseq::shrink_hashtab(void)
1028 unsigned new_hashtabsize;
1029 while (hashtabsize!=(new_hashtabsize=calc_hashtabsize(seq.size()))) {
1030 ASSERT(new_hashtabsize<hashtabsize);
1031 if (new_hashtabsize==0) {
1038 // shrink by a factor of 2
1039 unsigned half_hashtabsize=hashtabsize/2;
1040 for (unsigned i=0; i<half_hashtabsize-1; ++i) {
1041 hashtab[i].merge(hashtab[i+half_hashtabsize],epp_is_less());
1043 // special treatment for numeric hashes
1044 hashtab[0].merge(hashtab[half_hashtabsize-1],epp_is_less());
1045 hashtab[half_hashtabsize-1]=hashtab[hashtabsize-1];
1046 hashtab.resize(half_hashtabsize);
1047 hashtabsize=half_hashtabsize;
1048 hashmask=hashtabsize-1;
1052 void expairseq::remove_hashtab_entry(epvector::const_iterator element)
1054 if (hashtabsize==0) return; // nothing to do
1056 // calculate hashindex of element to be deleted
1057 unsigned hashindex=calc_hashindex((*element).rest);
1059 // find it in hashtab and remove it
1060 epplist & eppl=hashtab[hashindex];
1061 epplist::iterator epplit=eppl.begin();
1063 while (epplit!=eppl.end()) {
1064 if (*epplit == element) {
1073 cout << "tried to erase " << element-seq.begin() << endl;
1074 cout << "size " << seq.end()-seq.begin() << endl;
1076 unsigned hashindex=calc_hashindex((*element).rest);
1077 epplist & eppl=hashtab[hashindex];
1078 epplist::iterator epplit=eppl.begin();
1080 while (epplit!=eppl.end()) {
1081 if (*epplit == element) {
1093 void expairseq::move_hashtab_entry(epvector::const_iterator oldpos,
1094 epvector::iterator newpos)
1096 ASSERT(hashtabsize!=0);
1098 // calculate hashindex of element which was moved
1099 unsigned hashindex=calc_hashindex((*newpos).rest);
1101 // find it in hashtab and modify it
1102 epplist & eppl=hashtab[hashindex];
1103 epplist::iterator epplit=eppl.begin();
1104 while (epplit!=eppl.end()) {
1105 if (*epplit == oldpos) {
1111 ASSERT(epplit!=eppl.end());
1114 void expairseq::sorted_insert(epplist & eppl, epp elem)
1116 epplist::iterator current=eppl.begin();
1117 while ((current!=eppl.end())&&((*(*current)).is_less(*elem))) {
1120 eppl.insert(current,elem);
1123 void expairseq::build_hashtab_and_combine(epvector::iterator & first_numeric,
1124 epvector::iterator & last_non_zero,
1125 vector<bool> & touched,
1126 unsigned & number_of_zeroes)
1128 epp current=seq.begin();
1130 while (current!=first_numeric) {
1131 if (is_ex_exactly_of_type((*current).rest,numeric)) {
1133 iter_swap(current,first_numeric);
1135 // calculate hashindex
1136 unsigned currenthashindex=calc_hashindex((*current).rest);
1138 // test if there is already a matching expair in the hashtab-list
1139 epplist & eppl=hashtab[currenthashindex];
1140 epplist::iterator epplit=eppl.begin();
1141 while (epplit!=eppl.end()) {
1142 if ((*current).rest.is_equal((*(*epplit)).rest)) break;
1145 if (epplit==eppl.end()) {
1146 // no matching expair found, append this to end of list
1147 sorted_insert(eppl,current);
1150 // epplit points to a matching expair, combine it with current
1151 (*(*epplit)).coeff=ex_to_numeric((*(*epplit)).coeff).
1152 add_dyn(ex_to_numeric((*current).coeff));
1154 // move obsolete current expair to end by swapping with last_non_zero element
1155 // if this was a numeric, it is swapped with the expair before first_numeric
1156 iter_swap(current,last_non_zero);
1158 if (first_numeric!=last_non_zero) iter_swap(first_numeric,current);
1161 // test if combined term has coeff 0 and can be removed is done later
1162 touched[(*epplit)-seq.begin()]=true;
1168 void expairseq::drop_coeff_0_terms(epvector::iterator & first_numeric,
1169 epvector::iterator & last_non_zero,
1170 vector<bool> & touched,
1171 unsigned & number_of_zeroes)
1173 // move terms with coeff 0 to end and remove them from hashtab
1174 // check only those elements which have been touched
1175 epp current=seq.begin();
1177 while (current!=first_numeric) {
1181 } else if (!ex_to_numeric((*current).coeff).is_equal(numZERO())) {
1185 remove_hashtab_entry(current);
1187 // move element to the end, unless it is already at the end
1188 if (current!=last_non_zero) {
1189 iter_swap(current,last_non_zero);
1191 bool numeric_swapped=first_numeric!=last_non_zero;
1192 if (numeric_swapped) iter_swap(first_numeric,current);
1193 epvector::iterator changed_entry;
1195 if (numeric_swapped) {
1196 changed_entry=first_numeric;
1198 changed_entry=last_non_zero;
1204 if (first_numeric!=current) {
1206 // change entry in hashtab which referred to first_numeric or last_non_zero to current
1207 move_hashtab_entry(changed_entry,current);
1208 touched[current-seq.begin()]=touched[changed_entry-seq.begin()];
1217 ASSERT(i==current-seq.begin());
1220 bool expairseq::has_coeff_0(void) const
1222 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
1223 if ((*cit).coeff.is_equal(exZERO())) {
1230 void expairseq::add_numerics_to_hashtab(epvector::iterator first_numeric,
1231 epvector::const_iterator last_non_zero)
1233 if (first_numeric==seq.end()) return; // no numerics
1235 epvector::iterator current=first_numeric;
1236 epvector::const_iterator last=last_non_zero+1;
1237 while (current!=last) {
1238 sorted_insert(hashtab[hashmask],current);
1243 void expairseq::combine_same_terms(void)
1245 // combine same terms, drop term with coeff 0, move numerics to end
1247 // calculate size of hashtab
1248 hashtabsize=calc_hashtabsize(seq.size());
1250 // hashtabsize is a power of 2
1251 hashmask=hashtabsize-1;
1255 hashtab.resize(hashtabsize);
1257 if (hashtabsize==0) {
1259 combine_same_terms_sorted_seq();
1260 ASSERT(!has_coeff_0());
1264 // iterate through seq, move numerics to end,
1265 // fill hashtab and combine same terms
1266 epvector::iterator first_numeric=seq.end();
1267 epvector::iterator last_non_zero=seq.end()-1;
1269 vector<bool> touched;
1270 touched.reserve(seq.size());
1271 for (unsigned i=0; i<seq.size(); ++i) touched[i]=false;
1273 unsigned number_of_zeroes=0;
1275 ASSERT(!has_coeff_0());
1276 build_hashtab_and_combine(first_numeric,last_non_zero,touched,number_of_zeroes);
1278 cout << "in combine:" << endl;
1280 cout << "size=" << seq.end() - seq.begin() << endl;
1281 cout << "first_numeric=" << first_numeric - seq.begin() << endl;
1282 cout << "last_non_zero=" << last_non_zero - seq.begin() << endl;
1283 for (unsigned i=0; i<seq.size(); ++i) {
1284 if (touched[i]) cout << i << " is touched" << endl;
1286 cout << "end in combine" << endl;
1289 // there should not be any terms with coeff 0 from the beginning,
1290 // so it should be safe to skip this step
1291 if (number_of_zeroes!=0) {
1292 drop_coeff_0_terms(first_numeric,last_non_zero,touched,number_of_zeroes);
1294 cout << "in combine after drop:" << endl;
1296 cout << "size=" << seq.end() - seq.begin() << endl;
1297 cout << "first_numeric=" << first_numeric - seq.begin() << endl;
1298 cout << "last_non_zero=" << last_non_zero - seq.begin() << endl;
1299 for (unsigned i=0; i<seq.size(); ++i) {
1300 if (touched[i]) cout << i << " is touched" << endl;
1302 cout << "end in combine after drop" << endl;
1306 add_numerics_to_hashtab(first_numeric,last_non_zero);
1308 // pop zero elements
1309 for (unsigned i=0; i<number_of_zeroes; ++i) {
1313 // shrink hashtabsize to calculated value
1314 ASSERT(!has_coeff_0());
1318 ASSERT(!has_coeff_0());
1321 #endif // def EXPAIRSEQ_USE_HASHTAB
1323 bool expairseq::is_canonical() const
1325 if (seq.size()<=1) return 1;
1327 #ifdef EXPAIRSEQ_USE_HASHTAB
1328 if (hashtabsize>0) return 1; // not canoncalized
1329 #endif // def EXPAIRSEQ_USE_HASHTAB
1331 epvector::const_iterator it=seq.begin();
1332 epvector::const_iterator it_last=it;
1333 for (++it; it!=seq.end(); it_last=it, ++it) {
1334 if (!((*it_last).is_less(*it)||(*it_last).is_equal(*it))) {
1335 if (!is_ex_exactly_of_type((*it_last).rest,numeric)||
1336 !is_ex_exactly_of_type((*it).rest,numeric)) {
1337 // double test makes it easier to set a breakpoint...
1338 if (!is_ex_exactly_of_type((*it_last).rest,numeric)||
1339 !is_ex_exactly_of_type((*it).rest,numeric)) {
1340 printpair(cout,*it_last,0);
1342 printpair(cout,*it,0);
1344 cout << "pair1:" << endl;
1345 (*it_last).rest.printtree(cout);
1346 (*it_last).coeff.printtree(cout);
1347 cout << "pair2:" << endl;
1348 (*it).rest.printtree(cout);
1349 (*it).coeff.printtree(cout);
1358 epvector * expairseq::expandchildren(unsigned options) const
1360 epvector::const_iterator last=seq.end();
1361 epvector::const_iterator cit=seq.begin();
1363 ex const & expanded_ex=(*cit).rest.expand(options);
1364 if (!are_ex_trivially_equal((*cit).rest,expanded_ex)) {
1366 // something changed, copy seq, eval and return it
1367 epvector *s=new epvector;
1368 s->reserve(seq.size());
1370 // copy parts of seq which are known not to have changed
1371 epvector::const_iterator cit2=seq.begin();
1373 s->push_back(*cit2);
1376 // copy first changed element
1377 s->push_back(combine_ex_with_coeff_to_pair(expanded_ex,
1381 while (cit2!=last) {
1382 s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.expand(options),
1391 return 0; // nothing has changed
1394 epvector * expairseq::evalchildren(int level) const
1396 // returns a NULL pointer if nothing had to be evaluated
1397 // returns a pointer to a newly created epvector otherwise
1398 // (which has to be deleted somewhere else)
1403 if (level == -max_recursion_level) {
1404 throw(std::runtime_error("max recursion level reached"));
1408 epvector::const_iterator last=seq.end();
1409 epvector::const_iterator cit=seq.begin();
1411 ex const & evaled_ex=(*cit).rest.eval(level);
1412 if (!are_ex_trivially_equal((*cit).rest,evaled_ex)) {
1414 // something changed, copy seq, eval and return it
1415 epvector *s=new epvector;
1416 s->reserve(seq.size());
1418 // copy parts of seq which are known not to have changed
1419 epvector::const_iterator cit2=seq.begin();
1421 s->push_back(*cit2);
1424 // copy first changed element
1425 s->push_back(combine_ex_with_coeff_to_pair(evaled_ex,
1429 while (cit2!=last) {
1430 s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.eval(level),
1439 return 0; // nothing has changed
1442 epvector expairseq::evalfchildren(int level) const
1445 s.reserve(seq.size());
1450 if (level == -max_recursion_level) {
1451 throw(std::runtime_error("max recursion level reached"));
1454 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
1455 s.push_back(combine_ex_with_coeff_to_pair((*it).rest.evalf(level),
1461 epvector expairseq::normalchildren(int level) const
1464 s.reserve(seq.size());
1469 if (level == -max_recursion_level) {
1470 throw(std::runtime_error("max recursion level reached"));
1473 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
1474 s.push_back(combine_ex_with_coeff_to_pair((*it).rest.normal(level),
1480 epvector expairseq::diffchildren(symbol const & y) const
1483 s.reserve(seq.size());
1485 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
1486 s.push_back(combine_ex_with_coeff_to_pair((*it).rest.diff(y),
1492 epvector * expairseq::subschildren(lst const & ls, lst const & lr) const
1494 // returns a NULL pointer if nothing had to be substituted
1495 // returns a pointer to a newly created epvector otherwise
1496 // (which has to be deleted somewhere else)
1498 epvector::const_iterator last=seq.end();
1499 epvector::const_iterator cit=seq.begin();
1501 ex const & subsed_ex=(*cit).rest.subs(ls,lr);
1502 if (!are_ex_trivially_equal((*cit).rest,subsed_ex)) {
1504 // something changed, copy seq, subs and return it
1505 epvector *s=new epvector;
1506 s->reserve(seq.size());
1508 // copy parts of seq which are known not to have changed
1509 epvector::const_iterator cit2=seq.begin();
1511 s->push_back(*cit2);
1514 // copy first changed element
1515 s->push_back(combine_ex_with_coeff_to_pair(subsed_ex,
1519 while (cit2!=last) {
1520 s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.subs(ls,lr),
1529 return 0; // nothing has changed
1533 epvector expairseq::subschildren(lst const & ls, lst const & lr) const
1536 s.reserve(seq.size());
1538 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
1539 s.push_back(split_ex_to_pair((*it).rest.subs(ls,lr),(*it).coeff));
1546 void expairseq::sort(epviter first, epviter last, expair_is_less comp)
1548 if (first != last) {
1549 introsort_loop(first, last, lg(last - first) * 2, comp);
1550 __final_insertion_sort(first, last, comp);
1554 ptrdiff_t expairseq::lg(ptrdiff_t n)
1557 for (k = 0; n > 1; n >>= 1) ++k;
1561 void expairseq::introsort_loop(epviter first, epviter last,
1562 ptrdiff_t depth_limit, expair_is_less comp)
1564 while (last - first > stl_threshold) {
1565 if (depth_limit == 0) {
1566 partial_sort(first, last, last, comp);
1570 epviter cut = unguarded_partition(first, last,
1571 expair(__median(*first, *(first + (last - first)/2),
1572 *(last - 1), comp)), comp);
1573 introsort_loop(cut, last, depth_limit, comp);
1578 epviter expairseq::unguarded_partition(epviter first, epviter last,
1579 expair pivot, expair_is_less comp)
1582 while (comp(*first, pivot)) ++first;
1584 while (comp(pivot, *last)) --last;
1585 if (!(first < last)) return first;
1586 iter_swap(first, last);
1591 void expairseq::partial_sort(epviter first, epviter middle, epviter last,
1592 expair_is_less comp) {
1593 make_heap(first, middle, comp);
1594 for (RandomAccessIterator i = middle; i < last; ++i)
1595 if (comp(*i, *first))
1596 __pop_heap(first, middle, i, T(*i), comp, distance_type(first));
1597 sort_heap(first, middle, comp);
1602 // static member variables
1607 unsigned expairseq::precedence=10;
1609 #ifdef EXPAIRSEQ_USE_HASHTAB
1610 unsigned expairseq::maxhashtabsize=0x4000000U;
1611 unsigned expairseq::minhashtabsize=0x1000U;
1612 unsigned expairseq::hashtabfactor=1;
1613 #endif // def EXPAIRSEQ_USE_HASHTAB
1619 const expairseq some_expairseq;
1620 type_info const & typeid_expairseq=typeid(some_expairseq);