/** @file expairseq.cpp
*
+ * Implementation of sequences of expression pairs. */
+
+/*
* GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
#include <algorithm>
#include <string>
#include <stdexcept>
+#include <cmath>
+
+#include "expairseq.h"
+#include "lst.h"
+#include "debugmsg.h"
+#include "utils.h"
-#include "ginac.h"
+#ifndef NO_GINAC_NAMESPACE
+namespace GiNaC {
+#endif // ndef NO_GINAC_NAMESPACE
#ifdef EXPAIRSEQ_USE_HASHTAB
-#error "!!!!!!!!TODO: expair_needs_further_processing not yet implemented for hashtabs, sorry. A.F."
+#error "FIXME: expair_needs_further_processing not yet implemented for hashtabs, sorry. A.F."
#endif // def EXPAIRSEQ_USE_HASHTAB
//////////
// other constructors
//////////
-expairseq::expairseq(ex const & lh, ex const & rh) : basic(TINFO_EXPAIRSEQ)
+expairseq::expairseq(ex const & lh, ex const & rh) : basic(TINFO_expairseq)
{
debugmsg("expairseq constructor from ex,ex",LOGLEVEL_CONSTRUCT);
construct_from_2_ex(lh,rh);
- ASSERT(is_canonical());
+ GINAC_ASSERT(is_canonical());
}
-expairseq::expairseq(exvector const & v) : basic(TINFO_EXPAIRSEQ)
+expairseq::expairseq(exvector const & v) : basic(TINFO_expairseq)
{
debugmsg("expairseq constructor from exvector",LOGLEVEL_CONSTRUCT);
construct_from_exvector(v);
- ASSERT(is_canonical());
+ GINAC_ASSERT(is_canonical());
}
/*
expairseq::expairseq(epvector const & v, bool do_not_canonicalize) :
- basic(TINFO_EXPAIRSEQ)
+ basic(TINFO_expairseq)
{
debugmsg("expairseq constructor from epvector",LOGLEVEL_CONSTRUCT);
if (do_not_canonicalize) {
} else {
construct_from_epvector(v);
}
- ASSERT(is_canonical());
+ GINAC_ASSERT(is_canonical());
}
*/
expairseq::expairseq(epvector const & v, ex const & oc) :
- basic(TINFO_EXPAIRSEQ), overall_coeff(oc)
+ basic(TINFO_expairseq), overall_coeff(oc)
{
debugmsg("expairseq constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
construct_from_epvector(v);
- ASSERT(is_canonical());
+ GINAC_ASSERT(is_canonical());
}
expairseq::expairseq(epvector * vp, ex const & oc) :
- basic(TINFO_EXPAIRSEQ), overall_coeff(oc)
+ basic(TINFO_expairseq), overall_coeff(oc)
{
debugmsg("expairseq constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
- ASSERT(vp!=0);
+ GINAC_ASSERT(vp!=0);
construct_from_epvector(*vp);
delete vp;
- ASSERT(is_canonical());
+ GINAC_ASSERT(is_canonical());
}
//////////
return new expairseq(*this);
}
+void expairseq::print(ostream & os, unsigned upper_precedence) const
+{
+ debugmsg("expairseq print",LOGLEVEL_PRINT);
+ os << "[[";
+ printseq(os,',',precedence,upper_precedence);
+ os << "]]";
+}
+
+void expairseq::printraw(ostream & os) const
+{
+ debugmsg("expairseq printraw",LOGLEVEL_PRINT);
+
+ os << "expairseq(";
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ os << "(";
+ (*cit).rest.printraw(os);
+ os << ",";
+ (*cit).coeff.printraw(os);
+ os << "),";
+ }
+ os << ")";
+}
+
+void expairseq::printtree(ostream & os, unsigned indent) const
+{
+ debugmsg("expairseq printtree",LOGLEVEL_PRINT);
+
+ os << string(indent,' ') << "type=" << typeid(*this).name()
+ << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+ << ", flags=" << flags
+ << ", nops=" << nops() << endl;
+ for (unsigned i=0; i<seq.size(); ++i) {
+ seq[i].rest.printtree(os,indent+delta_indent);
+ seq[i].coeff.printtree(os,indent+delta_indent);
+ if (i!=seq.size()-1) {
+ os << string(indent+delta_indent,' ') << "-----" << endl;
+ }
+ }
+ if (!overall_coeff.is_equal(default_overall_coeff())) {
+ os << string(indent+delta_indent,' ') << "-----" << endl;
+ os << string(indent+delta_indent,' ') << "overall_coeff" << endl;
+ overall_coeff.printtree(os,indent+delta_indent);
+ }
+ os << string(indent+delta_indent,' ') << "=====" << endl;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+ os << string(indent+delta_indent,' ')
+ << "hashtab size " << hashtabsize << endl;
+ if (hashtabsize==0) return;
+#define MAXCOUNT 5
+ unsigned count[MAXCOUNT+1];
+ for (int i=0; i<MAXCOUNT+1; ++i) count[i]=0;
+ unsigned this_bin_fill;
+ unsigned cum_fill_sq=0;
+ unsigned cum_fill=0;
+ for (unsigned i=0; i<hashtabsize; ++i) {
+ this_bin_fill=0;
+ if (hashtab[i].size()>0) {
+ os << string(indent+delta_indent,' ')
+ << "bin " << i << " with entries ";
+ for (epplist::const_iterator it=hashtab[i].begin();
+ it!=hashtab[i].end(); ++it) {
+ os << *it-seq.begin() << " ";
+ this_bin_fill++;
+ }
+ os << endl;
+ cum_fill += this_bin_fill;
+ cum_fill_sq += this_bin_fill*this_bin_fill;
+ }
+ if (this_bin_fill<MAXCOUNT) {
+ ++count[this_bin_fill];
+ } else {
+ ++count[MAXCOUNT];
+ }
+ }
+ unsigned fact=1;
+ double cum_prob=0;
+ double lambda=(1.0*seq.size())/hashtabsize;
+ for (int k=0; k<MAXCOUNT; ++k) {
+ if (k>0) fact *= k;
+ double prob=pow(lambda,k)/fact*exp(-lambda);
+ cum_prob += prob;
+ os << string(indent+delta_indent,' ') << "bins with " << k << " entries: "
+ << int(1000.0*count[k]/hashtabsize)/10.0 << "% (expected: "
+ << int(prob*1000)/10.0 << ")" << endl;
+ }
+ os << string(indent+delta_indent,' ') << "bins with more entries: "
+ << int(1000.0*count[MAXCOUNT]/hashtabsize)/10.0 << "% (expected: "
+ << int((1-cum_prob)*1000)/10.0 << ")" << endl;
+
+ os << string(indent+delta_indent,' ') << "variance: "
+ << 1.0/hashtabsize*cum_fill_sq-(1.0/hashtabsize*cum_fill)*(1.0/hashtabsize*cum_fill)
+ << endl;
+ os << string(indent+delta_indent,' ') << "average fill: "
+ << (1.0*cum_fill)/hashtabsize
+ << " (should be equal to " << (1.0*seq.size())/hashtabsize << ")" << endl;
+#endif // def EXPAIRSEQ_USE_HASHTAB
+}
+
bool expairseq::info(unsigned inf) const
{
return basic::info(inf);
if (unsigned(i)<seq.size()) {
return recombine_pair_to_ex(seq[i]);
}
- ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
+ GINAC_ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
return overall_coeff;
}
int expairseq::compare_same_type(basic const & other) const
{
- ASSERT(is_of_type(other, expairseq));
+ GINAC_ASSERT(is_of_type(other, expairseq));
expairseq const & o=static_cast<expairseq const &>(const_cast<basic &>(other));
int cmpval;
//if (seq.size()==0) return 0; // empty expairseq's are equal
#ifdef EXPAIRSEQ_USE_HASHTAB
- ASSERT(hashtabsize==o.hashtabsize);
+ GINAC_ASSERT(hashtabsize==o.hashtabsize);
if (hashtabsize==0) {
#endif // def EXPAIRSEQ_USE_HASHTAB
epvector::const_iterator cit1=seq.begin();
if (cmpval!=0) return cmpval;
}
- ASSERT(cit1==last1);
- ASSERT(cit2==last2);
+ GINAC_ASSERT(cit1==last1);
+ GINAC_ASSERT(cit2==last2);
return 0;
#ifdef EXPAIRSEQ_USE_HASHTAB
other.printtree(cout,0);
}
- ASSERT(hashtabsize==o.hashtabsize);
+ GINAC_ASSERT(hashtabsize==o.hashtabsize);
if (hashtabsize==0) {
#endif // def EXPAIRSEQ_USE_HASHTAB
return expairseq(vp,oc);
}
+void expairseq::printpair(ostream & os, expair const & p, unsigned upper_precedence) const
+{
+ os << "[[";
+ p.rest.bp->print(os,precedence);
+ os << ",";
+ p.coeff.bp->print(os,precedence);
+ os << "]]";
+}
+
+void expairseq::printseq(ostream & os, char delim, unsigned this_precedence,
+ unsigned upper_precedence) const
+{
+ if (this_precedence<=upper_precedence) os << "(";
+ epvector::const_iterator it,it_last;
+ it_last=seq.end();
+ --it_last;
+ for (it=seq.begin(); it!=it_last; ++it) {
+ printpair(os,*it,this_precedence);
+ os << delim;
+ }
+ printpair(os,*it,this_precedence);
+ if (!overall_coeff.is_equal(default_overall_coeff())) {
+ os << delim << overall_coeff;
+ }
+ if (this_precedence<=upper_precedence) os << ")";
+}
+
expair expairseq::split_ex_to_pair(ex const & e) const
{
- return expair(e,exONE());
+ return expair(e,_ex1());
}
expair expairseq::combine_ex_with_coeff_to_pair(ex const & e,
ex const & c) const
{
- ASSERT(is_ex_exactly_of_type(c,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
return expair(e,c);
}
expair expairseq::combine_pair_with_coeff_to_pair(expair const & p,
ex const & c) const
{
- ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
- ASSERT(is_ex_exactly_of_type(c,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
}
ex expairseq::default_overall_coeff(void) const
{
- return exZERO();
+ return _ex0();
}
void expairseq::combine_overall_coeff(ex const & c)
{
- ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
- ASSERT(is_ex_exactly_of_type(c,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
overall_coeff = ex_to_numeric(overall_coeff).add_dyn(ex_to_numeric(c));
}
void expairseq::combine_overall_coeff(ex const & c1, ex const & c2)
{
- ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
- ASSERT(is_ex_exactly_of_type(c1,numeric));
- ASSERT(is_ex_exactly_of_type(c2,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(c1,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(c2,numeric));
overall_coeff = ex_to_numeric(overall_coeff).
add_dyn(ex_to_numeric(c1).mul(ex_to_numeric(c2)));
}
v.push_back(rh);
construct_from_exvector(v);
#ifdef EXPAIRSEQ_USE_HASHTAB
- ASSERT((hashtabsize==0)||(hashtabsize>=minhashtabsize));
- ASSERT(hashtabsize==calc_hashtabsize(seq.size()));
+ GINAC_ASSERT((hashtabsize==0)||(hashtabsize>=minhashtabsize));
+ GINAC_ASSERT(hashtabsize==calc_hashtabsize(seq.size()));
#endif // def EXPAIRSEQ_USE_HASHTAB
}
// size=nearest_power_of_2*hashtabfactor;
size=nearest_power_of_2/hashtabfactor;
if (size<minhashtabsize) return 0;
- ASSERT(hashtabsize<=0x8000000U); // really max size due to 31 bit hashing
+ GINAC_ASSERT(hashtabsize<=0x8000000U); // really max size due to 31 bit hashing
// hashtabsize must be a power of 2
- ASSERT((1U << log2(size))==size);
+ GINAC_ASSERT((1U << log2(size))==size);
return size;
}
// last hashtab entry is reserved for numerics
if (hashindex==hashmask) hashindex=0;
}
- ASSERT(hashindex>=0);
- ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
+ GINAC_ASSERT(hashindex>=0);
+ GINAC_ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
return hashindex;
}
{
unsigned new_hashtabsize;
while (hashtabsize!=(new_hashtabsize=calc_hashtabsize(seq.size()))) {
- ASSERT(new_hashtabsize<hashtabsize);
+ GINAC_ASSERT(new_hashtabsize<hashtabsize);
if (new_hashtabsize==0) {
hashtab.clear();
hashtabsize=0;
}
++epplit;
}
- ASSERT(erased);
+ GINAC_ASSERT(erased);
}
- ASSERT(erased);
+ GINAC_ASSERT(erased);
}
void expairseq::move_hashtab_entry(epvector::const_iterator oldpos,
epvector::iterator newpos)
{
- ASSERT(hashtabsize!=0);
+ GINAC_ASSERT(hashtabsize!=0);
// calculate hashindex of element which was moved
unsigned hashindex=calc_hashindex((*newpos).rest);
}
++epplit;
}
- ASSERT(epplit!=eppl.end());
+ GINAC_ASSERT(epplit!=eppl.end());
}
void expairseq::sorted_insert(epplist & eppl, epp elem)
if (!touched[i]) {
++current;
++i;
- } else if (!ex_to_numeric((*current).coeff).is_equal(numZERO())) {
+ } else if (!ex_to_numeric((*current).coeff).is_equal(_num0())) {
++current;
++i;
} else {
}
}
}
- ASSERT(i==current-seq.begin());
+ GINAC_ASSERT(i==current-seq.begin());
}
bool expairseq::has_coeff_0(void) const
{
for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- if ((*cit).coeff.is_equal(exZERO())) {
+ if ((*cit).coeff.is_equal(_ex0())) {
return true;
}
}
if (hashtabsize==0) {
canonicalize();
combine_same_terms_sorted_seq();
- ASSERT(!has_coeff_0());
+ GINAC_ASSERT(!has_coeff_0());
return;
}
unsigned number_of_zeroes=0;
- ASSERT(!has_coeff_0());
+ GINAC_ASSERT(!has_coeff_0());
build_hashtab_and_combine(first_numeric,last_non_zero,touched,number_of_zeroes);
/*
cout << "in combine:" << endl;
}
// shrink hashtabsize to calculated value
- ASSERT(!has_coeff_0());
+ GINAC_ASSERT(!has_coeff_0());
shrink_hashtab();
- ASSERT(!has_coeff_0());
+ GINAC_ASSERT(!has_coeff_0());
}
#endif // def EXPAIRSEQ_USE_HASHTAB
ex const & evaled_ex=(*cit).rest.eval(level);
if (!are_ex_trivially_equal((*cit).rest,evaled_ex)) {
- // something changed, copy seq, eval and return it
+ // something changed, copy seq, eval and return it
epvector *s=new epvector;
s->reserve(seq.size());
// returns a NULL pointer if nothing had to be substituted
// returns a pointer to a newly created epvector otherwise
// (which has to be deleted somewhere else)
-
+ GINAC_ASSERT(ls.nops()==lr.nops());
+
epvector::const_iterator last=seq.end();
epvector::const_iterator cit=seq.begin();
while (cit!=last) {
ex const & subsed_ex=(*cit).rest.subs(ls,lr);
if (!are_ex_trivially_equal((*cit).rest,subsed_ex)) {
-
+
// something changed, copy seq, subs and return it
epvector *s=new epvector;
s->reserve(seq.size());
-
+
// copy parts of seq which are known not to have changed
epvector::const_iterator cit2=seq.begin();
while (cit2!=cit) {
s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.subs(ls,lr),
(*cit2).coeff));
++cit2;
- }
+ }
return s;
}
++cit;
return 0; // nothing has changed
}
-/*
-epvector expairseq::subschildren(lst const & ls, lst const & lr) const
-{
- epvector s;
- s.reserve(seq.size());
-
- for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- s.push_back(split_ex_to_pair((*it).rest.subs(ls,lr),(*it).coeff));
- }
- return s;
-}
-*/
-
-/*
-void expairseq::sort(epviter first, epviter last, expair_is_less comp)
-{
- if (first != last) {
- introsort_loop(first, last, lg(last - first) * 2, comp);
- __final_insertion_sort(first, last, comp);
- }
-}
-
-ptrdiff_t expairseq::lg(ptrdiff_t n)
-{
- ptrdiff_t k;
- for (k = 0; n > 1; n >>= 1) ++k;
- return k;
-}
-
-void expairseq::introsort_loop(epviter first, epviter last,
- ptrdiff_t depth_limit, expair_is_less comp)
-{
- while (last - first > stl_threshold) {
- if (depth_limit == 0) {
- partial_sort(first, last, last, comp);
- return;
- }
- --depth_limit;
- epviter cut = unguarded_partition(first, last,
- expair(__median(*first, *(first + (last - first)/2),
- *(last - 1), comp)), comp);
- introsort_loop(cut, last, depth_limit, comp);
- last = cut;
- }
-}
-
-epviter expairseq::unguarded_partition(epviter first, epviter last,
- expair pivot, expair_is_less comp)
-{
- while (1) {
- while (comp(*first, pivot)) ++first;
- --last;
- while (comp(pivot, *last)) --last;
- if (!(first < last)) return first;
- iter_swap(first, last);
- ++first;
- }
-}
-
-void expairseq::partial_sort(epviter first, epviter middle, epviter last,
- expair_is_less comp) {
- make_heap(first, middle, comp);
- for (RandomAccessIterator i = middle; i < last; ++i)
- if (comp(*i, *first))
- __pop_heap(first, middle, i, T(*i), comp, distance_type(first));
- sort_heap(first, middle, comp);
-}
-*/
-
//////////
// static member variables
//////////
const expairseq some_expairseq;
type_info const & typeid_expairseq=typeid(some_expairseq);
+#ifndef NO_GINAC_NAMESPACE
+} // namespace GiNaC
+#endif // ndef NO_GINAC_NAMESPACE