add::add()
{
- debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_add;
+ debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_add;
}
add::~add()
{
- debugmsg("add destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("add destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
add::add(const add & other)
{
- debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const add & add::operator=(const add & other)
{
- debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void add::copy(const add & other)
{
- inherited::copy(other);
+ inherited::copy(other);
}
void add::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
//////////
add::add(const ex & lh, const ex & rh)
{
- debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_add;
- overall_coeff = _ex0();
- construct_from_2_ex(lh,rh);
- GINAC_ASSERT(is_canonical());
+ debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_add;
+ overall_coeff = _ex0();
+ construct_from_2_ex(lh,rh);
+ GINAC_ASSERT(is_canonical());
}
add::add(const exvector & v)
{
- debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_add;
- overall_coeff = _ex0();
- construct_from_exvector(v);
- GINAC_ASSERT(is_canonical());
+ debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_add;
+ overall_coeff = _ex0();
+ construct_from_exvector(v);
+ GINAC_ASSERT(is_canonical());
}
/*
add::add(const epvector & v, bool do_not_canonicalize)
{
- debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_add;
- if (do_not_canonicalize) {
- seq=v;
+ debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_add;
+ if (do_not_canonicalize) {
+ seq=v;
#ifdef EXPAIRSEQ_USE_HASHTAB
- combine_same_terms(); // to build hashtab
+ combine_same_terms(); // to build hashtab
#endif // def EXPAIRSEQ_USE_HASHTAB
- } else {
- construct_from_epvector(v);
- }
- GINAC_ASSERT(is_canonical());
+ } else {
+ construct_from_epvector(v);
+ }
+ GINAC_ASSERT(is_canonical());
}
*/
add::add(const epvector & v)
{
- debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_add;
- overall_coeff = _ex0();
- construct_from_epvector(v);
- GINAC_ASSERT(is_canonical());
+ debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_add;
+ overall_coeff = _ex0();
+ construct_from_epvector(v);
+ GINAC_ASSERT(is_canonical());
}
add::add(const epvector & v, const ex & oc)
{
- debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_add;
- overall_coeff = oc;
- construct_from_epvector(v);
- GINAC_ASSERT(is_canonical());
+ debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_add;
+ overall_coeff = oc;
+ construct_from_epvector(v);
+ GINAC_ASSERT(is_canonical());
}
add::add(epvector * vp, const ex & oc)
{
- debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_add;
- GINAC_ASSERT(vp!=0);
- overall_coeff = oc;
- construct_from_epvector(*vp);
- delete vp;
- GINAC_ASSERT(is_canonical());
+ debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_add;
+ GINAC_ASSERT(vp!=0);
+ overall_coeff = oc;
+ construct_from_epvector(*vp);
+ delete vp;
+ GINAC_ASSERT(is_canonical());
}
//////////
/** Construct object from archive_node. */
add::add(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("add constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ debugmsg("add constructor from archive_node", LOGLEVEL_CONSTRUCT);
}
/** Unarchive the object. */
ex add::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new add(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new add(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void add::archive(archive_node &n) const
{
- inherited::archive(n);
+ inherited::archive(n);
}
//////////
basic * add::duplicate() const
{
- debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
- return new add(*this);
+ debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
+ return new add(*this);
}
void add::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("add print",LOGLEVEL_PRINT);
- if (precedence<=upper_precedence) os << "(";
- numeric coeff;
- bool first = true;
- // first print the overall numeric coefficient, if present:
- if (!overall_coeff.is_zero()) {
- os << overall_coeff;
- first = false;
- }
- // then proceed with the remaining factors:
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- coeff = ex_to_numeric(cit->coeff);
- if (!first) {
- if (coeff.csgn()==-1) os << '-'; else os << '+';
- } else {
- if (coeff.csgn()==-1) os << '-';
- first = false;
- }
- if (!coeff.is_equal(_num1()) &&
- !coeff.is_equal(_num_1())) {
- if (coeff.is_rational()) {
- if (coeff.is_negative())
- os << -coeff;
- else
- os << coeff;
- } else {
- if (coeff.csgn()==-1)
- (-coeff).print(os, precedence);
- else
- coeff.print(os, precedence);
- }
- os << '*';
- }
- os << cit->rest;
- }
- if (precedence<=upper_precedence) os << ")";
+ debugmsg("add print",LOGLEVEL_PRINT);
+ if (precedence<=upper_precedence) os << "(";
+ numeric coeff;
+ bool first = true;
+ // first print the overall numeric coefficient, if present:
+ if (!overall_coeff.is_zero()) {
+ os << overall_coeff;
+ first = false;
+ }
+ // then proceed with the remaining factors:
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ coeff = ex_to_numeric(cit->coeff);
+ if (!first) {
+ if (coeff.csgn()==-1) os << '-'; else os << '+';
+ } else {
+ if (coeff.csgn()==-1) os << '-';
+ first = false;
+ }
+ if (!coeff.is_equal(_num1()) &&
+ !coeff.is_equal(_num_1())) {
+ if (coeff.is_rational()) {
+ if (coeff.is_negative())
+ os << -coeff;
+ else
+ os << coeff;
+ } else {
+ if (coeff.csgn()==-1)
+ (-coeff).print(os, precedence);
+ else
+ coeff.print(os, precedence);
+ }
+ os << '*';
+ }
+ os << cit->rest;
+ }
+ if (precedence<=upper_precedence) os << ")";
}
void add::printraw(std::ostream & os) const
{
- debugmsg("add printraw",LOGLEVEL_PRINT);
+ debugmsg("add printraw",LOGLEVEL_PRINT);
- os << "+(";
- for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- os << "(";
- (*it).rest.bp->printraw(os);
- os << ",";
- (*it).coeff.bp->printraw(os);
- os << "),";
- }
- os << ",hash=" << hashvalue << ",flags=" << flags;
- os << ")";
+ os << "+(";
+ for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ os << "(";
+ (*it).rest.bp->printraw(os);
+ os << ",";
+ (*it).coeff.bp->printraw(os);
+ os << "),";
+ }
+ os << ",hash=" << hashvalue << ",flags=" << flags;
+ os << ")";
}
void add::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("add print csrc", LOGLEVEL_PRINT);
- if (precedence <= upper_precedence)
- os << "(";
-
- // Print arguments, separated by "+"
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- while (it != itend) {
-
- // If the coefficient is -1, it is replaced by a single minus sign
- if (it->coeff.compare(_num1()) == 0) {
- it->rest.bp->printcsrc(os, type, precedence);
- } else if (it->coeff.compare(_num_1()) == 0) {
- os << "-";
- it->rest.bp->printcsrc(os, type, precedence);
- } else if (ex_to_numeric(it->coeff).numer().compare(_num1()) == 0) {
- it->rest.bp->printcsrc(os, type, precedence);
- os << "/";
- ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
- } else if (ex_to_numeric(it->coeff).numer().compare(_num_1()) == 0) {
- os << "-";
- it->rest.bp->printcsrc(os, type, precedence);
- os << "/";
- ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
- } else {
- it->coeff.bp->printcsrc(os, type, precedence);
- os << "*";
- it->rest.bp->printcsrc(os, type, precedence);
- }
-
- // Separator is "+", except if the following expression would have a leading minus sign
- it++;
- if (it != itend && !(it->coeff.compare(_num0()) < 0 || (it->coeff.compare(_num1()) == 0 && is_ex_exactly_of_type(it->rest, numeric) && it->rest.compare(_num0()) < 0)))
- os << "+";
- }
-
- if (!overall_coeff.is_equal(_ex0())) {
- if (overall_coeff.info(info_flags::positive)) os << '+';
- overall_coeff.bp->printcsrc(os,type,precedence);
- }
-
- if (precedence <= upper_precedence)
- os << ")";
+ debugmsg("add print csrc", LOGLEVEL_PRINT);
+ if (precedence <= upper_precedence)
+ os << "(";
+
+ // Print arguments, separated by "+"
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ while (it != itend) {
+
+ // If the coefficient is -1, it is replaced by a single minus sign
+ if (it->coeff.compare(_num1()) == 0) {
+ it->rest.bp->printcsrc(os, type, precedence);
+ } else if (it->coeff.compare(_num_1()) == 0) {
+ os << "-";
+ it->rest.bp->printcsrc(os, type, precedence);
+ } else if (ex_to_numeric(it->coeff).numer().compare(_num1()) == 0) {
+ it->rest.bp->printcsrc(os, type, precedence);
+ os << "/";
+ ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
+ } else if (ex_to_numeric(it->coeff).numer().compare(_num_1()) == 0) {
+ os << "-";
+ it->rest.bp->printcsrc(os, type, precedence);
+ os << "/";
+ ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
+ } else {
+ it->coeff.bp->printcsrc(os, type, precedence);
+ os << "*";
+ it->rest.bp->printcsrc(os, type, precedence);
+ }
+
+ // Separator is "+", except if the following expression would have a leading minus sign
+ it++;
+ if (it != itend && !(it->coeff.compare(_num0()) < 0 || (it->coeff.compare(_num1()) == 0 && is_ex_exactly_of_type(it->rest, numeric) && it->rest.compare(_num0()) < 0)))
+ os << "+";
+ }
+
+ if (!overall_coeff.is_equal(_ex0())) {
+ if (overall_coeff.info(info_flags::positive)) os << '+';
+ overall_coeff.bp->printcsrc(os,type,precedence);
+ }
+
+ if (precedence <= upper_precedence)
+ os << ")";
}
bool add::info(unsigned inf) const
{
- switch (inf) {
- case info_flags::polynomial:
- case info_flags::integer_polynomial:
- case info_flags::cinteger_polynomial:
- case info_flags::rational_polynomial:
- case info_flags::crational_polynomial:
- case info_flags::rational_function: {
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
- if (!(recombine_pair_to_ex(*i).info(inf)))
- return false;
- }
- return overall_coeff.info(inf);
- }
- case info_flags::algebraic: {
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
- if ((recombine_pair_to_ex(*i).info(inf)))
- return true;
- }
- return false;
- }
- }
- return inherited::info(inf);
+ switch (inf) {
+ case info_flags::polynomial:
+ case info_flags::integer_polynomial:
+ case info_flags::cinteger_polynomial:
+ case info_flags::rational_polynomial:
+ case info_flags::crational_polynomial:
+ case info_flags::rational_function: {
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+ if (!(recombine_pair_to_ex(*i).info(inf)))
+ return false;
+ }
+ return overall_coeff.info(inf);
+ }
+ case info_flags::algebraic: {
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+ if ((recombine_pair_to_ex(*i).info(inf)))
+ return true;
+ }
+ return false;
+ }
+ }
+ return inherited::info(inf);
}
int add::degree(const symbol & s) const
{
- int deg = INT_MIN;
- if (!overall_coeff.is_equal(_ex0())) {
- deg = 0;
- }
- int cur_deg;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- cur_deg=(*cit).rest.degree(s);
- if (cur_deg>deg) deg=cur_deg;
- }
- return deg;
+ int deg = INT_MIN;
+ if (!overall_coeff.is_equal(_ex0())) {
+ deg = 0;
+ }
+ int cur_deg;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ cur_deg=(*cit).rest.degree(s);
+ if (cur_deg>deg) deg=cur_deg;
+ }
+ return deg;
}
int add::ldegree(const symbol & s) const
{
- int deg = INT_MAX;
- if (!overall_coeff.is_equal(_ex0())) {
- deg = 0;
- }
- int cur_deg;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- cur_deg = (*cit).rest.ldegree(s);
- if (cur_deg<deg) deg=cur_deg;
- }
- return deg;
+ int deg = INT_MAX;
+ if (!overall_coeff.is_equal(_ex0())) {
+ deg = 0;
+ }
+ int cur_deg;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ cur_deg = (*cit).rest.ldegree(s);
+ if (cur_deg<deg) deg=cur_deg;
+ }
+ return deg;
}
ex add::coeff(const symbol & s, int n) const
{
- epvector coeffseq;
- coeffseq.reserve(seq.size());
+ epvector coeffseq;
+ coeffseq.reserve(seq.size());
- epvector::const_iterator it=seq.begin();
- while (it!=seq.end()) {
- coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
- (*it).coeff));
- ++it;
- }
- if (n==0) {
- return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
- }
- return (new add(coeffseq))->setflag(status_flags::dynallocated);
+ epvector::const_iterator it=seq.begin();
+ while (it!=seq.end()) {
+ coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
+ (*it).coeff));
+ ++it;
+ }
+ if (n==0) {
+ return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
+ }
+ return (new add(coeffseq))->setflag(status_flags::dynallocated);
}
ex add::eval(int level) const
{
- // simplifications: +(;c) -> c
- // +(x;1) -> x
+ // simplifications: +(;c) -> c
+ // +(x;1) -> x
- debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
+ debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
- epvector * evaled_seqp=evalchildren(level);
- if (evaled_seqp!=0) {
- // do more evaluation later
- return (new add(evaled_seqp,overall_coeff))->
- setflag(status_flags::dynallocated);
- }
-
+ epvector * evaled_seqp=evalchildren(level);
+ if (evaled_seqp!=0) {
+ // do more evaluation later
+ return (new add(evaled_seqp,overall_coeff))->
+ setflag(status_flags::dynallocated);
+ }
+
#ifdef DO_GINAC_ASSERT
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
- if (is_ex_exactly_of_type((*cit).rest,numeric)) {
- dbgprint();
- }
- GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
- }
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
+ if (is_ex_exactly_of_type((*cit).rest,numeric)) {
+ dbgprint();
+ }
+ GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
+ }
#endif // def DO_GINAC_ASSERT
-
- if (flags & status_flags::evaluated) {
- GINAC_ASSERT(seq.size()>0);
- GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(_ex0()));
- return *this;
- }
-
- int seq_size=seq.size();
- if (seq_size==0) {
- // +(;c) -> c
- return overall_coeff;
- } else if ((seq_size==1)&&overall_coeff.is_equal(_ex0())) {
- // +(x;0) -> x
- return recombine_pair_to_ex(*(seq.begin()));
- }
- return this->hold();
+
+ if (flags & status_flags::evaluated) {
+ GINAC_ASSERT(seq.size()>0);
+ GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(_ex0()));
+ return *this;
+ }
+
+ int seq_size=seq.size();
+ if (seq_size==0) {
+ // +(;c) -> c
+ return overall_coeff;
+ } else if ((seq_size==1)&&overall_coeff.is_equal(_ex0())) {
+ // +(x;0) -> x
+ return recombine_pair_to_ex(*(seq.begin()));
+ }
+ return this->hold();
}
exvector add::get_indices(void) const
{
- // FIXME: all terms in the sum should have the same indices (compatible
- // tensors) however this is not checked, since there is no function yet
- // which compares indices (idxvector can be unsorted)
- if (seq.size()==0) {
- return exvector();
- }
- return (seq.begin())->rest.get_indices();
+ // FIXME: all terms in the sum should have the same indices (compatible
+ // tensors) however this is not checked, since there is no function yet
+ // which compares indices (idxvector can be unsorted)
+ if (seq.size()==0) {
+ return exvector();
+ }
+ return (seq.begin())->rest.get_indices();
}
ex add::simplify_ncmul(const exvector & v) const
{
- if (seq.size()==0) {
- return inherited::simplify_ncmul(v);
- }
- return (*seq.begin()).rest.simplify_ncmul(v);
+ if (seq.size()==0) {
+ return inherited::simplify_ncmul(v);
+ }
+ return (*seq.begin()).rest.simplify_ncmul(v);
}
// protected
* @see ex::diff */
ex add::derivative(const symbol & s) const
{
- // D(a+b+c)=D(a)+D(b)+D(c)
- return (new add(diffchildren(s)))->setflag(status_flags::dynallocated);
+ // D(a+b+c)=D(a)+D(b)+D(c)
+ return (new add(diffchildren(s)))->setflag(status_flags::dynallocated);
}
int add::compare_same_type(const basic & other) const
{
- return inherited::compare_same_type(other);
+ return inherited::compare_same_type(other);
}
bool add::is_equal_same_type(const basic & other) const
{
- return inherited::is_equal_same_type(other);
+ return inherited::is_equal_same_type(other);
}
unsigned add::return_type(void) const
{
- if (seq.size()==0) {
- return return_types::commutative;
- }
- return (*seq.begin()).rest.return_type();
+ if (seq.size()==0) {
+ return return_types::commutative;
+ }
+ return (*seq.begin()).rest.return_type();
}
unsigned add::return_type_tinfo(void) const
{
- if (seq.size()==0) {
- return tinfo_key;
- }
- return (*seq.begin()).rest.return_type_tinfo();
+ if (seq.size()==0) {
+ return tinfo_key;
+ }
+ return (*seq.begin()).rest.return_type_tinfo();
}
ex add::thisexpairseq(const epvector & v, const ex & oc) const
{
- return (new add(v,oc))->setflag(status_flags::dynallocated);
+ return (new add(v,oc))->setflag(status_flags::dynallocated);
}
ex add::thisexpairseq(epvector * vp, const ex & oc) const
{
- return (new add(vp,oc))->setflag(status_flags::dynallocated);
+ return (new add(vp,oc))->setflag(status_flags::dynallocated);
}
expair add::split_ex_to_pair(const ex & e) const
{
- if (is_ex_exactly_of_type(e,mul)) {
- const mul & mulref=ex_to_mul(e);
- ex numfactor=mulref.overall_coeff;
- // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
- mul * mulcopyp=new mul(mulref);
- mulcopyp->overall_coeff=_ex1();
- mulcopyp->clearflag(status_flags::evaluated);
- mulcopyp->clearflag(status_flags::hash_calculated);
- return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
- }
- return expair(e,_ex1());
+ if (is_ex_exactly_of_type(e,mul)) {
+ const mul & mulref=ex_to_mul(e);
+ ex numfactor=mulref.overall_coeff;
+ // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
+ mul * mulcopyp=new mul(mulref);
+ mulcopyp->overall_coeff=_ex1();
+ mulcopyp->clearflag(status_flags::evaluated);
+ mulcopyp->clearflag(status_flags::hash_calculated);
+ return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
+ }
+ return expair(e,_ex1());
}
expair add::combine_ex_with_coeff_to_pair(const ex & e,
- const ex & c) const
-{
- GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
- if (is_ex_exactly_of_type(e,mul)) {
- const mul & mulref=ex_to_mul(e);
- ex numfactor=mulref.overall_coeff;
- //mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
- mul * mulcopyp=new mul(mulref);
- mulcopyp->overall_coeff=_ex1();
- mulcopyp->clearflag(status_flags::evaluated);
- mulcopyp->clearflag(status_flags::hash_calculated);
- if (are_ex_trivially_equal(c,_ex1())) {
- return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
- } else if (are_ex_trivially_equal(numfactor,_ex1())) {
- return expair(mulcopyp->setflag(status_flags::dynallocated),c);
- }
- return expair(mulcopyp->setflag(status_flags::dynallocated),
- ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c)));
- } else if (is_ex_exactly_of_type(e,numeric)) {
- if (are_ex_trivially_equal(c,_ex1())) {
- return expair(e,_ex1());
- }
- return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),_ex1());
- }
- return expair(e,c);
-}
-
+ const ex & c) const
+{
+ GINAC_ASSERT(is_ex_exactly_of_type(c, numeric));
+ ex one = _ex1();
+ if (is_ex_exactly_of_type(e, mul)) {
+ const mul &mulref = ex_to_mul(e);
+ ex numfactor = mulref.overall_coeff;
+ mul *mulcopyp = new mul(mulref);
+ mulcopyp->overall_coeff = one;
+ mulcopyp->clearflag(status_flags::evaluated);
+ mulcopyp->clearflag(status_flags::hash_calculated);
+ mulcopyp->setflag(status_flags::dynallocated);
+ if (are_ex_trivially_equal(c, one)) {
+ return expair(*mulcopyp, numfactor);
+ } else if (are_ex_trivially_equal(numfactor, one)) {
+ return expair(*mulcopyp, c);
+ }
+ return expair(*mulcopyp, ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c)));
+ } else if (is_ex_exactly_of_type(e, numeric)) {
+ if (are_ex_trivially_equal(c, one)) {
+ return expair(e, one);
+ }
+ return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)), one);
+ }
+ return expair(e, c);
+}
+
expair add::combine_pair_with_coeff_to_pair(const expair & p,
- const ex & c) const
+ const ex & c) const
{
- GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
- GINAC_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));
- if (is_ex_exactly_of_type(p.rest,numeric)) {
- GINAC_ASSERT(ex_to_numeric(p.coeff).is_equal(_num1())); // should be normalized
- return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),_ex1());
- }
+ if (is_ex_exactly_of_type(p.rest,numeric)) {
+ GINAC_ASSERT(ex_to_numeric(p.coeff).is_equal(_num1())); // should be normalized
+ return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),_ex1());
+ }
- return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
+ return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
}
-
+
ex add::recombine_pair_to_ex(const expair & p) const
{
- //if (p.coeff.compare(_ex1())==0) {
- //if (are_ex_trivially_equal(p.coeff,_ex1())) {
- if (ex_to_numeric(p.coeff).is_equal(_num1())) {
- return p.rest;
- } else {
- return p.rest*p.coeff;
- }
+ if (ex_to_numeric(p.coeff).is_equal(_num1()))
+ return p.rest;
+ else
+ return p.rest*p.coeff;
}
ex add::expand(unsigned options) const
{
- if (flags & status_flags::expanded)
- return *this;
-
- epvector * vp = expandchildren(options);
- if (vp==0)
- return *this;
-
- return (new add(vp,overall_coeff))->
- setflag(status_flags::expanded |
- status_flags::dynallocated);
+ if (flags & status_flags::expanded)
+ return *this;
+
+ epvector * vp = expandchildren(options);
+ if (vp==0)
+ return *this;
+
+ return (new add(vp,overall_coeff))->
+ setflag(status_flags::expanded |
+ status_flags::dynallocated);
}
//////////
/** Sum of expressions. */
class add : public expairseq
{
- GINAC_DECLARE_REGISTERED_CLASS(add, expairseq)
+ GINAC_DECLARE_REGISTERED_CLASS(add, expairseq)
- friend class mul;
- friend class ncmul;
- friend class power;
+ friend class mul;
+ friend class ncmul;
+ friend class power;
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- add();
- ~add();
- add(const add & other);
- const add & operator=(const add & other);
+ add();
+ ~add();
+ add(const add & other);
+ const add & operator=(const add & other);
protected:
- void copy(const add & other);
- void destroy(bool call_parent);
+ void copy(const add & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- add(const ex & lh, const ex & rh);
- add(const exvector & v);
- add(const epvector & v);
- //add(const epvector & v, bool do_not_canonicalize=0);
- add(const epvector & v, const ex & oc);
- add(epvector * vp, const ex & oc);
-
- // functions overriding virtual functions from bases classes
+ add(const ex & lh, const ex & rh);
+ add(const exvector & v);
+ add(const epvector & v);
+ //add(const epvector & v, bool do_not_canonicalize=0);
+ add(const epvector & v, const ex & oc);
+ add(epvector * vp, const ex & oc);
+
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printraw(std::ostream & os) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
- int degree(const symbol & s) const;
- int ldegree(const symbol & s) const;
- ex coeff(const symbol & s, int n=1) const;
- ex eval(int level=0) const;
- ex series(const relational & r, int order, unsigned options = 0) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
- numeric integer_content(void) const;
- ex smod(const numeric &xi) const;
- numeric max_coefficient(void) const;
- exvector get_indices(void) const;
- ex simplify_ncmul(const exvector & v) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printraw(std::ostream & os) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
+ int degree(const symbol & s) const;
+ int ldegree(const symbol & s) const;
+ ex coeff(const symbol & s, int n=1) const;
+ ex eval(int level=0) const;
+ ex series(const relational & r, int order, unsigned options = 0) const;
+ ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+ numeric integer_content(void) const;
+ ex smod(const numeric &xi) const;
+ numeric max_coefficient(void) const;
+ exvector get_indices(void) const;
+ ex simplify_ncmul(const exvector & v) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- ex thisexpairseq(const epvector & v, const ex & oc) const;
- ex thisexpairseq(epvector * vp, const ex & oc) const;
- expair split_ex_to_pair(const ex & e) const;
- expair combine_ex_with_coeff_to_pair(const ex & e,
- const ex & c) const;
- expair combine_pair_with_coeff_to_pair(const expair & p,
- const ex & c) const;
- ex recombine_pair_to_ex(const expair & p) const;
- ex expand(unsigned options=0) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
- // none
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+ ex thisexpairseq(const epvector & v, const ex & oc) const;
+ ex thisexpairseq(epvector * vp, const ex & oc) const;
+ expair split_ex_to_pair(const ex & e) const;
+ expair combine_ex_with_coeff_to_pair(const ex & e,
+ const ex & c) const;
+ expair combine_pair_with_coeff_to_pair(const expair & p,
+ const ex & c) const;
+ ex recombine_pair_to_ex(const expair & p) const;
+ ex expand(unsigned options=0) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
+ // none
// member variables
protected:
- static unsigned precedence;
+ static unsigned precedence;
};
// global constants
write_unsigned(os, n.props[i].type | (n.props[i].name << 3));
write_unsigned(os, n.props[i].value);
}
- return os;
+ return os;
}
/** Write archive to binary data stream. */
write_unsigned(os, num_nodes);
for (unsigned int i=0; i<num_nodes; i++)
os << ar.nodes[i];
- return os;
+ return os;
}
/** Read archive_node from binary data stream. */
n.props[i].name = name_type >> 3;
n.props[i].value = read_unsigned(is);
}
- return is;
+ return is;
}
/** Read archive from binary data stream. */
ar.nodes.resize(num_nodes, ar);
for (unsigned int i=0; i<num_nodes; i++)
is >> ar.nodes[i];
- return is;
+ return is;
}
* ctor, which is currently a Cint-requirement. */
archive* archive_node::dummy_ar_creator(void)
{
- static archive* some_ar = new archive;
- return some_ar;
+ static archive* some_ar = new archive;
+ return some_ar;
}
#include <vector>
namespace std {
- class ostream;
- class istream;
+ class ostream;
+ class istream;
}
#ifndef NO_NAMESPACE_GINAC
#ifndef INLINE_BASIC_CONSTRUCTORS
basic::basic() : flags(0), refcount(0), tinfo_key(TINFO_BASIC)
{
- debugmsg("basic default constructor", LOGLEVEL_CONSTRUCT);
- // nothing to do
+ debugmsg("basic default constructor", LOGLEVEL_CONSTRUCT);
+ // nothing to do
}
basic::~basic()
{
- debugmsg("basic destructor", LOGLEVEL_DESTRUCT);
- destroy(0);
- GINAC_ASSERT((!(flags & status_flags::dynallocated))||(refcount==0));
+ debugmsg("basic destructor", LOGLEVEL_DESTRUCT);
+ destroy(0);
+ GINAC_ASSERT((!(flags & status_flags::dynallocated))||(refcount==0));
}
basic::basic(const basic & other) : flags(0), refcount(0), tinfo_key(TINFO_BASIC)
{
- debugmsg("basic copy constructor", LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("basic copy constructor", LOGLEVEL_CONSTRUCT);
+ copy(other);
}
#endif
const basic & basic::operator=(const basic & other)
{
- debugmsg("basic operator=", LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("basic operator=", LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
#ifndef INLINE_BASIC_CONSTRUCTORS
basic::basic(unsigned ti) : flags(0), refcount(0), tinfo_key(ti)
{
- debugmsg("basic constructor with tinfo_key", LOGLEVEL_CONSTRUCT);
- // nothing to do
+ debugmsg("basic constructor with tinfo_key", LOGLEVEL_CONSTRUCT);
+ // nothing to do
}
#endif
/** Construct object from archive_node. */
basic::basic(const archive_node &n, const lst &sym_lst) : flags(0), refcount(0)
{
- debugmsg("basic constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ debugmsg("basic constructor from archive_node", LOGLEVEL_CONSTRUCT);
- // Reconstruct tinfo_key from class name
- std::string class_name;
- if (n.find_string("class", class_name))
- tinfo_key = find_tinfo_key(class_name);
- else
- throw (std::runtime_error("archive node contains no class name"));
+ // Reconstruct tinfo_key from class name
+ std::string class_name;
+ if (n.find_string("class", class_name))
+ tinfo_key = find_tinfo_key(class_name);
+ else
+ throw (std::runtime_error("archive node contains no class name"));
}
/** Unarchive the object. */
ex basic::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new basic(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new basic(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void basic::archive(archive_node &n) const
{
- n.add_string("class", class_name());
+ n.add_string("class", class_name());
}
//////////
/** Output to stream formatted to be useful as ginsh input. */
void basic::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("basic print",LOGLEVEL_PRINT);
- os << "[basic object]";
+ debugmsg("basic print",LOGLEVEL_PRINT);
+ os << "[basic object]";
}
/** Output to stream in ugly raw format, so brave developers can have a look
* at the underlying structure. */
void basic::printraw(std::ostream & os) const
{
- debugmsg("basic printraw",LOGLEVEL_PRINT);
- os << "[basic object]";
+ debugmsg("basic printraw",LOGLEVEL_PRINT);
+ os << "[basic object]";
}
/** Output to stream formatted in tree- (indented-) form, so developers can
* have a look at the underlying structure. */
void basic::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("basic printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "type=" << typeid(*this).name()
- << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags
- << ", nops=" << nops() << std::endl;
- for (unsigned i=0; i<nops(); ++i) {
- op(i).printtree(os,indent+delta_indent);
- }
+ debugmsg("basic printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << "type=" << class_name()
+ << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags
+ << ", nops=" << nops() << std::endl;
+ for (unsigned i=0; i<nops(); ++i) {
+ op(i).printtree(os,indent+delta_indent);
+ }
}
/** Output to stream formatted as C-source.
* @see ex::printcsrc */
void basic::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("basic print csrc", LOGLEVEL_PRINT);
+ debugmsg("basic print csrc", LOGLEVEL_PRINT);
}
/** Little wrapper arount print to be called within a debugger. */
void basic::dbgprint(void) const
{
- print(std::cerr);
- std::cerr << std::endl;
+ print(std::cerr);
+ std::cerr << std::endl;
}
/** Little wrapper arount printtree to be called within a debugger. */
void basic::dbgprinttree(void) const
{
- printtree(std::cerr,0);
+ printtree(std::cerr,0);
}
basic * basic::duplicate() const
{
- debugmsg("basic duplicate",LOGLEVEL_DUPLICATE);
- return new basic(*this);
+ debugmsg("basic duplicate",LOGLEVEL_DUPLICATE);
+ return new basic(*this);
}
/** Information about the object.
* @see class info_flags */
bool basic::info(unsigned inf) const
{
- return false; // all possible properties are false for basic objects
+ return false; // all possible properties are false for basic objects
}
/** Number of operands/members. */
unsigned basic::nops() const
{
- // iterating from 0 to nops() on atomic objects should be an empty loop,
- // and accessing their elements is a range error. Container objects should
- // override this.
- return 0;
+ // iterating from 0 to nops() on atomic objects should be an empty loop,
+ // and accessing their elements is a range error. Container objects should
+ // override this.
+ return 0;
}
/** Return operand/member at position i. */
ex basic::op(int i) const
{
- return (const_cast<basic *>(this))->let_op(i);
+ return (const_cast<basic *>(this))->let_op(i);
}
/** Return modifyable operand/member at position i. */
ex & basic::let_op(int i)
{
- throw(std::out_of_range("op() out of range"));
+ throw(std::out_of_range("op() out of range"));
}
ex basic::operator[](const ex & index) const
{
- if (is_exactly_of_type(*index.bp,numeric))
- return op(static_cast<const numeric &>(*index.bp).to_int());
-
- throw(std::invalid_argument("non-numeric indices not supported by this type"));
+ if (is_exactly_of_type(*index.bp,numeric))
+ return op(static_cast<const numeric &>(*index.bp).to_int());
+
+ throw(std::invalid_argument("non-numeric indices not supported by this type"));
}
ex basic::operator[](int i) const
{
- return op(i);
+ return op(i);
}
/** Search ocurrences. An object 'has' an expression if it is the expression
* itself or one of the children 'has' it. */
bool basic::has(const ex & other) const
{
- GINAC_ASSERT(other.bp!=0);
- if (is_equal(*other.bp)) return true;
- if (nops()>0) {
- for (unsigned i=0; i<nops(); i++) {
- if (op(i).has(other)) return true;
- }
- }
- return false;
+ GINAC_ASSERT(other.bp!=0);
+ if (is_equal(*other.bp)) return true;
+ if (nops()>0) {
+ for (unsigned i=0; i<nops(); i++) {
+ if (op(i).has(other)) return true;
+ }
+ }
+ return false;
}
/** Return degree of highest power in symbol s. */
int basic::degree(const symbol & s) const
{
- return 0;
+ return 0;
}
/** Return degree of lowest power in symbol s. */
int basic::ldegree(const symbol & s) const
{
- return 0;
+ return 0;
}
/** Return coefficient of degree n in symbol s. */
ex basic::coeff(const symbol & s, int n) const
{
- return n==0 ? *this : _ex0();
+ return n==0 ? *this : _ex0();
}
/** Sort expression in terms of powers of some symbol.
* @param s symbol to sort in. */
ex basic::collect(const symbol & s) const
{
- ex x;
- int ldeg = this->ldegree(s);
- int deg = this->degree(s);
- for (int n=ldeg; n<=deg; n++) {
- x += this->coeff(s,n)*power(s,n);
- }
- return x;
+ ex x;
+ int ldeg = this->ldegree(s);
+ int deg = this->degree(s);
+ for (int n=ldeg; n<=deg; n++) {
+ x += this->coeff(s,n)*power(s,n);
+ }
+ return x;
}
/* Perform automatic symbolic evaluations on expression. */
ex basic::eval(int level) const
{
- // There is nothing to do for basic objects:
- return this->hold();
+ // There is nothing to do for basic objects:
+ return this->hold();
}
/** Evaluate object numerically. */
ex basic::evalf(int level) const
{
- // There is nothing to do for basic objects:
- return *this;
+ // There is nothing to do for basic objects:
+ return *this;
}
/* Substitute a set of symbols. */
ex basic::subs(const lst & ls, const lst & lr) const
{
- return *this;
+ return *this;
}
/** Default interface of nth derivative ex::diff(s, n). It should be called
* @see ex::diff */
ex basic::diff(const symbol & s, unsigned nth) const
{
- // trivial: zeroth derivative
- if (nth==0)
- return ex(*this);
-
- // evaluate unevaluated *this before differentiating
- if (!(flags & status_flags::evaluated))
- return ex(*this).diff(s, nth);
-
- ex ndiff = this->derivative(s);
- while (!ndiff.is_zero() && // stop differentiating zeros
- nth>1) {
- ndiff = ndiff.diff(s);
- --nth;
- }
- return ndiff;
+ // trivial: zeroth derivative
+ if (nth==0)
+ return ex(*this);
+
+ // evaluate unevaluated *this before differentiating
+ if (!(flags & status_flags::evaluated))
+ return ex(*this).diff(s, nth);
+
+ ex ndiff = this->derivative(s);
+ while (!ndiff.is_zero() && // stop differentiating zeros
+ nth>1) {
+ ndiff = ndiff.diff(s);
+ --nth;
+ }
+ return ndiff;
}
exvector basic::get_indices(void) const
{
- return exvector(); // return an empty exvector
+ return exvector(); // return an empty exvector
}
ex basic::simplify_ncmul(const exvector & v) const
{
- return simplified_ncmul(v);
+ return simplified_ncmul(v);
}
// protected
* @see ex::diff */
ex basic::derivative(const symbol & s) const
{
- throw(std::logic_error("differentiation not supported by this type"));
+ throw(std::logic_error("differentiation not supported by this type"));
}
/** Returns order relation between two objects of same type. Needs to be
* implemented by each class. */
int basic::compare_same_type(const basic & other) const
{
- return compare_pointers(this, &other);
+ return compare_pointers(this, &other);
}
/** Returns true if two objects of same type are equal. Normally needs
* class, since it just calls complare_same_type(). */
bool basic::is_equal_same_type(const basic & other) const
{
- return compare_same_type(other)==0;
+ return compare_same_type(other)==0;
}
unsigned basic::return_type(void) const
{
- return return_types::commutative;
+ return return_types::commutative;
}
unsigned basic::return_type_tinfo(void) const
{
- return tinfo();
+ return tinfo();
}
unsigned basic::calchash(void) const
{
- unsigned v=golden_ratio_hash(tinfo());
- for (unsigned i=0; i<nops(); i++) {
- v=rotate_left_31(v);
- v ^= (const_cast<basic *>(this))->op(i).gethash();
- }
+ unsigned v=golden_ratio_hash(tinfo());
+ for (unsigned i=0; i<nops(); i++) {
+ v=rotate_left_31(v);
+ v ^= (const_cast<basic *>(this))->op(i).gethash();
+ }
- v = v & 0x7FFFFFFFU;
-
- // store calculated hash value only if object is already evaluated
- if (flags & status_flags::evaluated) {
- setflag(status_flags::hash_calculated);
- hashvalue=v;
- }
+ v = v & 0x7FFFFFFFU;
+
+ // store calculated hash value only if object is already evaluated
+ if (flags & status_flags::evaluated) {
+ setflag(status_flags::hash_calculated);
+ hashvalue=v;
+ }
- return v;
+ return v;
}
/** Expand expression, i.e. multiply it out and return the result as a new
* expression. */
ex basic::expand(unsigned options) const
{
- return this->setflag(status_flags::expanded);
+ return this->setflag(status_flags::expanded);
}
* In addition, an object of class idx can be used instead of a symbol. */
ex basic::subs(const ex & e) const
{
- if (e.info(info_flags::relation_equal)) {
- return subs(lst(e));
- }
- if (!e.info(info_flags::list)) {
- throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
- }
- lst ls;
- lst lr;
- for (unsigned i=0; i<e.nops(); i++) {
- if (!e.op(i).info(info_flags::relation_equal)) {
- throw(std::invalid_argument("basic::subs(ex): argument must be a list or equations"));
- }
- if (!e.op(i).op(0).info(info_flags::symbol)) {
- if (!e.op(i).op(0).info(info_flags::idx)) {
- throw(std::invalid_argument("basic::subs(ex): lhs must be a symbol or an idx"));
- }
- }
- ls.append(e.op(i).op(0));
- lr.append(e.op(i).op(1));
- }
- return subs(ls,lr);
+ if (e.info(info_flags::relation_equal)) {
+ return subs(lst(e));
+ }
+ if (!e.info(info_flags::list)) {
+ throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
+ }
+ lst ls;
+ lst lr;
+ for (unsigned i=0; i<e.nops(); i++) {
+ if (!e.op(i).info(info_flags::relation_equal)) {
+ throw(std::invalid_argument("basic::subs(ex): argument must be a list or equations"));
+ }
+ if (!e.op(i).op(0).info(info_flags::symbol)) {
+ if (!e.op(i).op(0).info(info_flags::idx)) {
+ throw(std::invalid_argument("basic::subs(ex): lhs must be a symbol or an idx"));
+ }
+ }
+ ls.append(e.op(i).op(0));
+ lr.append(e.op(i).op(1));
+ }
+ return subs(ls,lr);
}
/** Compare objects to establish canonical order.
* 1 greater. */
int basic::compare(const basic & other) const
{
- unsigned hash_this = gethash();
- unsigned hash_other = other.gethash();
-
- if (hash_this<hash_other) return -1;
- if (hash_this>hash_other) return 1;
-
- unsigned typeid_this = tinfo();
- unsigned typeid_other = other.tinfo();
-
- if (typeid_this<typeid_other) {
- /*
- cout << "hash collision, different types: "
- << *this << " and " << other << endl;
- this->printraw(cout);
- cout << " and ";
- other.printraw(cout);
- cout << endl;
- */
- return -1;
- }
- if (typeid_this>typeid_other) {
- /*
- cout << "hash collision, different types: "
- << *this << " and " << other << endl;
- this->printraw(cout);
- cout << " and ";
- other.printraw(cout);
- cout << endl;
- */
- return 1;
- }
-
- GINAC_ASSERT(typeid(*this)==typeid(other));
-
- int cmpval=compare_same_type(other);
- if ((cmpval!=0)&&(hash_this<0x80000000U)) {
- /*
- cout << "hash collision, same type: "
- << *this << " and " << other << endl;
- this->printraw(cout);
- cout << " and ";
- other.printraw(cout);
- cout << endl;
- */
- }
- return cmpval;
+ unsigned hash_this = gethash();
+ unsigned hash_other = other.gethash();
+
+ if (hash_this<hash_other) return -1;
+ if (hash_this>hash_other) return 1;
+
+ unsigned typeid_this = tinfo();
+ unsigned typeid_other = other.tinfo();
+
+ if (typeid_this<typeid_other) {
+ /*
+ cout << "hash collision, different types: "
+ << *this << " and " << other << endl;
+ this->printraw(cout);
+ cout << " and ";
+ other.printraw(cout);
+ cout << endl;
+ */
+ return -1;
+ }
+ if (typeid_this>typeid_other) {
+ /*
+ cout << "hash collision, different types: "
+ << *this << " and " << other << endl;
+ this->printraw(cout);
+ cout << " and ";
+ other.printraw(cout);
+ cout << endl;
+ */
+ return 1;
+ }
+
+ GINAC_ASSERT(typeid(*this)==typeid(other));
+
+ int cmpval=compare_same_type(other);
+ if ((cmpval!=0)&&(hash_this<0x80000000U)) {
+ /*
+ cout << "hash collision, same type: "
+ << *this << " and " << other << endl;
+ this->printraw(cout);
+ cout << " and ";
+ other.printraw(cout);
+ cout << endl;
+ */
+ }
+ return cmpval;
}
/** Test for equality. */
bool basic::is_equal(const basic & other) const
{
- unsigned hash_this = gethash();
- unsigned hash_other = other.gethash();
+ unsigned hash_this = gethash();
+ unsigned hash_other = other.gethash();
- if (hash_this!=hash_other) return false;
+ if (hash_this!=hash_other) return false;
- unsigned typeid_this = tinfo();
- unsigned typeid_other = other.tinfo();
+ unsigned typeid_this = tinfo();
+ unsigned typeid_other = other.tinfo();
- if (typeid_this!=typeid_other) return false;
+ if (typeid_this!=typeid_other) return false;
- GINAC_ASSERT(typeid(*this)==typeid(other));
+ GINAC_ASSERT(typeid(*this)==typeid(other));
- return is_equal_same_type(other);
+ return is_equal_same_type(other);
}
// protected
* @see basic::eval */
const basic & basic::hold(void) const
{
- return setflag(status_flags::evaluated);
+ return setflag(status_flags::evaluated);
}
void basic::ensure_if_modifiable(void) const
{
- if (refcount>1) {
- throw(std::runtime_error("cannot modify multiply referenced object"));
- }
+ if (refcount>1) {
+ throw(std::runtime_error("cannot modify multiply referenced object"));
+ }
}
//////////
* It is responsible for the reference counting. */
class basic
{
- GINAC_DECLARE_REGISTERED_CLASS(basic, void)
+ GINAC_DECLARE_REGISTERED_CLASS(basic, void)
- friend class ex;
+ friend class ex;
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- basic()
+ basic()
#ifdef INLINE_BASIC_CONSTRUCTORS
- : tinfo_key(TINFO_basic), flags(0), refcount(0)
- {
- }
+ : tinfo_key(TINFO_basic), flags(0), refcount(0)
+ {
+ }
#else
;
#endif // def INLINE_BASIC_CONSTRUCTORS
- virtual ~basic()
+ virtual ~basic()
#ifdef INLINE_BASIC_CONSTRUCTORS
- {
- destroy(0);
- GINAC_ASSERT((!(flags & status_flags::dynallocated))||(refcount==0));
- }
+ {
+ destroy(0);
+ GINAC_ASSERT((!(flags & status_flags::dynallocated))||(refcount==0));
+ }
#else
;
#endif // def INLINE_BASIC_CONSTRUCTORS
- basic(const basic & other)
+ basic(const basic & other)
#ifdef INLINE_BASIC_CONSTRUCTORS
- {
- copy(other);
- }
+ {
+ copy(other);
+ }
#else
;
#endif // def INLINE_BASIC_CONSTRUCTORS
- virtual const basic & operator=(const basic & other);
-
+ virtual const basic & operator=(const basic & other);
+
protected:
- void copy(const basic & other)
- {
- flags = other.flags & ~status_flags::dynallocated;
- hashvalue = other.hashvalue;
- tinfo_key = other.tinfo_key;
- }
- void destroy(bool call_parent) {}
-
- // other constructors
- basic(unsigned ti)
+ void copy(const basic & other)
+ {
+ flags = other.flags & ~status_flags::dynallocated;
+ hashvalue = other.hashvalue;
+ tinfo_key = other.tinfo_key;
+ }
+ void destroy(bool call_parent) {}
+
+ // other constructors
+ basic(unsigned ti)
#ifdef INLINE_BASIC_CONSTRUCTORS
- : tinfo_key(ti), flags(0), refcount(0)
- {
- }
+ : tinfo_key(ti), flags(0), refcount(0)
+ {
+ }
#else
;
#endif // def INLINE_BASIC_CONSTRUCTORS
- // functions overriding virtual functions from bases classes
- // none
-
- // new virtual functions which can be overridden by derived classes
+ // functions overriding virtual functions from bases classes
+ // none
+
+ // new virtual functions which can be overridden by derived classes
public: // only const functions please (may break reference counting)
- virtual basic * duplicate() const;
- virtual void print(std::ostream & os,unsigned upper_precedence = 0) const;
- virtual void printraw(std::ostream & os) const;
- virtual void printtree(std::ostream & os, unsigned indent) const;
- virtual void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence = 0) const;
- virtual void dbgprint(void) const;
- virtual void dbgprinttree(void) const;
- virtual bool info(unsigned inf) const;
- virtual unsigned nops() const;
- virtual ex op(int i) const;
- virtual ex & let_op(int i);
- virtual ex operator[](const ex & index) const;
- virtual ex operator[](int i) const;
- virtual bool has(const ex & other) const;
- virtual int degree(const symbol & s) const;
- virtual int ldegree(const symbol & s) const;
- virtual ex coeff(const symbol & s, int n = 1) const;
- virtual ex collect(const symbol & s) const;
- virtual ex eval(int level = 0) const;
- virtual ex evalf(int level = 0) const;
- virtual ex series(const relational & r, int order, unsigned options = 0) const;
- virtual ex subs(const lst & ls, const lst & lr) const;
- virtual ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
- virtual ex to_rational(lst &repl_lst) const;
- virtual numeric integer_content(void) const;
- virtual ex smod(const numeric &xi) const;
- virtual numeric max_coefficient(void) const;
- virtual exvector get_indices(void) const;
- virtual ex simplify_ncmul(const exvector & v) const;
+ virtual basic * duplicate() const;
+ virtual void print(std::ostream & os,unsigned upper_precedence = 0) const;
+ virtual void printraw(std::ostream & os) const;
+ virtual void printtree(std::ostream & os, unsigned indent) const;
+ virtual void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence = 0) const;
+ virtual void dbgprint(void) const;
+ virtual void dbgprinttree(void) const;
+ virtual bool info(unsigned inf) const;
+ virtual unsigned nops() const;
+ virtual ex op(int i) const;
+ virtual ex & let_op(int i);
+ virtual ex operator[](const ex & index) const;
+ virtual ex operator[](int i) const;
+ virtual bool has(const ex & other) const;
+ virtual int degree(const symbol & s) const;
+ virtual int ldegree(const symbol & s) const;
+ virtual ex coeff(const symbol & s, int n = 1) const;
+ virtual ex collect(const symbol & s) const;
+ virtual ex eval(int level = 0) const;
+ virtual ex evalf(int level = 0) const;
+ virtual ex series(const relational & r, int order, unsigned options = 0) const;
+ virtual ex subs(const lst & ls, const lst & lr) const;
+ virtual ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
+ virtual ex to_rational(lst &repl_lst) const;
+ virtual numeric integer_content(void) const;
+ virtual ex smod(const numeric &xi) const;
+ virtual numeric max_coefficient(void) const;
+ virtual exvector get_indices(void) const;
+ virtual ex simplify_ncmul(const exvector & v) const;
protected: // non-const functions should be called from class ex only
- virtual ex derivative(const symbol & s) const;
- virtual int compare_same_type(const basic & other) const;
- virtual bool is_equal_same_type(const basic & other) const;
- virtual unsigned return_type(void) const;
- virtual unsigned return_type_tinfo(void) const;
- virtual unsigned calchash(void) const;
- virtual ex expand(unsigned options=0) const;
-
- // non-virtual functions in this class
+ virtual ex derivative(const symbol & s) const;
+ virtual int compare_same_type(const basic & other) const;
+ virtual bool is_equal_same_type(const basic & other) const;
+ virtual unsigned return_type(void) const;
+ virtual unsigned return_type_tinfo(void) const;
+ virtual unsigned calchash(void) const;
+ virtual ex expand(unsigned options=0) const;
+
+ // non-virtual functions in this class
public:
- ex subs(const ex & e) const;
- ex diff(const symbol & s, unsigned nth=1) const;
- int compare(const basic & other) const;
- bool is_equal(const basic & other) const;
- const basic & hold(void) const;
- unsigned gethash(void) const {if (flags & status_flags::hash_calculated) return hashvalue; else return calchash();}
- unsigned tinfo(void) const {return tinfo_key;}
- const basic & setflag(unsigned f) const {flags |= f; return *this;}
- const basic & clearflag(unsigned f) const {flags &= ~f; return *this;}
+ ex subs(const ex & e) const;
+ ex diff(const symbol & s, unsigned nth=1) const;
+ int compare(const basic & other) const;
+ bool is_equal(const basic & other) const;
+ const basic & hold(void) const;
+ unsigned gethash(void) const {if (flags & status_flags::hash_calculated) return hashvalue; else return calchash();}
+ unsigned tinfo(void) const {return tinfo_key;}
+ const basic & setflag(unsigned f) const {flags |= f; return *this;}
+ const basic & clearflag(unsigned f) const {flags &= ~f; return *this;}
protected:
- void ensure_if_modifiable(void) const;
+ void ensure_if_modifiable(void) const;
// member variables
-
+
protected:
- unsigned tinfo_key;
- mutable unsigned flags;
- mutable unsigned hashvalue;
- static unsigned precedence;
- static unsigned delta_indent;
+ unsigned tinfo_key;
+ mutable unsigned flags;
+ mutable unsigned hashvalue;
+ static unsigned precedence;
+ static unsigned delta_indent;
private:
- unsigned refcount;
+ unsigned refcount;
};
// global constants
#ifndef NO_NAMESPACE_GINAC
#define is_of_type(OBJ,TYPE) \
- (dynamic_cast<TYPE *>(const_cast<GiNaC::basic *>(&OBJ))!=0)
+ (dynamic_cast<TYPE *>(const_cast<GiNaC::basic *>(&OBJ))!=0)
#define is_exactly_of_type(OBJ,TYPE) \
- ((OBJ).tinfo()==GiNaC::TINFO_##TYPE)
+ ((OBJ).tinfo()==GiNaC::TINFO_##TYPE)
#define is_ex_of_type(OBJ,TYPE) \
- (dynamic_cast<TYPE *>(const_cast<GiNaC::basic *>((OBJ).bp))!=0)
+ (dynamic_cast<TYPE *>(const_cast<GiNaC::basic *>((OBJ).bp))!=0)
#define is_ex_exactly_of_type(OBJ,TYPE) \
- ((*(OBJ).bp).tinfo()==GiNaC::TINFO_##TYPE)
+ ((*(OBJ).bp).tinfo()==GiNaC::TINFO_##TYPE)
#else // ndef NO_NAMESPACE_GINAC
#define is_of_type(OBJ,TYPE) \
- (dynamic_cast<TYPE *>(const_cast<basic *>(&OBJ))!=0)
+ (dynamic_cast<TYPE *>(const_cast<basic *>(&OBJ))!=0)
#define is_exactly_of_type(OBJ,TYPE) \
- ((OBJ).tinfo()==TINFO_##TYPE)
+ ((OBJ).tinfo()==TINFO_##TYPE)
#define is_ex_of_type(OBJ,TYPE) \
- (dynamic_cast<TYPE *>(const_cast<basic *>((OBJ).bp))!=0)
+ (dynamic_cast<TYPE *>(const_cast<basic *>((OBJ).bp))!=0)
#define is_ex_exactly_of_type(OBJ,TYPE) \
- ((*(OBJ).bp).tinfo()==TINFO_##TYPE)
+ ((*(OBJ).bp).tinfo()==TINFO_##TYPE)
#endif // ndef NO_NAMESPACE_GINAC
clifford::clifford()
{
- debugmsg("clifford default constructor",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- name=autoname_prefix()+ToString(serial);
- tinfo_key=TINFO_clifford;
+ debugmsg("clifford default constructor",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ name=autoname_prefix()+ToString(serial);
+ tinfo_key=TINFO_clifford;
}
clifford::~clifford()
{
- debugmsg("clifford destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("clifford destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
clifford::clifford(const clifford & other)
{
- debugmsg("clifford copy constructor",LOGLEVEL_CONSTRUCT);
- copy (other);
+ debugmsg("clifford copy constructor",LOGLEVEL_CONSTRUCT);
+ copy (other);
}
const clifford & clifford::operator=(const clifford & other)
{
- debugmsg("clifford operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("clifford operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void clifford::copy(const clifford & other)
{
- indexed::copy(other);
- name=other.name;
- serial=other.serial;
+ indexed::copy(other);
+ name=other.name;
+ serial=other.serial;
}
void clifford::destroy(bool call_parent)
{
- if (call_parent) {
- indexed::destroy(call_parent);
- }
+ if (call_parent) {
+ indexed::destroy(call_parent);
+ }
}
//////////
clifford::clifford(const std::string & initname)
{
- debugmsg("clifford constructor from string",LOGLEVEL_CONSTRUCT);
- name=initname;
- serial=next_serial++;
- tinfo_key=TINFO_clifford;
+ debugmsg("clifford constructor from string",LOGLEVEL_CONSTRUCT);
+ name=initname;
+ serial=next_serial++;
+ tinfo_key=TINFO_clifford;
}
//////////
basic * clifford::duplicate() const
{
- debugmsg("clifford duplicate",LOGLEVEL_DUPLICATE);
- return new clifford(*this);
+ debugmsg("clifford duplicate",LOGLEVEL_DUPLICATE);
+ return new clifford(*this);
}
void clifford::printraw(std::ostream & os) const
{
- debugmsg("clifford printraw",LOGLEVEL_PRINT);
- os << "clifford(" << "name=" << name << ",serial=" << serial
- << ",indices=";
- printrawindices(os);
- os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+ debugmsg("clifford printraw",LOGLEVEL_PRINT);
+ os << "clifford(" << "name=" << name << ",serial=" << serial
+ << ",indices=";
+ printrawindices(os);
+ os << ",hash=" << hashvalue << ",flags=" << flags << ")";
}
void clifford::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("clifford printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << name << " (clifford): "
- << "serial=" << serial << ","
- << seq.size() << "indices=";
- printtreeindices(os, indent);
- os << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("clifford printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << name << " (clifford): "
+ << "serial=" << serial << ","
+ << seq.size() << "indices=";
+ printtreeindices(os, indent);
+ os << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void clifford::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("clifford print",LOGLEVEL_PRINT);
- os << name;
- printindices(os);
+ debugmsg("clifford print",LOGLEVEL_PRINT);
+ os << name;
+ printindices(os);
}
void clifford::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("clifford print csrc",LOGLEVEL_PRINT);
- print(os,upper_precedence);
+ debugmsg("clifford print csrc",LOGLEVEL_PRINT);
+ print(os,upper_precedence);
}
bool clifford::info(unsigned inf) const
{
- return indexed::info(inf);
+ return indexed::info(inf);
}
// protected
int clifford::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(other.tinfo() == TINFO_clifford);
- const clifford *o = static_cast<const clifford *>(&other);
- if (serial==o->serial) {
- return indexed::compare_same_type(other);
- }
- return serial < o->serial ? -1 : 1;
+ GINAC_ASSERT(other.tinfo() == TINFO_clifford);
+ const clifford *o = static_cast<const clifford *>(&other);
+ if (serial==o->serial) {
+ return indexed::compare_same_type(other);
+ }
+ return serial < o->serial ? -1 : 1;
}
ex clifford::simplify_ncmul(const exvector & v) const
{
- return simplified_ncmul(v);
+ return simplified_ncmul(v);
}
unsigned clifford::calchash(void) const
{
- hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555556U ^
- golden_ratio_hash(tinfo_key) ^
- serial));
- setflag(status_flags::hash_calculated);
- return hashvalue;
+ hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555556U ^
+ golden_ratio_hash(tinfo_key) ^
+ serial));
+ setflag(status_flags::hash_calculated);
+ return hashvalue;
}
//////////
void clifford::setname(const std::string & n)
{
- name = n;
+ name = n;
}
// private
std::string & clifford::autoname_prefix(void)
{
- static std::string * s = new std::string("clifford");
- return *s;
+ static std::string * s = new std::string("clifford");
+ return *s;
}
//////////
{
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- clifford();
- ~clifford();
- clifford(const clifford & other);
- const clifford & operator=(const clifford & other);
+ clifford();
+ ~clifford();
+ clifford(const clifford & other);
+ const clifford & operator=(const clifford & other);
protected:
- void copy(const clifford & other);
- void destroy(bool call_parent);
+ void copy(const clifford & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- explicit clifford(const std::string & initname);
+ explicit clifford(const std::string & initname);
- // functions overriding virtual functions from base classes
+ // functions overriding virtual functions from base classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
protected:
- int compare_same_type(const basic & other) const;
- ex simplify_ncmul(const exvector & v) const;
- unsigned calchash(void) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ int compare_same_type(const basic & other) const;
+ ex simplify_ncmul(const exvector & v) const;
+ unsigned calchash(void) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
public:
- void setname(const std::string & n);
+ void setname(const std::string & n);
private:
- std::string & autoname_prefix(void);
+ std::string & autoname_prefix(void);
// member variables
protected:
- std::string name;
- unsigned serial; // unique serial number for comparision
+ std::string name;
+ unsigned serial; // unique serial number for comparision
private:
- static unsigned next_serial;
+ static unsigned next_serial;
};
// global constants
color::color() : type(invalid), representation_label(0)
{
- debugmsg("color default constructor",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_color;
+ debugmsg("color default constructor",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_color;
}
color::~color()
{
- debugmsg("color destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("color destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
color::color(const color & other)
{
- debugmsg("color copy constructor",LOGLEVEL_CONSTRUCT);
- copy (other);
+ debugmsg("color copy constructor",LOGLEVEL_CONSTRUCT);
+ copy (other);
}
const color & color::operator=(const color & other)
{
- debugmsg("color operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("color operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void color::copy(const color & other)
{
- inherited::copy(other);
- type=other.type;
- representation_label=other.representation_label;
+ inherited::copy(other);
+ type=other.type;
+ representation_label=other.representation_label;
}
void color::destroy(bool call_parent)
{
- if (call_parent) {
- inherited::destroy(call_parent);
- }
+ if (call_parent) {
+ inherited::destroy(call_parent);
+ }
}
//////////
color::color(color_types const t, unsigned rl) : type(t), representation_label(rl)
{
- debugmsg("color constructor from color_types,unsigned",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
- tinfo_key=TINFO_color;
- GINAC_ASSERT(all_of_type_coloridx());
+ debugmsg("color constructor from color_types,unsigned",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+ tinfo_key=TINFO_color;
+ GINAC_ASSERT(all_of_type_coloridx());
}
color::color(color_types const t, const ex & i1, unsigned rl)
- : inherited(i1), type(t), representation_label(rl)
+ : inherited(i1), type(t), representation_label(rl)
{
- debugmsg("color constructor from color_types,ex,unsigned",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
- tinfo_key=TINFO_color;
- GINAC_ASSERT(all_of_type_coloridx());
+ debugmsg("color constructor from color_types,ex,unsigned",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+ tinfo_key=TINFO_color;
+ GINAC_ASSERT(all_of_type_coloridx());
}
color::color(color_types const t, const ex & i1, const ex & i2, unsigned rl)
- : inherited(i1,i2), type(t), representation_label(rl)
+ : inherited(i1,i2), type(t), representation_label(rl)
{
- debugmsg("color constructor from color_types,ex,ex,unsigned",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
- tinfo_key=TINFO_color;
- GINAC_ASSERT(all_of_type_coloridx());
+ debugmsg("color constructor from color_types,ex,ex,unsigned",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+ tinfo_key=TINFO_color;
+ GINAC_ASSERT(all_of_type_coloridx());
}
color::color(color_types const t, const ex & i1, const ex & i2, const ex & i3,
- unsigned rl) : inherited(i1,i2,i3), type(t), representation_label(rl)
+ unsigned rl) : inherited(i1,i2,i3), type(t), representation_label(rl)
{
- debugmsg("color constructor from color_types,ex,ex,ex,unsigned",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
- tinfo_key=TINFO_color;
- GINAC_ASSERT(all_of_type_coloridx());
+ debugmsg("color constructor from color_types,ex,ex,ex,unsigned",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+ tinfo_key=TINFO_color;
+ GINAC_ASSERT(all_of_type_coloridx());
}
color::color(color_types const t, const exvector & iv, unsigned rl)
- : inherited(iv), type(t), representation_label(rl)
+ : inherited(iv), type(t), representation_label(rl)
{
- debugmsg("color constructor from color_types,exvector,unsigned",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
- tinfo_key=TINFO_color;
- GINAC_ASSERT(all_of_type_coloridx());
+ debugmsg("color constructor from color_types,exvector,unsigned",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+ tinfo_key=TINFO_color;
+ GINAC_ASSERT(all_of_type_coloridx());
}
color::color(color_types const t, exvector * ivp, unsigned rl)
- : inherited(ivp), type(t), representation_label(rl)
+ : inherited(ivp), type(t), representation_label(rl)
{
- debugmsg("color constructor from color_types,exvector *,unsigned",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
- tinfo_key=TINFO_color;
- GINAC_ASSERT(all_of_type_coloridx());
+ debugmsg("color constructor from color_types,exvector *,unsigned",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+ tinfo_key=TINFO_color;
+ GINAC_ASSERT(all_of_type_coloridx());
}
//////////
/** Construct object from archive_node. */
color::color(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("color constructor from archive_node", LOGLEVEL_CONSTRUCT);
- unsigned int ty;
- if (!(n.find_unsigned("type", ty)))
- throw (std::runtime_error("unknown color type in archive"));
- type = (color_types)ty;
- if (!(n.find_unsigned("representation", representation_label)))
- throw (std::runtime_error("unknown color representation label in archive"));
+ debugmsg("color constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ unsigned int ty;
+ if (!(n.find_unsigned("type", ty)))
+ throw (std::runtime_error("unknown color type in archive"));
+ type = (color_types)ty;
+ if (!(n.find_unsigned("representation", representation_label)))
+ throw (std::runtime_error("unknown color representation label in archive"));
}
/** Unarchive the object. */
ex color::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new color(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new color(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void color::archive(archive_node &n) const
{
- inherited::archive(n);
- n.add_unsigned("type", type);
- n.add_unsigned("representation", representation_label);
+ inherited::archive(n);
+ n.add_unsigned("type", type);
+ n.add_unsigned("representation", representation_label);
}
//////////
basic * color::duplicate() const
{
- debugmsg("color duplicate",LOGLEVEL_DUPLICATE);
- return new color(*this);
+ debugmsg("color duplicate",LOGLEVEL_DUPLICATE);
+ return new color(*this);
}
void color::printraw(std::ostream & os) const
{
- debugmsg("color printraw",LOGLEVEL_PRINT);
- os << "color(type=" << (unsigned)type
- << ",representation_label=" << representation_label
- << ",indices=";
- printrawindices(os);
- os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+ debugmsg("color printraw",LOGLEVEL_PRINT);
+ os << "color(type=" << (unsigned)type
+ << ",representation_label=" << representation_label
+ << ",indices=";
+ printrawindices(os);
+ os << ",hash=" << hashvalue << ",flags=" << flags << ")";
}
void color::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("color printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "color object: "
- << "type=" << (unsigned)type
- << ",representation_label=" << representation_label << ", ";
- os << seq.size() << " indices" << std::endl;
- printtreeindices(os,indent);
- os << std::string(indent,' ') << "hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("color printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << "color object: "
+ << "type=" << (unsigned)type
+ << ",representation_label=" << representation_label << ", ";
+ os << seq.size() << " indices" << std::endl;
+ printtreeindices(os,indent);
+ os << std::string(indent,' ') << "hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void color::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("color print",LOGLEVEL_PRINT);
- switch (type) {
- case color_T:
- os << "T";
- if (representation_label!=0) {
- os << "^(" << representation_label << ")";
- }
- break;
- case color_f:
- os << "f";
- break;
- case color_d:
- os << "d";
- break;
- case color_delta8:
- os << "delta8";
- break;
- case color_ONE:
- os << "color_ONE";
- break;
- case invalid:
- default:
- os << "INVALID_COLOR_OBJECT";
- break;
- }
- printindices(os);
+ debugmsg("color print",LOGLEVEL_PRINT);
+ switch (type) {
+ case color_T:
+ os << "T";
+ if (representation_label!=0) {
+ os << "^(" << representation_label << ")";
+ }
+ break;
+ case color_f:
+ os << "f";
+ break;
+ case color_d:
+ os << "d";
+ break;
+ case color_delta8:
+ os << "delta8";
+ break;
+ case color_ONE:
+ os << "color_ONE";
+ break;
+ case invalid:
+ default:
+ os << "INVALID_COLOR_OBJECT";
+ break;
+ }
+ printindices(os);
}
void color::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("color print csrc",LOGLEVEL_PRINT);
- print(os,upper_precedence);
+ debugmsg("color print csrc",LOGLEVEL_PRINT);
+ print(os,upper_precedence);
}
bool color::info(unsigned inf) const
{
- return inherited::info(inf);
+ return inherited::info(inf);
}
#define CMPINDICES(A,B,C) ((idx1.get_value()==(A))&&(idx2.get_value()==(B))&&(idx3.get_value()==(C)))
ex color::eval(int level) const
{
- // canonicalize indices
-
- bool antisymmetric=false;
-
- switch (type) {
- case color_f:
- antisymmetric=true; // no break here!
- case color_d:
- case color_delta8:
- {
- exvector iv=seq;
- int sig=canonicalize_indices(iv,antisymmetric);
- if (sig!=INT_MAX) {
- // something has changed while sorting indices, more evaluations later
- if (sig==0) return _ex0();
- return ex(sig)*color(type,iv,representation_label);
- }
- }
- break;
- default:
- // nothing to canonicalize
- break;
- }
-
- switch (type) {
- case color_delta8:
- {
- GINAC_ASSERT(seq.size()==2);
- const coloridx & idx1=ex_to_coloridx(seq[0]);
- const coloridx & idx2=ex_to_coloridx(seq[1]);
-
- // check for delta8_{a,a} where a is a symbolic index, replace by 8
- if ((idx1.is_symbolic())&&(idx1.is_equal_same_type(idx2))) {
- return ex(COLOR_EIGHT);
- }
-
- // check for delta8_{a,b} where a and b are numeric indices, replace by 0 or 1
- if ((!idx1.is_symbolic())&&(!idx2.is_symbolic())) {
- if ((idx1.get_value()!=idx2.get_value())) {
- return _ex1();
- } else {
- return _ex0();
- }
- }
+ // canonicalize indices
+
+ bool antisymmetric=false;
+
+ switch (type) {
+ case color_f:
+ antisymmetric=true; // no break here!
+ case color_d:
+ case color_delta8:
+ {
+ exvector iv=seq;
+ int sig=canonicalize_indices(iv,antisymmetric);
+ if (sig!=INT_MAX) {
+ // something has changed while sorting indices, more evaluations later
+ if (sig==0) return _ex0();
+ return ex(sig)*color(type,iv,representation_label);
+ }
+ }
+ break;
+ default:
+ // nothing to canonicalize
+ break;
+ }
+
+ switch (type) {
+ case color_delta8:
+ {
+ GINAC_ASSERT(seq.size()==2);
+ const coloridx & idx1=ex_to_coloridx(seq[0]);
+ const coloridx & idx2=ex_to_coloridx(seq[1]);
+
+ // check for delta8_{a,a} where a is a symbolic index, replace by 8
+ if ((idx1.is_symbolic())&&(idx1.is_equal_same_type(idx2))) {
+ return ex(COLOR_EIGHT);
+ }
+
+ // check for delta8_{a,b} where a and b are numeric indices, replace by 0 or 1
+ if ((!idx1.is_symbolic())&&(!idx2.is_symbolic())) {
+ if ((idx1.get_value()!=idx2.get_value())) {
+ return _ex1();
+ } else {
+ return _ex0();
+ }
+ }
+ }
+ break;
+ case color_d:
+ // check for d_{a,a,c} (=0) when a is symbolic
+ {
+ GINAC_ASSERT(seq.size()==3);
+ const coloridx & idx1=ex_to_coloridx(seq[0]);
+ const coloridx & idx2=ex_to_coloridx(seq[1]);
+ const coloridx & idx3=ex_to_coloridx(seq[2]);
+
+ if (idx1.is_equal_same_type(idx2) && idx1.is_symbolic()) {
+ return _ex0();
+ } else if (idx2.is_equal_same_type(idx3) && idx2.is_symbolic()) {
+ return _ex0();
+ }
+
+ // check for three numeric indices
+ if (!(idx1.is_symbolic()||idx2.is_symbolic()||idx3.is_symbolic())) {
+ GINAC_ASSERT(idx1.get_value()<=idx2.get_value());
+ GINAC_ASSERT(idx2.get_value()<=idx3.get_value());
+ if (CMPINDICES(1,4,6)||CMPINDICES(1,5,7)||CMPINDICES(2,5,6)||
+ CMPINDICES(3,4,4)||CMPINDICES(3,5,5)) {
+ return _ex1_2();
+ } else if (CMPINDICES(2,4,7)||CMPINDICES(3,6,6)||CMPINDICES(3,7,7)) {
+ return -_ex1_2();
+ } else if (CMPINDICES(1,1,8)||CMPINDICES(2,2,8)||CMPINDICES(3,3,8)) {
+ return 1/sqrt(numeric(3));
+ } else if (CMPINDICES(8,8,8)) {
+ return -1/sqrt(numeric(3));
+ } else if (CMPINDICES(4,4,8)||CMPINDICES(5,5,8)||CMPINDICES(6,6,8)||CMPINDICES(7,7,8)) {
+ return -1/(2*sqrt(numeric(3)));
+ }
+ return _ex0();
+ }
+ }
+ break;
+ case color_f:
+ {
+ GINAC_ASSERT(seq.size()==3);
+ const coloridx & idx1=ex_to_coloridx(seq[0]);
+ const coloridx & idx2=ex_to_coloridx(seq[1]);
+ const coloridx & idx3=ex_to_coloridx(seq[2]);
+
+ // check for three numeric indices
+ if (!(idx1.is_symbolic()||idx2.is_symbolic()||idx3.is_symbolic())) {
+ GINAC_ASSERT(idx1.get_value()<=idx2.get_value());
+ GINAC_ASSERT(idx2.get_value()<=idx3.get_value());
+ if (CMPINDICES(1,2,3)) {
+ return _ex1();
+ } else if (CMPINDICES(1,4,7)||CMPINDICES(2,4,6)||
+ CMPINDICES(2,5,7)||CMPINDICES(3,4,5)) {
+ return _ex1_2();
+ } else if (CMPINDICES(1,5,6)||CMPINDICES(3,6,7)) {
+ return -_ex1_2();
+ } else if (CMPINDICES(4,5,8)||CMPINDICES(6,7,8)) {
+ return sqrt(numeric(3))/2;
+ } else if (CMPINDICES(8,8,8)) {
+ return -1/sqrt(numeric(3));
+ } else if (CMPINDICES(4,4,8)||CMPINDICES(5,5,8)||CMPINDICES(6,6,8)||CMPINDICES(7,7,8)) {
+ return -1/(2*sqrt(numeric(3)));
+ }
+ return _ex0();
+ }
+ break;
+ }
+ default:
+ // nothing to evaluate
+ break;
}
- break;
- case color_d:
- // check for d_{a,a,c} (=0) when a is symbolic
- {
- GINAC_ASSERT(seq.size()==3);
- const coloridx & idx1=ex_to_coloridx(seq[0]);
- const coloridx & idx2=ex_to_coloridx(seq[1]);
- const coloridx & idx3=ex_to_coloridx(seq[2]);
-
- if (idx1.is_equal_same_type(idx2) && idx1.is_symbolic()) {
- return _ex0();
- } else if (idx2.is_equal_same_type(idx3) && idx2.is_symbolic()) {
- return _ex0();
- }
-
- // check for three numeric indices
- if (!(idx1.is_symbolic()||idx2.is_symbolic()||idx3.is_symbolic())) {
- GINAC_ASSERT(idx1.get_value()<=idx2.get_value());
- GINAC_ASSERT(idx2.get_value()<=idx3.get_value());
- if (CMPINDICES(1,4,6)||CMPINDICES(1,5,7)||CMPINDICES(2,5,6)||
- CMPINDICES(3,4,4)||CMPINDICES(3,5,5)) {
- return _ex1_2();
- } else if (CMPINDICES(2,4,7)||CMPINDICES(3,6,6)||CMPINDICES(3,7,7)) {
- return -_ex1_2();
- } else if (CMPINDICES(1,1,8)||CMPINDICES(2,2,8)||CMPINDICES(3,3,8)) {
- return 1/sqrt(numeric(3));
- } else if (CMPINDICES(8,8,8)) {
- return -1/sqrt(numeric(3));
- } else if (CMPINDICES(4,4,8)||CMPINDICES(5,5,8)||CMPINDICES(6,6,8)||CMPINDICES(7,7,8)) {
- return -1/(2*sqrt(numeric(3)));
- }
- return _ex0();
- }
- }
- break;
- case color_f:
- {
- GINAC_ASSERT(seq.size()==3);
- const coloridx & idx1=ex_to_coloridx(seq[0]);
- const coloridx & idx2=ex_to_coloridx(seq[1]);
- const coloridx & idx3=ex_to_coloridx(seq[2]);
-
- // check for three numeric indices
- if (!(idx1.is_symbolic()||idx2.is_symbolic()||idx3.is_symbolic())) {
- GINAC_ASSERT(idx1.get_value()<=idx2.get_value());
- GINAC_ASSERT(idx2.get_value()<=idx3.get_value());
- if (CMPINDICES(1,2,3)) {
- return _ex1();
- } else if (CMPINDICES(1,4,7)||CMPINDICES(2,4,6)||
- CMPINDICES(2,5,7)||CMPINDICES(3,4,5)) {
- return _ex1_2();
- } else if (CMPINDICES(1,5,6)||CMPINDICES(3,6,7)) {
- return -_ex1_2();
- } else if (CMPINDICES(4,5,8)||CMPINDICES(6,7,8)) {
- return sqrt(numeric(3))/2;
- } else if (CMPINDICES(8,8,8)) {
- return -1/sqrt(numeric(3));
- } else if (CMPINDICES(4,4,8)||CMPINDICES(5,5,8)||CMPINDICES(6,6,8)||CMPINDICES(7,7,8)) {
- return -1/(2*sqrt(numeric(3)));
- }
- return _ex0();
- }
- break;
- }
- default:
- // nothing to evaluate
- break;
- }
-
- return this->hold();
-}
-
+
+ return this->hold();
+}
+
// protected
int color::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(other.tinfo() == TINFO_color);
- const color *o = static_cast<const color *>(&other);
- if (type==o->type) {
- if (representation_label==o->representation_label) {
- return inherited::compare_same_type(other);
- }
- return representation_label < o->representation_label ? -1 : 1;
- }
- return type < o->type ? -1 : 1;
+ GINAC_ASSERT(other.tinfo() == TINFO_color);
+ const color *o = static_cast<const color *>(&other);
+ if (type==o->type) {
+ if (representation_label==o->representation_label) {
+ return inherited::compare_same_type(other);
+ }
+ return representation_label < o->representation_label ? -1 : 1;
+ }
+ return type < o->type ? -1 : 1;
}
bool color::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(other.tinfo() == TINFO_color);
- const color *o = static_cast<const color *>(&other);
- if (type!=o->type) return false;
- if (representation_label!=o->representation_label) return false;
- return inherited::is_equal_same_type(other);
+ GINAC_ASSERT(other.tinfo() == TINFO_color);
+ const color *o = static_cast<const color *>(&other);
+ if (type!=o->type) return false;
+ if (representation_label!=o->representation_label) return false;
+ return inherited::is_equal_same_type(other);
}
#include <iostream>
ex color::simplify_ncmul(const exvector & v) const
{
- // simplifications: contract delta8_{a,b} where possible
- // sort delta8,f,d,T(rl=0),T(rl=1),...,ONE(rl=0),ONE(rl=1),...
- // remove superfluous ONEs
-
- // contract indices of delta8_{a,b} if they are different and symbolic
-
- exvector v_contracted=v;
- unsigned replacements;
- bool something_changed=false;
-
- exvector::iterator it=v_contracted.begin();
- while (it!=v_contracted.end()) {
- // process only delta8 objects
- if (is_ex_exactly_of_type(*it,color) && (ex_to_color(*it).type==color_delta8)) {
- color & d8=ex_to_nonconst_color(*it);
- GINAC_ASSERT(d8.seq.size()==2);
- const coloridx & first_idx=ex_to_coloridx(d8.seq[0]);
- const coloridx & second_idx=ex_to_coloridx(d8.seq[1]);
- // delta8_{a,a} should have been contracted in color::eval()
- GINAC_ASSERT((!first_idx.is_equal(second_idx))||(!first_idx.is_symbolic()));
- ex saved_delta8=*it; // save to restore it later
-
- // try to contract first index
- replacements=1;
- if (first_idx.is_symbolic()) {
- replacements = subs_index_in_exvector(v_contracted,first_idx,second_idx);
- if (replacements==1) {
- // not contracted except in itself, restore delta8 object
- *it=saved_delta8;
- } else {
- // a contracted index should occur exactly twice
- GINAC_ASSERT(replacements==2);
- *it=_ex1();
- something_changed=true;
- }
- }
-
- // try second index only if first was not contracted
- if ((replacements==1)&&(second_idx.is_symbolic())) {
- // first index not contracted, *it is guaranteed to be the original delta8 object
- replacements = subs_index_in_exvector(v_contracted,second_idx,first_idx);
- if (replacements==1) {
- // not contracted except in itself, restore delta8 object
- *it=saved_delta8;
- } else {
- // a contracted index should occur exactly twice
- GINAC_ASSERT(replacements==2);
- *it=_ex1();
- something_changed=true;
- }
- }
- }
- ++it;
- }
-
- if (something_changed) {
- // do more simplifications later
- return nonsimplified_ncmul(v_contracted);
- }
-
- // there were no indices to contract
- // sort delta8,f,d,T(rl=0),T(rl=1),...,ONE(rl=0),ONE(rl=1),...,unknown
- // (if there is at least one unknown object, all Ts will be unknown to not change the order)
-
- exvector delta8vec;
- exvector fvec;
- exvector dvec;
- exvectorvector Tvecs;
- Tvecs.resize(MAX_REPRESENTATION_LABELS);
- exvectorvector ONEvecs;
- ONEvecs.resize(MAX_REPRESENTATION_LABELS);
- exvector unknownvec;
-
- split_color_string_in_parts(v,delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
-
- // d_{a,k,l} f_{b,k,l}=0 (includes case a=b)
- if ((dvec.size()>=1)&&(fvec.size()>=1)) {
- for (exvector::iterator it1=dvec.begin(); it1!=dvec.end(); ++it1) {
- for (exvector::iterator it2=fvec.begin(); it2!=fvec.end(); ++it2) {
- GINAC_ASSERT(is_ex_exactly_of_type(*it1,color));
- GINAC_ASSERT(is_ex_exactly_of_type(*it2,color));
- const color & col1=ex_to_color(*it1);
- const color & col2=ex_to_color(*it2);
- exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
- if (iv_intersect.size()>=2) return _ex0();
- }
- }
- }
-
- // d_{a,k,l} d_{b,k,l}=5/3 delta8_{a,b} (includes case a=b)
- if (dvec.size()>=2) {
- for (exvector::iterator it1=dvec.begin(); it1!=dvec.end()-1; ++it1) {
- for (exvector::iterator it2=it1+1; it2!=dvec.end(); ++it2) {
- GINAC_ASSERT(is_ex_exactly_of_type(*it1,color));
- GINAC_ASSERT(is_ex_exactly_of_type(*it2,color));
- const color & col1=ex_to_color(*it1);
- const color & col2=ex_to_color(*it2);
- exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
- if (iv_intersect.size()>=2) {
- if (iv_intersect.size()==3) {
- *it1=numeric(40)/numeric(3);
- *it2=_ex1();
- } else {
- int sig1, sig2; // unimportant, since symmetric
- ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,false,&sig1);
- ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,false,&sig2);
- *it1=numeric(5)/numeric(3)*color(color_delta8,idx1,idx2);
- *it2=_ex1();
- }
- return nonsimplified_ncmul(recombine_color_string(
- delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
- }
- }
- }
- }
-
- // f_{a,k,l} f_{b,k,l}=3 delta8_{a,b} (includes case a=b)
- if (fvec.size()>=2) {
- for (exvector::iterator it1=fvec.begin(); it1!=fvec.end()-1; ++it1) {
- for (exvector::iterator it2=it1+1; it2!=fvec.end(); ++it2) {
- GINAC_ASSERT(is_ex_exactly_of_type(*it1,color));
- GINAC_ASSERT(is_ex_exactly_of_type(*it2,color));
- const color & col1=ex_to_color(*it1);
- const color & col2=ex_to_color(*it2);
- exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
- if (iv_intersect.size()>=2) {
- if (iv_intersect.size()==3) {
- *it1=numeric(24);
- *it2=_ex1();
- } else {
- int sig1, sig2;
- ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,true,&sig1);
- ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,true,&sig2);
- *it1=numeric(sig1*sig2*5)/numeric(3)*color(color_delta8,idx1,idx2);
- *it2=_ex1();
- }
- return nonsimplified_ncmul(recombine_color_string(
- delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
- }
- }
- }
- }
-
- // d_{a,b,c} T_b T_c = 5/6 T_a
- // f_{a,b,c} T_b T_c = 3/2 I T_a
- for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
- if ((Tvecs[rl].size()>=2)&&((dvec.size()>=1)||(fvec.size()>=1))) {
- for (exvector::iterator it1=Tvecs[rl].begin(); it1!=Tvecs[rl].end()-1; ++it1) {
- exvector iv;
- GINAC_ASSERT(is_ex_exactly_of_type(*it1,color)&&ex_to_color(*it1).type==color_T);
- GINAC_ASSERT(is_ex_exactly_of_type(*(it1+1),color)&&ex_to_color(*(it1+1)).type==color_T);
- iv.push_back(ex_to_color(*it1).seq[0]);
- iv.push_back(ex_to_color(*(it1+1)).seq[0]);
-
- // d_{a,b,c} T_b T_c = 5/6 T_a
- for (exvector::iterator it2=dvec.begin(); it2!=dvec.end(); ++it2) {
- GINAC_ASSERT(is_ex_exactly_of_type(*it2,color)&&ex_to_color(*it2).type==color_d);
- const color & dref=ex_to_color(*it2);
- exvector iv_intersect=idx_intersect(dref.seq,iv);
- if (iv_intersect.size()==2) {
- int sig; // unimportant, since symmetric
- ex free_idx=permute_free_index_to_front(dref.seq,iv,false,&sig);
- *it1=color(color_T,free_idx,rl);
- *(it1+1)=color(color_ONE,rl);
- *it2=numeric(5)/numeric(6);
- return nonsimplified_ncmul(recombine_color_string(
- delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
- }
- }
-
- // f_{a,b,c} T_b T_c = 3/2 I T_a
- for (exvector::iterator it2=fvec.begin(); it2!=fvec.end(); ++it2) {
- GINAC_ASSERT(is_ex_exactly_of_type(*it2,color)&&ex_to_color(*it2).type==color_f);
- const color & fref=ex_to_color(*it2);
- exvector iv_intersect=idx_intersect(fref.seq,iv);
- if (iv_intersect.size()==2) {
- int sig;
- ex free_idx=permute_free_index_to_front(fref.seq,iv,true,&sig);
- *it1=color(color_T,free_idx,rl);
- *(it1+1)=color(color_ONE,rl);
- *it2=numeric(sig*3)/numeric(2)*I;
- return nonsimplified_ncmul(recombine_color_string(
- delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
- }
- }
- }
- }
- }
-
- // clear all ONEs when there is at least one corresponding color_T
- // in this representation, retain one ONE otherwise
- for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
- if (Tvecs[rl].size()!=0) {
- ONEvecs[rl].clear();
- } else if (ONEvecs[rl].size()!=0) {
- ONEvecs[rl].clear();
- ONEvecs[rl].push_back(color(color_ONE,rl));
- }
- }
-
- // return a sorted vector
- return simplified_ncmul(recombine_color_string(delta8vec,fvec,dvec,Tvecs,
- ONEvecs,unknownvec));
+ // simplifications: contract delta8_{a,b} where possible
+ // sort delta8,f,d,T(rl=0),T(rl=1),...,ONE(rl=0),ONE(rl=1),...
+ // remove superfluous ONEs
+
+ // contract indices of delta8_{a,b} if they are different and symbolic
+
+ exvector v_contracted=v;
+ unsigned replacements;
+ bool something_changed=false;
+
+ exvector::iterator it=v_contracted.begin();
+ while (it!=v_contracted.end()) {
+ // process only delta8 objects
+ if (is_ex_exactly_of_type(*it,color) && (ex_to_color(*it).type==color_delta8)) {
+ color & d8=ex_to_nonconst_color(*it);
+ GINAC_ASSERT(d8.seq.size()==2);
+ const coloridx & first_idx=ex_to_coloridx(d8.seq[0]);
+ const coloridx & second_idx=ex_to_coloridx(d8.seq[1]);
+ // delta8_{a,a} should have been contracted in color::eval()
+ GINAC_ASSERT((!first_idx.is_equal(second_idx))||(!first_idx.is_symbolic()));
+ ex saved_delta8=*it; // save to restore it later
+
+ // try to contract first index
+ replacements=1;
+ if (first_idx.is_symbolic()) {
+ replacements = subs_index_in_exvector(v_contracted,first_idx,second_idx);
+ if (replacements==1) {
+ // not contracted except in itself, restore delta8 object
+ *it=saved_delta8;
+ } else {
+ // a contracted index should occur exactly twice
+ GINAC_ASSERT(replacements==2);
+ *it=_ex1();
+ something_changed=true;
+ }
+ }
+
+ // try second index only if first was not contracted
+ if ((replacements==1)&&(second_idx.is_symbolic())) {
+ // first index not contracted, *it is guaranteed to be the original delta8 object
+ replacements = subs_index_in_exvector(v_contracted,second_idx,first_idx);
+ if (replacements==1) {
+ // not contracted except in itself, restore delta8 object
+ *it=saved_delta8;
+ } else {
+ // a contracted index should occur exactly twice
+ GINAC_ASSERT(replacements==2);
+ *it=_ex1();
+ something_changed=true;
+ }
+ }
+ }
+ ++it;
+ }
+
+ if (something_changed) {
+ // do more simplifications later
+ return nonsimplified_ncmul(v_contracted);
+ }
+
+ // there were no indices to contract
+ // sort delta8,f,d,T(rl=0),T(rl=1),...,ONE(rl=0),ONE(rl=1),...,unknown
+ // (if there is at least one unknown object, all Ts will be unknown to not change the order)
+
+ exvector delta8vec;
+ exvector fvec;
+ exvector dvec;
+ exvectorvector Tvecs;
+ Tvecs.resize(MAX_REPRESENTATION_LABELS);
+ exvectorvector ONEvecs;
+ ONEvecs.resize(MAX_REPRESENTATION_LABELS);
+ exvector unknownvec;
+
+ split_color_string_in_parts(v,delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
+
+ // d_{a,k,l} f_{b,k,l}=0 (includes case a=b)
+ if ((dvec.size()>=1)&&(fvec.size()>=1)) {
+ for (exvector::iterator it1=dvec.begin(); it1!=dvec.end(); ++it1) {
+ for (exvector::iterator it2=fvec.begin(); it2!=fvec.end(); ++it2) {
+ GINAC_ASSERT(is_ex_exactly_of_type(*it1,color));
+ GINAC_ASSERT(is_ex_exactly_of_type(*it2,color));
+ const color & col1=ex_to_color(*it1);
+ const color & col2=ex_to_color(*it2);
+ exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
+ if (iv_intersect.size()>=2) return _ex0();
+ }
+ }
+ }
+
+ // d_{a,k,l} d_{b,k,l}=5/3 delta8_{a,b} (includes case a=b)
+ if (dvec.size()>=2) {
+ for (exvector::iterator it1=dvec.begin(); it1!=dvec.end()-1; ++it1) {
+ for (exvector::iterator it2=it1+1; it2!=dvec.end(); ++it2) {
+ GINAC_ASSERT(is_ex_exactly_of_type(*it1,color));
+ GINAC_ASSERT(is_ex_exactly_of_type(*it2,color));
+ const color & col1=ex_to_color(*it1);
+ const color & col2=ex_to_color(*it2);
+ exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
+ if (iv_intersect.size()>=2) {
+ if (iv_intersect.size()==3) {
+ *it1=numeric(40)/numeric(3);
+ *it2=_ex1();
+ } else {
+ int sig1, sig2; // unimportant, since symmetric
+ ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,false,&sig1);
+ ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,false,&sig2);
+ *it1=numeric(5)/numeric(3)*color(color_delta8,idx1,idx2);
+ *it2=_ex1();
+ }
+ return nonsimplified_ncmul(recombine_color_string(
+ delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+ }
+ }
+ }
+ }
+
+ // f_{a,k,l} f_{b,k,l}=3 delta8_{a,b} (includes case a=b)
+ if (fvec.size()>=2) {
+ for (exvector::iterator it1=fvec.begin(); it1!=fvec.end()-1; ++it1) {
+ for (exvector::iterator it2=it1+1; it2!=fvec.end(); ++it2) {
+ GINAC_ASSERT(is_ex_exactly_of_type(*it1,color));
+ GINAC_ASSERT(is_ex_exactly_of_type(*it2,color));
+ const color & col1=ex_to_color(*it1);
+ const color & col2=ex_to_color(*it2);
+ exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
+ if (iv_intersect.size()>=2) {
+ if (iv_intersect.size()==3) {
+ *it1=numeric(24);
+ *it2=_ex1();
+ } else {
+ int sig1, sig2;
+ ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,true,&sig1);
+ ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,true,&sig2);
+ *it1=numeric(sig1*sig2*5)/numeric(3)*color(color_delta8,idx1,idx2);
+ *it2=_ex1();
+ }
+ return nonsimplified_ncmul(recombine_color_string(
+ delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+ }
+ }
+ }
+ }
+
+ // d_{a,b,c} T_b T_c = 5/6 T_a
+ // f_{a,b,c} T_b T_c = 3/2 I T_a
+ for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+ if ((Tvecs[rl].size()>=2)&&((dvec.size()>=1)||(fvec.size()>=1))) {
+ for (exvector::iterator it1=Tvecs[rl].begin(); it1!=Tvecs[rl].end()-1; ++it1) {
+ exvector iv;
+ GINAC_ASSERT(is_ex_exactly_of_type(*it1,color)&&ex_to_color(*it1).type==color_T);
+ GINAC_ASSERT(is_ex_exactly_of_type(*(it1+1),color)&&ex_to_color(*(it1+1)).type==color_T);
+ iv.push_back(ex_to_color(*it1).seq[0]);
+ iv.push_back(ex_to_color(*(it1+1)).seq[0]);
+
+ // d_{a,b,c} T_b T_c = 5/6 T_a
+ for (exvector::iterator it2=dvec.begin(); it2!=dvec.end(); ++it2) {
+ GINAC_ASSERT(is_ex_exactly_of_type(*it2,color)&&ex_to_color(*it2).type==color_d);
+ const color & dref=ex_to_color(*it2);
+ exvector iv_intersect=idx_intersect(dref.seq,iv);
+ if (iv_intersect.size()==2) {
+ int sig; // unimportant, since symmetric
+ ex free_idx=permute_free_index_to_front(dref.seq,iv,false,&sig);
+ *it1=color(color_T,free_idx,rl);
+ *(it1+1)=color(color_ONE,rl);
+ *it2=numeric(5)/numeric(6);
+ return nonsimplified_ncmul(recombine_color_string(
+ delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+ }
+ }
+
+ // f_{a,b,c} T_b T_c = 3/2 I T_a
+ for (exvector::iterator it2=fvec.begin(); it2!=fvec.end(); ++it2) {
+ GINAC_ASSERT(is_ex_exactly_of_type(*it2,color)&&ex_to_color(*it2).type==color_f);
+ const color & fref=ex_to_color(*it2);
+ exvector iv_intersect=idx_intersect(fref.seq,iv);
+ if (iv_intersect.size()==2) {
+ int sig;
+ ex free_idx=permute_free_index_to_front(fref.seq,iv,true,&sig);
+ *it1=color(color_T,free_idx,rl);
+ *(it1+1)=color(color_ONE,rl);
+ *it2=numeric(sig*3)/numeric(2)*I;
+ return nonsimplified_ncmul(recombine_color_string(
+ delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+ }
+ }
+ }
+ }
+ }
+
+ // clear all ONEs when there is at least one corresponding color_T
+ // in this representation, retain one ONE otherwise
+ for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+ if (Tvecs[rl].size()!=0) {
+ ONEvecs[rl].clear();
+ } else if (ONEvecs[rl].size()!=0) {
+ ONEvecs[rl].clear();
+ ONEvecs[rl].push_back(color(color_ONE,rl));
+ }
+ }
+
+ // return a sorted vector
+ return simplified_ncmul(recombine_color_string(delta8vec,fvec,dvec,Tvecs,
+ ONEvecs,unknownvec));
}
ex color::thisexprseq(const exvector & v) const
{
- return color(type,v,representation_label);
+ return color(type,v,representation_label);
}
ex color::thisexprseq(exvector * vp) const
{
- return color(type,vp,representation_label);
+ return color(type,vp,representation_label);
}
bool color::all_of_type_coloridx(void) const
{
- // used only inside of ASSERTs
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- if (!is_ex_of_type(*cit,coloridx)) return false;
- }
- return true;
+ // used only inside of ASSERTs
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ if (!is_ex_of_type(*cit,coloridx)) return false;
+ }
+ return true;
}
//////////
color color_ONE(unsigned rl)
{
- return color(color::color_ONE,rl);
+ return color(color::color_ONE,rl);
}
color color_T(const ex & a, unsigned rl)
{
- return color(color::color_T,a,rl);
+ return color(color::color_T,a,rl);
}
color color_f(const ex & a, const ex & b, const ex & c)
{
- return color(color::color_f,a,b,c);
+ return color(color::color_f,a,b,c);
}
color color_d(const ex & a, const ex & b, const ex & c)
{
- return color(color::color_d,a,b,c);
+ return color(color::color_d,a,b,c);
}
ex color_h(const ex & a, const ex & b, const ex & c)
{
- return color(color::color_d,a,b,c)+I*color(color::color_f,a,b,c);
+ return color(color::color_d,a,b,c)+I*color(color::color_f,a,b,c);
}
color color_delta8(const ex & a, const ex & b)
{
- return color(color::color_delta8,a,b);
+ return color(color::color_delta8,a,b);
}
void split_color_string_in_parts(const exvector & v, exvector & delta8vec,
- exvector & fvec, exvector & dvec,
- exvectorvector & Tvecs,
- exvectorvector & ONEvecs,
- exvector & unknownvec)
-{
- // if not all elements are of type color, put all Ts in unknownvec to
- // retain the ordering
- bool all_color=true;
- for (exvector::const_iterator cit=v.begin(); cit!=v.end(); ++cit) {
- if (!is_ex_exactly_of_type(*cit,color)) {
- all_color=false;
- break;
- }
- }
-
- for (exvector::const_iterator cit=v.begin(); cit!=v.end(); ++cit) {
- if (is_ex_exactly_of_type(*cit,color)) {
- switch (ex_to_color(*cit).type) {
- case color::color_delta8:
- delta8vec.push_back(*cit);
- break;
- case color::color_f:
- fvec.push_back(*cit);
- break;
- case color::color_d:
- dvec.push_back(*cit);
- break;
- case color::color_T:
- GINAC_ASSERT(ex_to_color(*cit).representation_label<MAX_REPRESENTATION_LABELS);
- if (all_color) {
- Tvecs[ex_to_color(*cit).representation_label].push_back(*cit);
- } else {
- unknownvec.push_back(*cit);
- }
- break;
- case color::color_ONE:
- GINAC_ASSERT(ex_to_color(*cit).representation_label<MAX_REPRESENTATION_LABELS);
- ONEvecs[ex_to_color(*cit).representation_label].push_back(*cit);
- break;
- default:
- throw(std::logic_error("invalid type in split_color_string_in_parts()"));
- }
- } else {
- unknownvec.push_back(*cit);
- }
- }
+ exvector & fvec, exvector & dvec,
+ exvectorvector & Tvecs,
+ exvectorvector & ONEvecs,
+ exvector & unknownvec)
+{
+ // if not all elements are of type color, put all Ts in unknownvec to
+ // retain the ordering
+ bool all_color=true;
+ for (exvector::const_iterator cit=v.begin(); cit!=v.end(); ++cit) {
+ if (!is_ex_exactly_of_type(*cit,color)) {
+ all_color=false;
+ break;
+ }
+ }
+
+ for (exvector::const_iterator cit=v.begin(); cit!=v.end(); ++cit) {
+ if (is_ex_exactly_of_type(*cit,color)) {
+ switch (ex_to_color(*cit).type) {
+ case color::color_delta8:
+ delta8vec.push_back(*cit);
+ break;
+ case color::color_f:
+ fvec.push_back(*cit);
+ break;
+ case color::color_d:
+ dvec.push_back(*cit);
+ break;
+ case color::color_T:
+ GINAC_ASSERT(ex_to_color(*cit).representation_label<MAX_REPRESENTATION_LABELS);
+ if (all_color) {
+ Tvecs[ex_to_color(*cit).representation_label].push_back(*cit);
+ } else {
+ unknownvec.push_back(*cit);
+ }
+ break;
+ case color::color_ONE:
+ GINAC_ASSERT(ex_to_color(*cit).representation_label<MAX_REPRESENTATION_LABELS);
+ ONEvecs[ex_to_color(*cit).representation_label].push_back(*cit);
+ break;
+ default:
+ throw(std::logic_error("invalid type in split_color_string_in_parts()"));
+ }
+ } else {
+ unknownvec.push_back(*cit);
+ }
+ }
}
exvector recombine_color_string(exvector & delta8vec, exvector & fvec,
- exvector & dvec, exvectorvector & Tvecs,
- exvectorvector & ONEvecs, exvector & unknownvec)
-{
- unsigned sz=delta8vec.size()+fvec.size()+dvec.size()+unknownvec.size();
- for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
- sz += Tvecs[rl].size();
- sz += ONEvecs[rl].size();
- }
- exvector v;
- v.reserve(sz);
-
- append_exvector_to_exvector(v,delta8vec);
- append_exvector_to_exvector(v,fvec);
- append_exvector_to_exvector(v,dvec);
- for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
- append_exvector_to_exvector(v,Tvecs[rl]);
- append_exvector_to_exvector(v,ONEvecs[rl]);
- }
- append_exvector_to_exvector(v,unknownvec);
- return v;
+ exvector & dvec, exvectorvector & Tvecs,
+ exvectorvector & ONEvecs, exvector & unknownvec)
+{
+ unsigned sz=delta8vec.size()+fvec.size()+dvec.size()+unknownvec.size();
+ for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+ sz += Tvecs[rl].size();
+ sz += ONEvecs[rl].size();
+ }
+ exvector v;
+ v.reserve(sz);
+
+ append_exvector_to_exvector(v,delta8vec);
+ append_exvector_to_exvector(v,fvec);
+ append_exvector_to_exvector(v,dvec);
+ for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+ append_exvector_to_exvector(v,Tvecs[rl]);
+ append_exvector_to_exvector(v,ONEvecs[rl]);
+ }
+ append_exvector_to_exvector(v,unknownvec);
+ return v;
}
ex color_trace_of_one_representation_label(const exvector & v)
{
- if (v.size()==0) {
- return numeric(COLOR_THREE);
- } else if (v.size()==1) {
- GINAC_ASSERT(is_ex_exactly_of_type(*(v.begin()),color));
- return _ex0();
- }
- exvector v1=v;
- ex last_element=v1.back();
- GINAC_ASSERT(is_ex_exactly_of_type(last_element,color));
- GINAC_ASSERT(ex_to_color(last_element).type==color::color_T);
- v1.pop_back();
- ex next_to_last_element=v1.back();
- GINAC_ASSERT(is_ex_exactly_of_type(next_to_last_element,color));
- GINAC_ASSERT(ex_to_color(next_to_last_element).type==color::color_T);
- v1.pop_back();
- exvector v2=v1;
-
- const ex & last_index=ex_to_color(last_element).seq[0];
- const ex & next_to_last_index=ex_to_color(next_to_last_element).seq[0];
- ex summation_index=coloridx();
-
- v2.push_back(color_T(summation_index)); // don't care about the representation_label
-
- // FIXME: check this formula for SU(N) with N!=3
- return numeric(1)/numeric(2*COLOR_THREE)*color_delta8(next_to_last_index,last_index)
- % color_trace_of_one_representation_label(v1)
- +numeric(1)/numeric(2)*color_h(next_to_last_index,last_index,summation_index)
- % color_trace_of_one_representation_label(v2);
- /*
- ex term1=numeric(1)/numeric(2*COLOR_THREE)*color_delta8(next_to_last_index,last_index)
- % color_trace_of_one_representation_label(v1);
- cout << "term 1 of trace of " << v.size() << " ts=" << term1 << endl;
- ex term2=numeric(1)/numeric(2)*color_h(next_to_last_index,last_index,summation_index)
- % color_trace_of_one_representation_label(v2);
- cout << "term 2 of trace of " << v.size() << " ts=" << term2 << endl;
- return term1+term2;
- */
+ if (v.size()==0) {
+ return numeric(COLOR_THREE);
+ } else if (v.size()==1) {
+ GINAC_ASSERT(is_ex_exactly_of_type(*(v.begin()),color));
+ return _ex0();
+ }
+ exvector v1=v;
+ ex last_element=v1.back();
+ GINAC_ASSERT(is_ex_exactly_of_type(last_element,color));
+ GINAC_ASSERT(ex_to_color(last_element).type==color::color_T);
+ v1.pop_back();
+ ex next_to_last_element=v1.back();
+ GINAC_ASSERT(is_ex_exactly_of_type(next_to_last_element,color));
+ GINAC_ASSERT(ex_to_color(next_to_last_element).type==color::color_T);
+ v1.pop_back();
+ exvector v2=v1;
+
+ const ex & last_index=ex_to_color(last_element).seq[0];
+ const ex & next_to_last_index=ex_to_color(next_to_last_element).seq[0];
+ ex summation_index=coloridx();
+
+ v2.push_back(color_T(summation_index)); // don't care about the representation_label
+
+ // FIXME: check this formula for SU(N) with N!=3
+ return numeric(1)/numeric(2*COLOR_THREE)*color_delta8(next_to_last_index,last_index)
+ % color_trace_of_one_representation_label(v1)
+ +numeric(1)/numeric(2)*color_h(next_to_last_index,last_index,summation_index)
+ % color_trace_of_one_representation_label(v2);
+ /*
+ ex term1=numeric(1)/numeric(2*COLOR_THREE)*color_delta8(next_to_last_index,last_index)
+ % color_trace_of_one_representation_label(v1);
+ cout << "term 1 of trace of " << v.size() << " ts=" << term1 << endl;
+ ex term2=numeric(1)/numeric(2)*color_h(next_to_last_index,last_index,summation_index)
+ % color_trace_of_one_representation_label(v2);
+ cout << "term 2 of trace of " << v.size() << " ts=" << term2 << endl;
+ return term1+term2;
+ */
}
ex color_trace(const exvector & v, unsigned rl)
{
- GINAC_ASSERT(rl<MAX_REPRESENTATION_LABELS);
-
- exvector v_rest;
- v_rest.reserve(v.size()+1); // max size if trace is empty
-
- exvector delta8vec;
- exvector fvec;
- exvector dvec;
- exvectorvector Tvecs;
- Tvecs.resize(MAX_REPRESENTATION_LABELS);
- exvectorvector ONEvecs;
- ONEvecs.resize(MAX_REPRESENTATION_LABELS);
- exvector unknownvec;
-
- split_color_string_in_parts(v,delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
-
- if (unknownvec.size()!=0) {
- throw(std::invalid_argument("color_trace(): expression must be expanded"));
- }
-
- append_exvector_to_exvector(v_rest,delta8vec);
- append_exvector_to_exvector(v_rest,fvec);
- append_exvector_to_exvector(v_rest,dvec);
- for (unsigned i=0; i<MAX_REPRESENTATION_LABELS; ++i) {
- if (i!=rl) {
- append_exvector_to_exvector(v_rest,Tvecs[i]);
- append_exvector_to_exvector(v_rest,ONEvecs[i]);
- } else {
- if (Tvecs[i].size()!=0) {
- v_rest.push_back(color_trace_of_one_representation_label(Tvecs[i]));
- } else if (ONEvecs[i].size()!=0) {
- v_rest.push_back(numeric(COLOR_THREE));
- } else {
- throw(std::logic_error("color_trace(): representation_label not in color string"));
- }
- }
- }
-
- return nonsimplified_ncmul(v_rest);
+ GINAC_ASSERT(rl<MAX_REPRESENTATION_LABELS);
+
+ exvector v_rest;
+ v_rest.reserve(v.size()+1); // max size if trace is empty
+
+ exvector delta8vec;
+ exvector fvec;
+ exvector dvec;
+ exvectorvector Tvecs;
+ Tvecs.resize(MAX_REPRESENTATION_LABELS);
+ exvectorvector ONEvecs;
+ ONEvecs.resize(MAX_REPRESENTATION_LABELS);
+ exvector unknownvec;
+
+ split_color_string_in_parts(v,delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
+
+ if (unknownvec.size()!=0) {
+ throw(std::invalid_argument("color_trace(): expression must be expanded"));
+ }
+
+ append_exvector_to_exvector(v_rest,delta8vec);
+ append_exvector_to_exvector(v_rest,fvec);
+ append_exvector_to_exvector(v_rest,dvec);
+ for (unsigned i=0; i<MAX_REPRESENTATION_LABELS; ++i) {
+ if (i!=rl) {
+ append_exvector_to_exvector(v_rest,Tvecs[i]);
+ append_exvector_to_exvector(v_rest,ONEvecs[i]);
+ } else {
+ if (Tvecs[i].size()!=0) {
+ v_rest.push_back(color_trace_of_one_representation_label(Tvecs[i]));
+ } else if (ONEvecs[i].size()!=0) {
+ v_rest.push_back(numeric(COLOR_THREE));
+ } else {
+ throw(std::logic_error("color_trace(): representation_label not in color string"));
+ }
+ }
+ }
+
+ return nonsimplified_ncmul(v_rest);
}
ex simplify_pure_color_string(const ex & e)
{
- GINAC_ASSERT(is_ex_exactly_of_type(e,ncmul));
-
- exvector delta8vec;
- exvector fvec;
- exvector dvec;
- exvectorvector Tvecs;
- Tvecs.resize(MAX_REPRESENTATION_LABELS);
- exvectorvector ONEvecs;
- ONEvecs.resize(MAX_REPRESENTATION_LABELS);
- exvector unknownvec;
-
- split_color_string_in_parts(ex_to_ncmul(e).get_factors(),delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
-
- // search for T_k S T_k (=1/2 Tr(S) - 1/6 S)
- for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
- if (Tvecs[rl].size()>=2) {
- for (unsigned i=0; i<Tvecs[rl].size()-1; ++i) {
- for (unsigned j=i+1; j<Tvecs[rl].size(); ++j) {
- ex & t1=Tvecs[rl][i];
- ex & t2=Tvecs[rl][j];
- GINAC_ASSERT(is_ex_exactly_of_type(t1,color)&&
- (ex_to_color(t1).type==color::color_T)&&
- (ex_to_color(t1).seq.size()==1));
- GINAC_ASSERT(is_ex_exactly_of_type(t2,color)&&
- (ex_to_color(t2).type==color::color_T)&&
- (ex_to_color(t2).seq.size()==1));
- const coloridx & idx1=ex_to_coloridx(ex_to_color(t1).seq[0]);
- const coloridx & idx2=ex_to_coloridx(ex_to_color(t2).seq[0]);
-
- if (idx1.is_equal(idx2) && idx1.is_symbolic()) {
- exvector S;
- for (unsigned k=i+1; k<j; ++k) {
- S.push_back(Tvecs[rl][k]);
- }
- t1=_ex1();
- t2=_ex1();
- ex term1=numeric(-1)/numeric(6)*nonsimplified_ncmul(recombine_color_string(
- delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
- for (unsigned k=i+1; k<j; ++k) {
- S.push_back(_ex1());
- }
- t1=color_trace_of_one_representation_label(S);
- ex term2=numeric(1)/numeric(2)*nonsimplified_ncmul(recombine_color_string(
- delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
- return simplify_color(term1+term2);
- }
- }
- }
- }
- }
-
- // FIXME: higher contractions
-
- return e;
-}
-
+ GINAC_ASSERT(is_ex_exactly_of_type(e,ncmul));
+
+ exvector delta8vec;
+ exvector fvec;
+ exvector dvec;
+ exvectorvector Tvecs;
+ Tvecs.resize(MAX_REPRESENTATION_LABELS);
+ exvectorvector ONEvecs;
+ ONEvecs.resize(MAX_REPRESENTATION_LABELS);
+ exvector unknownvec;
+
+ split_color_string_in_parts(ex_to_ncmul(e).get_factors(),delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
+
+ // search for T_k S T_k (=1/2 Tr(S) - 1/6 S)
+ for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+ if (Tvecs[rl].size()>=2) {
+ for (unsigned i=0; i<Tvecs[rl].size()-1; ++i) {
+ for (unsigned j=i+1; j<Tvecs[rl].size(); ++j) {
+ ex & t1=Tvecs[rl][i];
+ ex & t2=Tvecs[rl][j];
+ GINAC_ASSERT(is_ex_exactly_of_type(t1,color)&&
+ (ex_to_color(t1).type==color::color_T)&&
+ (ex_to_color(t1).seq.size()==1));
+ GINAC_ASSERT(is_ex_exactly_of_type(t2,color)&&
+ (ex_to_color(t2).type==color::color_T)&&
+ (ex_to_color(t2).seq.size()==1));
+ const coloridx & idx1=ex_to_coloridx(ex_to_color(t1).seq[0]);
+ const coloridx & idx2=ex_to_coloridx(ex_to_color(t2).seq[0]);
+
+ if (idx1.is_equal(idx2) && idx1.is_symbolic()) {
+ exvector S;
+ for (unsigned k=i+1; k<j; ++k) {
+ S.push_back(Tvecs[rl][k]);
+ }
+ t1=_ex1();
+ t2=_ex1();
+ ex term1=numeric(-1)/numeric(6)*nonsimplified_ncmul(recombine_color_string(
+ delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+ for (unsigned k=i+1; k<j; ++k) {
+ S.push_back(_ex1());
+ }
+ t1=color_trace_of_one_representation_label(S);
+ ex term2=numeric(1)/numeric(2)*nonsimplified_ncmul(recombine_color_string(
+ delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+ return simplify_color(term1+term2);
+ }
+ }
+ }
+ }
+ }
+
+ // FIXME: higher contractions
+
+ return e;
+}
+
ex simplify_color(const ex & e)
{
- // all simplification is done on expanded objects
- ex e_expanded=e.expand();
-
- // simplification of sum=sum of simplifications
- if (is_ex_exactly_of_type(e_expanded,add)) {
- ex sum=_ex0();
- for (unsigned i=0; i<e_expanded.nops(); ++i)
- sum += simplify_color(e_expanded.op(i));
-
- return sum;
- }
-
- // simplification of commutative product=commutative product of simplifications
- if (is_ex_exactly_of_type(e_expanded,mul)) {
- ex prod=_ex1();
- for (unsigned i=0; i<e_expanded.nops(); ++i)
- prod *= simplify_color(e_expanded.op(i));
-
- return prod;
- }
-
- // simplification of noncommutative product: test if everything is color
- if (is_ex_exactly_of_type(e_expanded,ncmul)) {
- bool all_color=true;
- for (unsigned i=0; i<e_expanded.nops(); ++i) {
- if (!is_ex_exactly_of_type(e_expanded.op(i),color)) {
- all_color=false;
- break;
- }
- }
- if (all_color) {
- return simplify_pure_color_string(e_expanded);
- }
- }
-
- // cannot do anything
- return e_expanded;
+ // all simplification is done on expanded objects
+ ex e_expanded=e.expand();
+
+ // simplification of sum=sum of simplifications
+ if (is_ex_exactly_of_type(e_expanded,add)) {
+ ex sum=_ex0();
+ for (unsigned i=0; i<e_expanded.nops(); ++i)
+ sum += simplify_color(e_expanded.op(i));
+
+ return sum;
+ }
+
+ // simplification of commutative product=commutative product of simplifications
+ if (is_ex_exactly_of_type(e_expanded,mul)) {
+ ex prod=_ex1();
+ for (unsigned i=0; i<e_expanded.nops(); ++i)
+ prod *= simplify_color(e_expanded.op(i));
+
+ return prod;
+ }
+
+ // simplification of noncommutative product: test if everything is color
+ if (is_ex_exactly_of_type(e_expanded,ncmul)) {
+ bool all_color=true;
+ for (unsigned i=0; i<e_expanded.nops(); ++i) {
+ if (!is_ex_exactly_of_type(e_expanded.op(i),color)) {
+ all_color=false;
+ break;
+ }
+ }
+ if (all_color) {
+ return simplify_pure_color_string(e_expanded);
+ }
+ }
+
+ // cannot do anything
+ return e_expanded;
}
ex brute_force_sum_color_indices(const ex & e)
{
- exvector iv_all=e.get_indices();
- exvector iv_double;
-
- // find double symbolic indices
- if (iv_all.size()<2) return e;
- for (exvector::const_iterator cit1=iv_all.begin(); cit1!=iv_all.end()-1; ++cit1) {
- GINAC_ASSERT(is_ex_of_type(*cit1,coloridx));
- for (exvector::const_iterator cit2=cit1+1; cit2!=iv_all.end(); ++cit2) {
- GINAC_ASSERT(is_ex_of_type(*cit2,coloridx));
- if (ex_to_coloridx(*cit1).is_symbolic() &&
- ex_to_coloridx(*cit1).is_equal(ex_to_coloridx(*cit2))) {
- iv_double.push_back(*cit1);
- break;
- }
- }
- }
-
- std::vector<int> counter;
- counter.resize(iv_double.size());
- int l;
- for (l=0; unsigned(l)<iv_double.size(); ++l) {
- counter[l]=1;
- }
-
- ex sum;
-
- while (1) {
- ex term = e;
- for (l=0; unsigned(l)<iv_double.size(); ++l) {
- term=term.subs(iv_double[l]==coloridx((unsigned)(counter[l])));
- //iv_double[l].print(cout);
- //cout << " " << counter[l] << " ";
- }
- //cout << endl;
- sum += term;
-
- // increment counter[]
- l = iv_double.size()-1;
- while ((l>=0)&&((++counter[l])>(int)COLOR_EIGHT)) {
- counter[l]=1;
- l--;
- }
- if (l<2) { std::cout << counter[0] << counter[1] << std::endl; }
- if (l<0) break;
- }
-
- return sum;
+ exvector iv_all=e.get_indices();
+ exvector iv_double;
+
+ // find double symbolic indices
+ if (iv_all.size()<2) return e;
+ for (exvector::const_iterator cit1=iv_all.begin(); cit1!=iv_all.end()-1; ++cit1) {
+ GINAC_ASSERT(is_ex_of_type(*cit1,coloridx));
+ for (exvector::const_iterator cit2=cit1+1; cit2!=iv_all.end(); ++cit2) {
+ GINAC_ASSERT(is_ex_of_type(*cit2,coloridx));
+ if (ex_to_coloridx(*cit1).is_symbolic() &&
+ ex_to_coloridx(*cit1).is_equal(ex_to_coloridx(*cit2))) {
+ iv_double.push_back(*cit1);
+ break;
+ }
+ }
+ }
+
+ std::vector<int> counter;
+ counter.resize(iv_double.size());
+ int l;
+ for (l=0; unsigned(l)<iv_double.size(); ++l) {
+ counter[l]=1;
+ }
+
+ ex sum;
+
+ while (1) {
+ ex term = e;
+ for (l=0; unsigned(l)<iv_double.size(); ++l) {
+ term=term.subs(iv_double[l]==coloridx((unsigned)(counter[l])));
+ //iv_double[l].print(cout);
+ //cout << " " << counter[l] << " ";
+ }
+ //cout << endl;
+ sum += term;
+
+ // increment counter[]
+ l = iv_double.size()-1;
+ while ((l>=0)&&((++counter[l])>(int)COLOR_EIGHT)) {
+ counter[l]=1;
+ l--;
+ }
+ if (l<2) { std::cout << counter[0] << counter[1] << std::endl; }
+ if (l<0) break;
+ }
+
+ return sum;
}
void append_exvector_to_exvector(exvector & dest, const exvector & source)
{
- for (exvector::const_iterator cit=source.begin(); cit!=source.end(); ++cit) {
- dest.push_back(*cit);
- }
+ for (exvector::const_iterator cit=source.begin(); cit!=source.end(); ++cit) {
+ dest.push_back(*cit);
+ }
}
#ifndef NO_NAMESPACE_GINAC
/** Base class for color object */
class color : public indexed
{
- GINAC_DECLARE_REGISTERED_CLASS(color, indexed)
+ GINAC_DECLARE_REGISTERED_CLASS(color, indexed)
// friends
- friend color color_ONE(unsigned rl);
- friend color color_T(const ex & a, unsigned rl);
- friend color color_f(const ex & a, const ex & b, const ex & c);
- friend color color_d(const ex & a, const ex & b, const ex & c);
- friend ex color_h(const ex & a, const ex & b, const ex & c);
- friend color color_delta8(const ex & a, const ex & b);
- friend unsigned subs_index_in_exvector(exvector & v, const ex & is, const ex & ir);
- friend void split_color_string_in_parts(const exvector & v, exvector & delta8vec,
- exvector & fvec, exvector & dvec,
- exvectorvector & Tvecs,
- exvectorvector & ONEvecs,
- exvector & unknownvec);
- friend exvector recombine_color_string(exvector & delta8vec, exvector & fvec,
- exvector & dvec, exvectorvector & Tvecs,
- exvectorvector & ONEvecs, exvector & unknownvec);
- friend ex color_trace_of_one_representation_label(const exvector & v);
- friend ex color_trace(const exvector & v, unsigned rl);
- friend ex simplify_pure_color_string(const ex & e);
- friend ex simplify_color(const ex & e);
-
-
+ friend color color_ONE(unsigned rl);
+ friend color color_T(const ex & a, unsigned rl);
+ friend color color_f(const ex & a, const ex & b, const ex & c);
+ friend color color_d(const ex & a, const ex & b, const ex & c);
+ friend ex color_h(const ex & a, const ex & b, const ex & c);
+ friend color color_delta8(const ex & a, const ex & b);
+ friend unsigned subs_index_in_exvector(exvector & v, const ex & is, const ex & ir);
+ friend void split_color_string_in_parts(const exvector & v, exvector & delta8vec,
+ exvector & fvec, exvector & dvec,
+ exvectorvector & Tvecs,
+ exvectorvector & ONEvecs,
+ exvector & unknownvec);
+ friend exvector recombine_color_string(exvector & delta8vec, exvector & fvec,
+ exvector & dvec, exvectorvector & Tvecs,
+ exvectorvector & ONEvecs, exvector & unknownvec);
+ friend ex color_trace_of_one_representation_label(const exvector & v);
+ friend ex color_trace(const exvector & v, unsigned rl);
+ friend ex simplify_pure_color_string(const ex & e);
+ friend ex simplify_color(const ex & e);
+
+
// types
public:
- typedef enum { invalid, // not properly constructed by one of the friend functions
- color_T,
- color_f,
- color_d,
- color_delta8,
- color_ONE
- } color_types;
-
+ typedef enum { invalid, // not properly constructed by one of the friend functions
+ color_T,
+ color_f,
+ color_d,
+ color_delta8,
+ color_ONE
+ } color_types;
+
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- color();
- ~color();
- color(const color & other);
- const color & operator=(const color & other);
+ color();
+ ~color();
+ color(const color & other);
+ const color & operator=(const color & other);
protected:
- void copy(const color & other);
- void destroy(bool call_parent);
+ void copy(const color & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
protected:
- color(color_types const t, unsigned rl=0);
- color(color_types const t, const ex & i1, unsigned rl=0);
- color(color_types const t, const ex & i1, const ex & i2, unsigned rl=0);
- color(color_types const t, const ex & i1, const ex & i2, const ex & i3,
- unsigned rl=0);
- color(color_types const t, const exvector & iv, unsigned rl=0);
- color(color_types const t, exvector * ivp, unsigned rl=0);
-
- // functions overriding virtual functions from base classes
+ color(color_types const t, unsigned rl=0);
+ color(color_types const t, const ex & i1, unsigned rl=0);
+ color(color_types const t, const ex & i1, const ex & i2, unsigned rl=0);
+ color(color_types const t, const ex & i1, const ex & i2, const ex & i3,
+ unsigned rl=0);
+ color(color_types const t, const exvector & iv, unsigned rl=0);
+ color(color_types const t, exvector * ivp, unsigned rl=0);
+
+ // functions overriding virtual functions from base classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
- ex eval(int level=0) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
+ ex eval(int level=0) const;
protected:
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- ex simplify_ncmul(const exvector & v) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ ex simplify_ncmul(const exvector & v) const;
+ ex thisexprseq(const exvector & v) const;
+ ex thisexprseq(exvector * vp) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
protected:
- bool all_of_type_coloridx(void) const;
-
+ bool all_of_type_coloridx(void) const;
+
// member variables
protected:
- color_types type;
- unsigned representation_label; // to distiguish independent color matrices coming from separated fermion lines
+ color_types type;
+ unsigned representation_label; // to distiguish independent color matrices coming from separated fermion lines
};
// global constants
ex color_h(const ex & a, const ex & b, const ex & c);
color color_delta8(const ex & a, const ex & b);
void split_color_string_in_parts(const exvector & v, exvector & delta8vec,
- exvector & fvec, exvector & dvec,
- exvectorvector & Tvecs,
- exvectorvector & ONEvecs,
- exvector & unknownvec);
+ exvector & fvec, exvector & dvec,
+ exvectorvector & Tvecs,
+ exvectorvector & ONEvecs,
+ exvector & unknownvec);
exvector recombine_color_string(exvector & delta8vec, exvector & fvec,
- exvector & dvec, exvectorvector & Tvecs,
- exvectorvector & ONEvecs, exvector & unknownvec);
+ exvector & dvec, exvectorvector & Tvecs,
+ exvectorvector & ONEvecs, exvector & unknownvec);
ex color_trace_of_one_representation_label(const exvector & v);
ex color_trace(const exvector & v, unsigned rl=0);
ex simplify_pure_color_string(const ex & e);
coloridx::coloridx()
{
- debugmsg("coloridx default constructor",LOGLEVEL_CONSTRUCT);
- // serial is incremented in idx::idx()
- name="color"+ToString(serial);
- tinfo_key=TINFO_coloridx;
+ debugmsg("coloridx default constructor",LOGLEVEL_CONSTRUCT);
+ // serial is incremented in idx::idx()
+ name="color"+ToString(serial);
+ tinfo_key=TINFO_coloridx;
}
coloridx::~coloridx()
{
- debugmsg("coloridx destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("coloridx destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
coloridx::coloridx(const coloridx & other)
{
- debugmsg("coloridx copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("coloridx copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const coloridx & coloridx::operator=(const coloridx & other)
{
- debugmsg("coloridx operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("coloridx operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void coloridx::copy(const coloridx & other)
{
- inherited::copy(other);
+ inherited::copy(other);
}
void coloridx::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
//////////
coloridx::coloridx(bool cov) : idx(cov)
{
- debugmsg("coloridx constructor from bool",LOGLEVEL_CONSTRUCT);
- // serial is incremented in idx::idx(bool)
- name="color"+ToString(serial);
- tinfo_key=TINFO_coloridx;
+ debugmsg("coloridx constructor from bool",LOGLEVEL_CONSTRUCT);
+ // serial is incremented in idx::idx(bool)
+ name="color"+ToString(serial);
+ tinfo_key=TINFO_coloridx;
}
coloridx::coloridx(const std::string & n, bool cov) : idx(n,cov)
{
- debugmsg("coloridx constructor from string,bool",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_coloridx;
+ debugmsg("coloridx constructor from string,bool",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_coloridx;
}
coloridx::coloridx(const char * n, bool cov) : idx(n,cov)
{
- debugmsg("coloridx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_coloridx;
+ debugmsg("coloridx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_coloridx;
}
coloridx::coloridx(unsigned v, bool cov) : idx(v,cov)
{
- debugmsg("coloridx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_coloridx;
+ debugmsg("coloridx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_coloridx;
}
//////////
/** Construct object from archive_node. */
coloridx::coloridx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("coloridx constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ debugmsg("coloridx constructor from archive_node", LOGLEVEL_CONSTRUCT);
}
/** Unarchive the object. */
ex coloridx::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new coloridx(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new coloridx(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void coloridx::archive(archive_node &n) const
{
- inherited::archive(n);
+ inherited::archive(n);
}
//////////
basic * coloridx::duplicate() const
{
- debugmsg("coloridx duplicate",LOGLEVEL_DUPLICATE);
- return new coloridx(*this);
+ debugmsg("coloridx duplicate",LOGLEVEL_DUPLICATE);
+ return new coloridx(*this);
}
void coloridx::printraw(std::ostream & os) const
{
- debugmsg("coloridx printraw",LOGLEVEL_PRINT);
+ debugmsg("coloridx printraw",LOGLEVEL_PRINT);
- os << "coloridx(";
+ os << "coloridx(";
- if (symbolic) {
- os << "symbolic,name=" << name;
- } else {
- os << "non symbolic,value=" << value;
- }
+ if (symbolic) {
+ os << "symbolic,name=" << name;
+ } else {
+ os << "non symbolic,value=" << value;
+ }
- if (covariant) {
- os << ",covariant";
- } else {
- os << ",contravariant";
- }
+ if (covariant) {
+ os << ",covariant";
+ } else {
+ os << ",contravariant";
+ }
- os << ",serial=" << serial;
- os << ",hash=" << hashvalue << ",flags=" << flags;
- os << ")";
+ os << ",serial=" << serial;
+ os << ",hash=" << hashvalue << ",flags=" << flags;
+ os << ")";
}
void coloridx::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("coloridx printtree",LOGLEVEL_PRINT);
+ debugmsg("coloridx printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "coloridx: ";
+ os << std::string(indent,' ') << "coloridx: ";
- if (symbolic) {
- os << "symbolic,name=" << name;
- } else {
- os << "non symbolic,value=" << value;
- }
+ if (symbolic) {
+ os << "symbolic,name=" << name;
+ } else {
+ os << "non symbolic,value=" << value;
+ }
- if (covariant) {
- os << ",covariant";
- } else {
- os << ",contravariant";
- }
+ if (covariant) {
+ os << ",covariant";
+ } else {
+ os << ",contravariant";
+ }
- os << ", serial=" << serial
- << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ os << ", serial=" << serial
+ << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void coloridx::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("coloridx print",LOGLEVEL_PRINT);
+ debugmsg("coloridx print",LOGLEVEL_PRINT);
- if (covariant) {
- os << "_";
- } else {
- os << "~";
- }
- if (symbolic) {
- os << name;
- } else {
- os << value;
- }
+ if (covariant) {
+ os << "_";
+ } else {
+ os << "~";
+ }
+ if (symbolic) {
+ os << name;
+ } else {
+ os << value;
+ }
}
bool coloridx::info(unsigned inf) const
{
- if (inf==info_flags::coloridx) return true;
- return idx::info(inf);
+ if (inf==info_flags::coloridx) return true;
+ return idx::info(inf);
}
//////////
class coloridx : public idx
{
- GINAC_DECLARE_REGISTERED_CLASS(coloridx, idx)
+ GINAC_DECLARE_REGISTERED_CLASS(coloridx, idx)
- friend class color;
+ friend class color;
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- coloridx();
- ~coloridx();
- coloridx (const coloridx & other);
- const coloridx & operator=(const coloridx & other);
+ coloridx();
+ ~coloridx();
+ coloridx (const coloridx & other);
+ const coloridx & operator=(const coloridx & other);
protected:
- void copy(const coloridx & other);
- void destroy(bool call_parent);
+ void copy(const coloridx & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- explicit coloridx(bool cov);
- explicit coloridx(const std::string & n, bool cov=false);
- explicit coloridx(const char * n, bool cov=false);
- explicit coloridx(unsigned v, bool cov=false);
+ explicit coloridx(bool cov);
+ explicit coloridx(const std::string & n, bool cov=false);
+ explicit coloridx(const char * n, bool cov=false);
+ explicit coloridx(unsigned v, bool cov=false);
- // functions overriding virtual functions from bases classes
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
- // new virtual functions which can be overridden by derived classes
- // none
+ // new virtual functions which can be overridden by derived classes
+ // none
- // non-virtual functions in this class
- // none
+ // non-virtual functions in this class
+ // none
- // member variables
- // none
+ // member variables
+ // none
};
// global constants
// public
constant::constant() :
- basic(TINFO_constant), name(""), ef(0),
- number(0), serial(next_serial++)
+ basic(TINFO_constant), name(""), ef(0),
+ number(0), serial(next_serial++)
{
- debugmsg("constant default constructor",LOGLEVEL_CONSTRUCT);
+ debugmsg("constant default constructor",LOGLEVEL_CONSTRUCT);
}
constant::~constant()
{
- debugmsg("constant destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("constant destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
constant::constant(const constant & other)
{
- debugmsg("constant copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("constant copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
// protected
void constant::copy(const constant & other)
{
- basic::copy(other);
- name=other.name;
- serial=other.serial;
- ef=other.ef;
- if (other.number != 0) {
- number = new numeric(*other.number);
- } else {
- number = 0;
- }
- // fct_assigned=other.fct_assigned;
+ basic::copy(other);
+ name=other.name;
+ serial=other.serial;
+ ef=other.ef;
+ if (other.number != 0) {
+ number = new numeric(*other.number);
+ } else {
+ number = 0;
+ }
+ // fct_assigned=other.fct_assigned;
}
void constant::destroy(bool call_parent)
{
- delete number;
- if (call_parent)
- basic::destroy(call_parent);
+ delete number;
+ if (call_parent)
+ basic::destroy(call_parent);
}
//////////
// public
constant::constant(const std::string & initname, evalffunctype efun) :
- basic(TINFO_constant), name(initname), ef(efun),
- // number(0), fct_assigned(true), serial(next_serial++)
- number(0), serial(next_serial++)
+ basic(TINFO_constant), name(initname), ef(efun),
+ // number(0), fct_assigned(true), serial(next_serial++)
+ number(0), serial(next_serial++)
{
- debugmsg("constant constructor from string, function",LOGLEVEL_CONSTRUCT);
+ debugmsg("constant constructor from string, function",LOGLEVEL_CONSTRUCT);
}
constant::constant(const std::string & initname, const numeric & initnumber) :
- basic(TINFO_constant), name(initname), ef(0),
- number(new numeric(initnumber)), /* fct_assigned(false),*/ serial(next_serial++)
+ basic(TINFO_constant), name(initname), ef(0),
+ number(new numeric(initnumber)), /* fct_assigned(false),*/ serial(next_serial++)
{
- debugmsg("constant constructor from string, numeric",LOGLEVEL_CONSTRUCT);
+ debugmsg("constant constructor from string, numeric",LOGLEVEL_CONSTRUCT);
}
//////////
/** Construct object from archive_node. */
constant::constant(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("constant constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ debugmsg("constant constructor from archive_node", LOGLEVEL_CONSTRUCT);
}
/** Unarchive the object. */
ex constant::unarchive(const archive_node &n, const lst &sym_lst)
{
- // Find constant by name (!! this is bad: 'twould be better if there
- // was a list of all global constants that we could search)
- std::string s;
- if (n.find_string("name", s)) {
- if (s == Pi.name)
- return Pi;
- else if (s == Catalan.name)
- return Catalan;
- else if (s == Euler.name)
- return Euler;
- else
- throw (std::runtime_error("unknown constant '" + s + "' in archive"));
- } else
- throw (std::runtime_error("unnamed constant in archive"));
+ // Find constant by name (!! this is bad: 'twould be better if there
+ // was a list of all global constants that we could search)
+ std::string s;
+ if (n.find_string("name", s)) {
+ if (s == Pi.name)
+ return Pi;
+ else if (s == Catalan.name)
+ return Catalan;
+ else if (s == Euler.name)
+ return Euler;
+ else
+ throw (std::runtime_error("unknown constant '" + s + "' in archive"));
+ } else
+ throw (std::runtime_error("unnamed constant in archive"));
}
/** Archive the object. */
void constant::archive(archive_node &n) const
{
- inherited::archive(n);
- n.add_string("name", name);
+ inherited::archive(n);
+ n.add_string("name", name);
}
//////////
basic * constant::duplicate() const
{
- debugmsg("constant duplicate",LOGLEVEL_DUPLICATE);
- return new constant(*this);
+ debugmsg("constant duplicate",LOGLEVEL_DUPLICATE);
+ return new constant(*this);
}
void constant::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("constant print",LOGLEVEL_PRINT);
- os << name;
+ debugmsg("constant print",LOGLEVEL_PRINT);
+ os << name;
}
void constant::printraw(std::ostream & os) const
{
- debugmsg("constant printraw",LOGLEVEL_PRINT);
- os << "constant(" << name << ")";
+ debugmsg("constant printraw",LOGLEVEL_PRINT);
+ os << "constant(" << name << ")";
}
void constant::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("constant printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << name
- << ", type=" << typeid(*this).name()
- << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("constant printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << name
+ << ", type=" << class_name()
+ << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void constant::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("constant print csrc",LOGLEVEL_PRINT);
- os << name;
+ debugmsg("constant print csrc",LOGLEVEL_PRINT);
+ os << name;
}
ex constant::evalf(int level) const
{
- if (ef!=0) {
- return ef();
- } else if (number != 0) {
- return *number;
- }
- return *this;
+ if (ef!=0) {
+ return ef();
+ } else if (number != 0) {
+ return *number;
+ }
+ return *this;
}
// protected
* @see ex::diff */
ex constant::derivative(const symbol & s) const
{
- return _ex0();
+ return _ex0();
}
int constant::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_exactly_of_type(other, constant));
- // const constant & o=static_cast<constant &>(const_cast<basic &>(other));
- // return name.compare(o.name);
- const constant *o = static_cast<const constant *>(&other);
- if (serial==o->serial) return 0;
- return serial < o->serial ? -1 : 1;
+ GINAC_ASSERT(is_exactly_of_type(other, constant));
+ // const constant & o=static_cast<constant &>(const_cast<basic &>(other));
+ // return name.compare(o.name);
+ const constant *o = static_cast<const constant *>(&other);
+ if (serial==o->serial) return 0;
+ return serial < o->serial ? -1 : 1;
}
bool constant::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(is_exactly_of_type(other, constant));
- const constant *o = static_cast<const constant *>(&other);
- return serial==o->serial;
+ GINAC_ASSERT(is_exactly_of_type(other, constant));
+ const constant *o = static_cast<const constant *>(&other);
+ return serial==o->serial;
}
//////////
#endif // ndef NO_NAMESPACE_GINAC
typedef ex (*evalffunctype)(void);
-
+
/** This class holds constants, symbols with specific numerical value. Each
* object of this class must either provide their own function to evaluate it
* to class numeric or provide the constant as a numeric (if it's an exact
* number). */
class constant : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(constant, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(constant, basic)
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- constant();
- ~constant();
- constant(const constant & other);
- // const constant & operator=(const constant & other); /* it's pervert! */
+ constant();
+ ~constant();
+ constant(const constant & other);
+ // const constant & operator=(const constant & other); /* it's pervert! */
protected:
- void copy(const constant & other);
- void destroy(bool call_parent);
+ void copy(const constant & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- constant(const std::string & initname, evalffunctype efun=0);
- constant(const std::string & initname, const numeric & initnumber);
+ constant(const std::string & initname, evalffunctype efun=0);
+ constant(const std::string & initname, const numeric & initnumber);
- // functions overriding virtual functions from bases classes
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
- ex evalf(int level=0) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ ex evalf(int level=0) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
- // non-virtual functions in this class
- // none
+ // non-virtual functions in this class
+ // none
// member variables
private:
- std::string name;
- evalffunctype ef;
- numeric * number;
- // bool fct_assigned;
- unsigned serial; //!< unique serial number for comparision
- static unsigned next_serial;
+ std::string name;
+ evalffunctype ef;
+ numeric * number;
+ // bool fct_assigned;
+ unsigned serial; //!< unique serial number for comparision
+ static unsigned next_serial;
};
// global constants
ex::ex() : bp(_ex0().bp)
{
- debugmsg("ex default constructor",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(_ex0().bp!=0);
- GINAC_ASSERT(_ex0().bp->flags & status_flags::dynallocated);
- GINAC_ASSERT(bp!=0);
- ++bp->refcount;
+ debugmsg("ex default constructor",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(_ex0().bp!=0);
+ GINAC_ASSERT(_ex0().bp->flags & status_flags::dynallocated);
+ GINAC_ASSERT(bp!=0);
+ ++bp->refcount;
}
ex::~ex()
{
- debugmsg("ex destructor",LOGLEVEL_DESTRUCT);
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- if (--bp->refcount == 0) {
- delete bp;
- }
+ debugmsg("ex destructor",LOGLEVEL_DESTRUCT);
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+ if (--bp->refcount == 0) {
+ delete bp;
+ }
}
ex::ex(const ex & other) : bp(other.bp)
{
- debugmsg("ex copy constructor",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- ++bp->refcount;
+ debugmsg("ex copy constructor",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
+ ++bp->refcount;
}
const ex & ex::operator=(const ex & other)
{
- debugmsg("ex operator=",LOGLEVEL_ASSIGNMENT);
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- GINAC_ASSERT(other.bp!=0);
- GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
- ++other.bp->refcount;
- basic * tmpbp=other.bp;
- if (--bp->refcount==0) {
- delete bp;
- }
- bp=tmpbp;
- return *this;
+ debugmsg("ex operator=",LOGLEVEL_ASSIGNMENT);
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+ GINAC_ASSERT(other.bp!=0);
+ GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
+ ++other.bp->refcount;
+ basic * tmpbp=other.bp;
+ if (--bp->refcount==0) {
+ delete bp;
+ }
+ bp=tmpbp;
+ return *this;
}
#endif // ndef INLINE_EX_CONSTRUCTORS
ex::ex(const basic & other)
{
- debugmsg("ex constructor from basic",LOGLEVEL_CONSTRUCT);
- construct_from_basic(other);
+ debugmsg("ex constructor from basic",LOGLEVEL_CONSTRUCT);
+ construct_from_basic(other);
}
ex::ex(int i)
{
- debugmsg("ex constructor from int",LOGLEVEL_CONSTRUCT);
- construct_from_int(i);
+ debugmsg("ex constructor from int",LOGLEVEL_CONSTRUCT);
+ construct_from_int(i);
}
ex::ex(unsigned int i)
{
- debugmsg("ex constructor from unsigned int",LOGLEVEL_CONSTRUCT);
- construct_from_uint(i);
+ debugmsg("ex constructor from unsigned int",LOGLEVEL_CONSTRUCT);
+ construct_from_uint(i);
}
ex::ex(long i)
{
- debugmsg("ex constructor from long",LOGLEVEL_CONSTRUCT);
- construct_from_long(i);
+ debugmsg("ex constructor from long",LOGLEVEL_CONSTRUCT);
+ construct_from_long(i);
}
ex::ex(unsigned long i)
{
- debugmsg("ex constructor from unsigned long",LOGLEVEL_CONSTRUCT);
- construct_from_ulong(i);
+ debugmsg("ex constructor from unsigned long",LOGLEVEL_CONSTRUCT);
+ construct_from_ulong(i);
}
ex::ex(double const d)
{
- debugmsg("ex constructor from double",LOGLEVEL_CONSTRUCT);
- construct_from_double(d);
+ debugmsg("ex constructor from double",LOGLEVEL_CONSTRUCT);
+ construct_from_double(d);
}
ex::ex(const std::string &s, const ex &l)
{
- debugmsg("ex constructor from string,lst",LOGLEVEL_CONSTRUCT);
- construct_from_string_and_lst(s, l);
+ debugmsg("ex constructor from string,lst",LOGLEVEL_CONSTRUCT);
+ construct_from_string_and_lst(s, l);
}
#endif // ndef INLINE_EX_CONSTRUCTORS
/** Swap the contents of two expressions. */
void ex::swap(ex & other)
{
- debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
+ debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- GINAC_ASSERT(other.bp!=0);
- GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
-
- basic * tmpbp=bp;
- bp=other.bp;
- other.bp=tmpbp;
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+ GINAC_ASSERT(other.bp!=0);
+ GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
+
+ basic * tmpbp=bp;
+ bp=other.bp;
+ other.bp=tmpbp;
}
/** Output formatted to be useful as ginsh input. */
void ex::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("ex print",LOGLEVEL_PRINT);
- GINAC_ASSERT(bp!=0);
- bp->print(os,upper_precedence);
+ debugmsg("ex print",LOGLEVEL_PRINT);
+ GINAC_ASSERT(bp!=0);
+ bp->print(os,upper_precedence);
}
void ex::printraw(std::ostream & os) const
{
- debugmsg("ex printraw",LOGLEVEL_PRINT);
- GINAC_ASSERT(bp!=0);
- os << "ex(";
- bp->printraw(os);
- os << ")";
+ debugmsg("ex printraw",LOGLEVEL_PRINT);
+ GINAC_ASSERT(bp!=0);
+ os << "ex(";
+ bp->printraw(os);
+ os << ")";
}
void ex::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("ex printtree",LOGLEVEL_PRINT);
- GINAC_ASSERT(bp!=0);
- // os << "refcount=" << bp->refcount << " ";
- bp->printtree(os,indent);
+ debugmsg("ex printtree",LOGLEVEL_PRINT);
+ GINAC_ASSERT(bp!=0);
+ // os << "refcount=" << bp->refcount << " ";
+ bp->printtree(os,indent);
}
/** Print expression as a C++ statement. The output looks like
* @param var_name variable name to be printed */
void ex::printcsrc(std::ostream & os, unsigned type, const char *var_name) const
{
- debugmsg("ex print csrc", LOGLEVEL_PRINT);
- GINAC_ASSERT(bp!=0);
- switch (type) {
- case csrc_types::ctype_float:
- os << "float ";
- break;
- case csrc_types::ctype_double:
- os << "double ";
- break;
- case csrc_types::ctype_cl_N:
- os << "cl_N ";
- break;
- }
- os << var_name << " = ";
- bp->printcsrc(os, type, 0);
- os << ";\n";
+ debugmsg("ex print csrc", LOGLEVEL_PRINT);
+ GINAC_ASSERT(bp!=0);
+ switch (type) {
+ case csrc_types::ctype_float:
+ os << "float ";
+ break;
+ case csrc_types::ctype_double:
+ os << "double ";
+ break;
+ case csrc_types::ctype_cl_N:
+ os << "cl_N ";
+ break;
+ }
+ os << var_name << " = ";
+ bp->printcsrc(os, type, 0);
+ os << ";\n";
}
/** Little wrapper arount print to be called within a debugger. */
void ex::dbgprint(void) const
{
- debugmsg("ex dbgprint",LOGLEVEL_PRINT);
- GINAC_ASSERT(bp!=0);
- bp->dbgprint();
+ debugmsg("ex dbgprint",LOGLEVEL_PRINT);
+ GINAC_ASSERT(bp!=0);
+ bp->dbgprint();
}
/** Little wrapper arount printtree to be called within a debugger. */
void ex::dbgprinttree(void) const
{
- debugmsg("ex dbgprinttree",LOGLEVEL_PRINT);
- GINAC_ASSERT(bp!=0);
- bp->dbgprinttree();
+ debugmsg("ex dbgprinttree",LOGLEVEL_PRINT);
+ GINAC_ASSERT(bp!=0);
+ bp->dbgprinttree();
}
bool ex::info(unsigned inf) const
{
- return bp->info(inf);
+ return bp->info(inf);
}
unsigned ex::nops() const
{
- GINAC_ASSERT(bp!=0);
- return bp->nops();
+ GINAC_ASSERT(bp!=0);
+ return bp->nops();
}
ex ex::expand(unsigned options) const
{
- GINAC_ASSERT(bp!=0);
- if (bp->flags & status_flags::expanded)
- return *bp;
- else
- return bp->expand(options);
+ GINAC_ASSERT(bp!=0);
+ if (bp->flags & status_flags::expanded)
+ return *bp;
+ else
+ return bp->expand(options);
}
bool ex::has(const ex & other) const
{
- GINAC_ASSERT(bp!=0);
- return bp->has(other);
+ GINAC_ASSERT(bp!=0);
+ return bp->has(other);
}
int ex::degree(const symbol & s) const
{
- GINAC_ASSERT(bp!=0);
- return bp->degree(s);
+ GINAC_ASSERT(bp!=0);
+ return bp->degree(s);
}
int ex::ldegree(const symbol & s) const
{
- GINAC_ASSERT(bp!=0);
- return bp->ldegree(s);
+ GINAC_ASSERT(bp!=0);
+ return bp->ldegree(s);
}
ex ex::coeff(const symbol & s, int n) const
{
- GINAC_ASSERT(bp!=0);
- return bp->coeff(s,n);
+ GINAC_ASSERT(bp!=0);
+ return bp->coeff(s,n);
}
ex ex::collect(const symbol & s) const
{
- GINAC_ASSERT(bp!=0);
- return bp->collect(s);
+ GINAC_ASSERT(bp!=0);
+ return bp->collect(s);
}
ex ex::eval(int level) const
{
- GINAC_ASSERT(bp!=0);
- return bp->eval(level);
+ GINAC_ASSERT(bp!=0);
+ return bp->eval(level);
}
ex ex::evalf(int level) const
{
- GINAC_ASSERT(bp!=0);
- return bp->evalf(level);
+ GINAC_ASSERT(bp!=0);
+ return bp->evalf(level);
}
/** Compute partial derivative of an expression.
* @return partial derivative as a new expression */
ex ex::diff(const symbol & s, unsigned nth) const
{
- GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp!=0);
- if (!nth)
- return *this;
- else
- return bp->diff(s, nth);
+ if (!nth)
+ return *this;
+ else
+ return bp->diff(s, nth);
}
ex ex::subs(const lst & ls, const lst & lr) const
{
- GINAC_ASSERT(bp!=0);
- return bp->subs(ls,lr);
+ GINAC_ASSERT(bp!=0);
+ return bp->subs(ls,lr);
}
ex ex::subs(const ex & e) const
{
- GINAC_ASSERT(bp!=0);
- return bp->subs(e);
+ GINAC_ASSERT(bp!=0);
+ return bp->subs(e);
}
exvector ex::get_indices(void) const
{
- GINAC_ASSERT(bp!=0);
- return bp->get_indices();
+ GINAC_ASSERT(bp!=0);
+ return bp->get_indices();
}
ex ex::simplify_ncmul(const exvector & v) const
{
- GINAC_ASSERT(bp!=0);
- return bp->simplify_ncmul(v);
+ GINAC_ASSERT(bp!=0);
+ return bp->simplify_ncmul(v);
}
ex ex::operator[](const ex & index) const
{
- debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
- GINAC_ASSERT(bp!=0);
- return (*bp)[index];
+ debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
+ GINAC_ASSERT(bp!=0);
+ return (*bp)[index];
}
ex ex::operator[](int i) const
{
- debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
- GINAC_ASSERT(bp!=0);
- return (*bp)[i];
+ debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
+ GINAC_ASSERT(bp!=0);
+ return (*bp)[i];
}
/** Return operand/member at position i. */
ex ex::op(int i) const
{
- debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
- GINAC_ASSERT(bp!=0);
- return bp->op(i);
+ debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
+ GINAC_ASSERT(bp!=0);
+ return bp->op(i);
}
/** Return modifyable operand/member at position i. */
ex & ex::let_op(int i)
{
- debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
- makewriteable();
- GINAC_ASSERT(bp!=0);
- return bp->let_op(i);
+ debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
+ makewriteable();
+ GINAC_ASSERT(bp!=0);
+ return bp->let_op(i);
}
/** Left hand side of relational expression. */
ex ex::lhs(void) const
{
- debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
- GINAC_ASSERT(is_ex_of_type(*this,relational));
- return (*static_cast<relational *>(bp)).lhs();
+ debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
+ GINAC_ASSERT(is_ex_of_type(*this,relational));
+ return (*static_cast<relational *>(bp)).lhs();
}
/** Right hand side of relational expression. */
ex ex::rhs(void) const
{
- debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
- GINAC_ASSERT(is_ex_of_type(*this,relational));
- return (*static_cast<relational *>(bp)).rhs();
+ debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
+ GINAC_ASSERT(is_ex_of_type(*this,relational));
+ return (*static_cast<relational *>(bp)).rhs();
}
#ifndef INLINE_EX_CONSTRUCTORS
int ex::compare(const ex & other) const
{
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(other.bp!=0);
- if (bp==other.bp) {
- // special case: both expression point to same basic, trivially equal
- return 0;
- }
- return bp->compare(*other.bp);
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(other.bp!=0);
+ if (bp==other.bp) {
+ // special case: both expression point to same basic, trivially equal
+ return 0;
+ }
+ return bp->compare(*other.bp);
}
#endif // ndef INLINE_EX_CONSTRUCTORS
#ifndef INLINE_EX_CONSTRUCTORS
bool ex::is_equal(const ex & other) const
{
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(other.bp!=0);
- // if both expression point to same basic they are trivially equal
- if (bp==other.bp)
- return true;
-
- return bp->is_equal(*other.bp);
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(other.bp!=0);
+ // if both expression point to same basic they are trivially equal
+ if (bp==other.bp)
+ return true;
+
+ return bp->is_equal(*other.bp);
}
#endif // ndef INLINE_EX_CONSTRUCTORS
unsigned ex::return_type(void) const
{
- GINAC_ASSERT(bp!=0);
- return bp->return_type();
+ GINAC_ASSERT(bp!=0);
+ return bp->return_type();
}
unsigned ex::return_type_tinfo(void) const
{
- GINAC_ASSERT(bp!=0);
- return bp->return_type_tinfo();
+ GINAC_ASSERT(bp!=0);
+ return bp->return_type_tinfo();
}
unsigned ex::gethash(void) const
{
- GINAC_ASSERT(bp!=0);
- return bp->gethash();
+ GINAC_ASSERT(bp!=0);
+ return bp->gethash();
}
ex ex::exadd(const ex & rh) const
{
- return (new add(*this,rh))->setflag(status_flags::dynallocated);
+ return (new add(*this,rh))->setflag(status_flags::dynallocated);
}
ex ex::exmul(const ex & rh) const
{
- return (new mul(*this,rh))->setflag(status_flags::dynallocated);
+ return (new mul(*this,rh))->setflag(status_flags::dynallocated);
}
ex ex::exncmul(const ex & rh) const
{
- return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
+ return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
}
// private
void ex::makewriteable()
{
- debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- if (bp->refcount > 1) {
- basic * bp2 = bp->duplicate();
- ++bp2->refcount;
- bp2->setflag(status_flags::dynallocated);
- --bp->refcount;
- bp = bp2;
- }
- GINAC_ASSERT(bp->refcount == 1);
+ debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+ if (bp->refcount > 1) {
+ basic * bp2 = bp->duplicate();
+ ++bp2->refcount;
+ bp2->setflag(status_flags::dynallocated);
+ --bp->refcount;
+ bp = bp2;
+ }
+ GINAC_ASSERT(bp->refcount == 1);
}
void ex::construct_from_basic(const basic & other)
{
- if ((other.flags & status_flags::evaluated)==0) {
- // cf. copy constructor
- const ex & tmpex = other.eval(1); // evaluate only one (top) level
- bp = tmpex.bp;
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- ++bp->refcount;
- if ((other.flags & status_flags::dynallocated)&&(other.refcount==0)) {
- delete &const_cast<basic &>(other);
- }
- } else {
- if (other.flags & status_flags::dynallocated) {
- // it's on the heap, so just copy bp:
- bp = &const_cast<basic &>(other);
- } else {
- // create a duplicate on the heap:
- bp = other.duplicate();
- bp->setflag(status_flags::dynallocated);
- }
- GINAC_ASSERT(bp!=0);
- // bp->clearflag(status_flags::evaluated);
- ++bp->refcount;
- }
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+ if ((other.flags & status_flags::evaluated)==0) {
+ // cf. copy constructor
+ const ex & tmpex = other.eval(1); // evaluate only one (top) level
+ bp = tmpex.bp;
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+ ++bp->refcount;
+ if ((other.flags & status_flags::dynallocated)&&(other.refcount==0)) {
+ delete &const_cast<basic &>(other);
+ }
+ } else {
+ if (other.flags & status_flags::dynallocated) {
+ // it's on the heap, so just copy bp:
+ bp = &const_cast<basic &>(other);
+ } else {
+ // create a duplicate on the heap:
+ bp = other.duplicate();
+ bp->setflag(status_flags::dynallocated);
+ }
+ GINAC_ASSERT(bp!=0);
+ // bp->clearflag(status_flags::evaluated);
+ ++bp->refcount;
+ }
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
}
void ex::construct_from_int(int i)
{
- switch (i) { // some tiny efficiency-hack
- case -2:
- bp = _ex_2().bp;
- ++bp->refcount;
- break;
- case -1:
- bp = _ex_1().bp;
- ++bp->refcount;
- break;
- case 0:
- bp = _ex0().bp;
- ++bp->refcount;
- break;
- case 1:
- bp = _ex1().bp;
- ++bp->refcount;
- break;
- case 2:
- bp = _ex2().bp;
- ++bp->refcount;
- break;
- default:
- bp = new numeric(i);
- bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount=1);
- }
-}
-
+ switch (i) { // some tiny efficiency-hack
+ case -2:
+ bp = _ex_2().bp;
+ ++bp->refcount;
+ break;
+ case -1:
+ bp = _ex_1().bp;
+ ++bp->refcount;
+ break;
+ case 0:
+ bp = _ex0().bp;
+ ++bp->refcount;
+ break;
+ case 1:
+ bp = _ex1().bp;
+ ++bp->refcount;
+ break;
+ case 2:
+ bp = _ex2().bp;
+ ++bp->refcount;
+ break;
+ default:
+ bp = new numeric(i);
+ bp->setflag(status_flags::dynallocated);
+ ++bp->refcount;
+ GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
+ GINAC_ASSERT(bp->refcount=1);
+ }
+}
+
void ex::construct_from_uint(unsigned int i)
{
- switch (i) { // some tiny efficiency-hack
- case -2:
- bp = _ex_2().bp;
- ++bp->refcount;
- break;
- case -1:
- bp = _ex_1().bp;
- ++bp->refcount;
- break;
- case 0:
- bp = _ex0().bp;
- ++bp->refcount;
- break;
- case 1:
- bp = _ex1().bp;
- ++bp->refcount;
- break;
- case 2:
- bp = _ex2().bp;
- ++bp->refcount;
- break;
- default:
- bp = new numeric(i);
- bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount=1);
- }
-}
-
+ switch (i) { // some tiny efficiency-hack
+ case -2:
+ bp = _ex_2().bp;
+ ++bp->refcount;
+ break;
+ case -1:
+ bp = _ex_1().bp;
+ ++bp->refcount;
+ break;
+ case 0:
+ bp = _ex0().bp;
+ ++bp->refcount;
+ break;
+ case 1:
+ bp = _ex1().bp;
+ ++bp->refcount;
+ break;
+ case 2:
+ bp = _ex2().bp;
+ ++bp->refcount;
+ break;
+ default:
+ bp = new numeric(i);
+ bp->setflag(status_flags::dynallocated);
+ ++bp->refcount;
+ GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
+ GINAC_ASSERT(bp->refcount=1);
+ }
+}
+
void ex::construct_from_long(long i)
{
- switch (i) { // some tiny efficiency-hack
- case -2:
- bp = _ex_2().bp;
- ++bp->refcount;
- break;
- case -1:
- bp = _ex_1().bp;
- ++bp->refcount;
- break;
- case 0:
- bp = _ex0().bp;
- ++bp->refcount;
- break;
- case 1:
- bp = _ex1().bp;
- ++bp->refcount;
- break;
- case 2:
- bp = _ex2().bp;
- ++bp->refcount;
- break;
- default:
- bp = new numeric(i);
- bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount=1);
- }
-}
-
+ switch (i) { // some tiny efficiency-hack
+ case -2:
+ bp = _ex_2().bp;
+ ++bp->refcount;
+ break;
+ case -1:
+ bp = _ex_1().bp;
+ ++bp->refcount;
+ break;
+ case 0:
+ bp = _ex0().bp;
+ ++bp->refcount;
+ break;
+ case 1:
+ bp = _ex1().bp;
+ ++bp->refcount;
+ break;
+ case 2:
+ bp = _ex2().bp;
+ ++bp->refcount;
+ break;
+ default:
+ bp = new numeric(i);
+ bp->setflag(status_flags::dynallocated);
+ ++bp->refcount;
+ GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
+ GINAC_ASSERT(bp->refcount=1);
+ }
+}
+
void ex::construct_from_ulong(unsigned long i)
{
- switch (i) { // some tiny efficiency-hack
- case -2:
- bp = _ex_2().bp;
- ++bp->refcount;
- break;
- case -1:
- bp = _ex_1().bp;
- ++bp->refcount;
- break;
- case 0:
- bp = _ex0().bp;
- ++bp->refcount;
- break;
- case 1:
- bp = _ex1().bp;
- ++bp->refcount;
- break;
- case 2:
- bp = _ex2().bp;
- ++bp->refcount;
- break;
- default:
- bp = new numeric(i);
- bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount=1);
- }
-}
-
+ switch (i) { // some tiny efficiency-hack
+ case -2:
+ bp = _ex_2().bp;
+ ++bp->refcount;
+ break;
+ case -1:
+ bp = _ex_1().bp;
+ ++bp->refcount;
+ break;
+ case 0:
+ bp = _ex0().bp;
+ ++bp->refcount;
+ break;
+ case 1:
+ bp = _ex1().bp;
+ ++bp->refcount;
+ break;
+ case 2:
+ bp = _ex2().bp;
+ ++bp->refcount;
+ break;
+ default:
+ bp = new numeric(i);
+ bp->setflag(status_flags::dynallocated);
+ ++bp->refcount;
+ GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
+ GINAC_ASSERT(bp->refcount=1);
+ }
+}
+
void ex::construct_from_double(double d)
{
- bp = new numeric(d);
- bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount=1);
+ bp = new numeric(d);
+ bp->setflag(status_flags::dynallocated);
+ ++bp->refcount;
+ GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
+ GINAC_ASSERT(bp->refcount=1);
}
void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
{
- set_lexer_string(s);
- set_lexer_symbols(l);
- ginac_yyrestart(NULL);
- if (ginac_yyparse())
- throw (std::runtime_error(get_parser_error()));
- else {
- bp = parsed_ex.bp;
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- ++bp->refcount;
- }
-}
-
+ set_lexer_string(s);
+ set_lexer_symbols(l);
+ ginac_yyrestart(NULL);
+ if (ginac_yyparse())
+ throw (std::runtime_error(get_parser_error()));
+ else {
+ bp = parsed_ex.bp;
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
+ ++bp->refcount;
+ }
+}
+
//////////
// static member variables
//////////
* provide methods for manipulation of these objects. */
class ex
{
- friend class basic;
+ friend class basic;
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- ex()
+ ex()
#ifdef INLINE_EX_CONSTRUCTORS
- : bp(_ex0().bp)
- {
- GINAC_ASSERT(_ex0().bp!=0);
- GINAC_ASSERT(_ex0().bp->flags & status_flags::dynallocated);
- GINAC_ASSERT(bp!=0);
- ++bp->refcount;
+ : bp(_ex0().bp)
+ {
+ GINAC_ASSERT(_ex0().bp!=0);
+ GINAC_ASSERT(_ex0().bp->flags & status_flags::dynallocated);
+ GINAC_ASSERT(bp!=0);
+ ++bp->refcount;
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
- ~ex()
+ ~ex()
#ifdef INLINE_EX_CONSTRUCTORS
- {
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- if (--bp->refcount == 0) {
- delete bp;
- }
- }
+ {
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+ if (--bp->refcount == 0) {
+ delete bp;
+ }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
-
- ex(const ex & other)
+
+ ex(const ex & other)
#ifdef INLINE_EX_CONSTRUCTORS
- : bp(other.bp)
- {
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- ++bp->refcount;
+ : bp(other.bp)
+ {
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
+ ++bp->refcount;
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
-
- const ex & operator=(const ex & other)
+
+ const ex & operator=(const ex & other)
#ifdef INLINE_EX_CONSTRUCTORS
- {
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- GINAC_ASSERT(other.bp!=0);
- GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
- ++other.bp->refcount;
- basic * tmpbp=other.bp;
- if (--bp->refcount==0) {
- delete bp;
- }
- bp=tmpbp;
+ {
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+ GINAC_ASSERT(other.bp!=0);
+ GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
+ ++other.bp->refcount;
+ basic * tmpbp=other.bp;
+ if (--bp->refcount==0) {
+ delete bp;
+ }
+ bp=tmpbp;
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- return *this;
- }
+ return *this;
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
- // other constructors
+ // other constructors
public:
- ex(const basic & other)
+ ex(const basic & other)
#ifdef INLINE_EX_CONSTRUCTORS
- {
- construct_from_basic(other);
+ {
+ construct_from_basic(other);
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
-
- ex(int i)
+
+ ex(int i)
#ifdef INLINE_EX_CONSTRUCTORS
- {
- construct_from_int(i);
+ {
+ construct_from_int(i);
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
- ex(unsigned int i)
+ ex(unsigned int i)
#ifdef INLINE_EX_CONSTRUCTORS
- {
- construct_from_uint(i);
+ {
+ construct_from_uint(i);
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
-
- ex(long i)
+
+ ex(long i)
#ifdef INLINE_EX_CONSTRUCTORS
- {
- construct_from_long(i);
+ {
+ construct_from_long(i);
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
- ex(unsigned long i)
+ ex(unsigned long i)
#ifdef INLINE_EX_CONSTRUCTORS
- {
- construct_from_ulong(i);
+ {
+ construct_from_ulong(i);
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
-
- ex(double const d)
+
+ ex(double const d)
#ifdef INLINE_EX_CONSTRUCTORS
- {
- construct_from_double(d);
+ {
+ construct_from_double(d);
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
- /** Construct ex from string and a list of symbols. The input grammar is
- * similar to the GiNaC output format. All symbols to be used in the
- * expression must be specified in a lst in the second argument. Undefined
- * symbols and other parser errors will throw an exception. */
- ex(const std::string &s, const ex &l)
+ /** Construct ex from string and a list of symbols. The input grammar is
+ * similar to the GiNaC output format. All symbols to be used in the
+ * expression must be specified in a lst in the second argument. Undefined
+ * symbols and other parser errors will throw an exception. */
+ ex(const std::string &s, const ex &l)
#ifdef INLINE_EX_CONSTRUCTORS
- {
- construct_from_string_and_lst(s, l);
+ {
+ construct_from_string_and_lst(s, l);
#ifdef OBSCURE_CINT_HACK
- update_last_created_or_assigned_bp();
+ update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
- }
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
-
- // functions overriding virtual functions from bases classes
- // none
-
- // new virtual functions which can be overridden by derived classes
- // none
+
+ // functions overriding virtual functions from bases classes
+ // none
+
+ // new virtual functions which can be overridden by derived classes
+ // none
- // non-virtual functions in this class
+ // non-virtual functions in this class
public:
- void swap(ex & other);
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent=0) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printcsrc(std::ostream & os, unsigned type, const char *var_name) const;
- void dbgprint(void) const;
- void dbgprinttree(void) const;
- bool info(unsigned inf) const;
- unsigned nops() const;
- ex expand(unsigned options=0) const;
- bool has(const ex & other) const;
- int degree(const symbol & s) const;
- int ldegree(const symbol & s) const;
- ex coeff(const symbol & s, int n=1) const;
- ex lcoeff(const symbol & s) const { return coeff(s, degree(s)); }
- ex tcoeff(const symbol & s) const { return coeff(s, ldegree(s)); }
- ex numer(void) const;
- ex denom(void) const;
- ex unit(const symbol &x) const;
- ex content(const symbol &x) const;
- numeric integer_content(void) const;
- ex primpart(const symbol &x) const;
- ex primpart(const symbol &x, const ex &cont) const;
- ex normal(int level = 0) const;
- ex to_rational(lst &repl_lst) const;
- ex smod(const numeric &xi) const;
- numeric max_coefficient(void) const;
- ex collect(const symbol & s) const;
- ex eval(int level = 0) const;
- ex evalf(int level = 0) const;
- ex diff(const symbol & s, unsigned nth = 1) const;
- ex series(const ex & r, int order, unsigned options = 0) const;
- ex subs(const lst & ls, const lst & lr) const;
- ex subs(const ex & e) const;
- exvector get_indices(void) const;
- ex simplify_ncmul(const exvector & v) const;
- ex operator[](const ex & index) const;
- ex operator[](int i) const;
- ex op(int i) const;
- ex & let_op(int i);
- ex lhs(void) const;
- ex rhs(void) const;
- int compare(const ex & other) const
+ void swap(ex & other);
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent=0) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printcsrc(std::ostream & os, unsigned type, const char *var_name) const;
+ void dbgprint(void) const;
+ void dbgprinttree(void) const;
+ bool info(unsigned inf) const;
+ unsigned nops() const;
+ ex expand(unsigned options=0) const;
+ bool has(const ex & other) const;
+ int degree(const symbol & s) const;
+ int ldegree(const symbol & s) const;
+ ex coeff(const symbol & s, int n=1) const;
+ ex lcoeff(const symbol & s) const { return coeff(s, degree(s)); }
+ ex tcoeff(const symbol & s) const { return coeff(s, ldegree(s)); }
+ ex numer(void) const;
+ ex denom(void) const;
+ ex unit(const symbol &x) const;
+ ex content(const symbol &x) const;
+ numeric integer_content(void) const;
+ ex primpart(const symbol &x) const;
+ ex primpart(const symbol &x, const ex &cont) const;
+ ex normal(int level = 0) const;
+ ex to_rational(lst &repl_lst) const;
+ ex smod(const numeric &xi) const;
+ numeric max_coefficient(void) const;
+ ex collect(const symbol & s) const;
+ ex eval(int level = 0) const;
+ ex evalf(int level = 0) const;
+ ex diff(const symbol & s, unsigned nth = 1) const;
+ ex series(const ex & r, int order, unsigned options = 0) const;
+ ex subs(const lst & ls, const lst & lr) const;
+ ex subs(const ex & e) const;
+ exvector get_indices(void) const;
+ ex simplify_ncmul(const exvector & v) const;
+ ex operator[](const ex & index) const;
+ ex operator[](int i) const;
+ ex op(int i) const;
+ ex & let_op(int i);
+ ex lhs(void) const;
+ ex rhs(void) const;
+ int compare(const ex & other) const
#ifdef INLINE_EX_CONSTRUCTORS
- {
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(other.bp!=0);
- if (bp==other.bp) {
- // special case: both expression point to same basic, trivially equal
- return 0;
- }
- return bp->compare(*other.bp);
- }
+ {
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(other.bp!=0);
+ if (bp==other.bp) {
+ // special case: both expression point to same basic, trivially equal
+ return 0;
+ }
+ return bp->compare(*other.bp);
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
- bool is_equal(const ex & other) const
+ bool is_equal(const ex & other) const
#ifdef INLINE_EX_CONSTRUCTORS
- {
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(other.bp!=0);
- if (bp==other.bp) {
- // special case: both expression point to same basic, trivially equal
- return true;
- }
- return bp->is_equal(*other.bp);
- }
+ {
+ GINAC_ASSERT(bp!=0);
+ GINAC_ASSERT(other.bp!=0);
+ if (bp==other.bp) {
+ // special case: both expression point to same basic, trivially equal
+ return true;
+ }
+ return bp->is_equal(*other.bp);
+ }
#else
;
#endif // def INLINE_EX_CONSTRUCTORS
- bool is_zero(void) const {return compare(_ex0())==0;};
-
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- unsigned gethash(void) const;
-
- ex exadd(const ex & rh) const;
- ex exmul(const ex & rh) const;
- ex exncmul(const ex & rh) const;
+ bool is_zero(void) const {return compare(_ex0())==0;};
+
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+ unsigned gethash(void) const;
+
+ ex exadd(const ex & rh) const;
+ ex exmul(const ex & rh) const;
+ ex exncmul(const ex & rh) const;
private:
- void construct_from_basic(const basic & other);
- void construct_from_int(int i);
- void construct_from_uint(unsigned int i);
- void construct_from_long(long i);
- void construct_from_ulong(unsigned long i);
- void construct_from_double(double d);
- void construct_from_string_and_lst(const std::string &s, const ex &l);
- void makewriteable();
+ void construct_from_basic(const basic & other);
+ void construct_from_int(int i);
+ void construct_from_uint(unsigned int i);
+ void construct_from_long(long i);
+ void construct_from_ulong(unsigned long i);
+ void construct_from_double(double d);
+ void construct_from_string_and_lst(const std::string &s, const ex &l);
+ void makewriteable();
#ifdef OBSCURE_CINT_HACK
public:
- static bool last_created_or_assigned_bp_can_be_converted_to_ex(void)
- {
- if (last_created_or_assigned_bp==0) return false;
- if ((last_created_or_assigned_bp->flags &
- status_flags::dynallocated)==0) return false;
- if ((last_created_or_assigned_bp->flags &
- status_flags::evaluated)==0) return false;
- return true;
- }
+ static bool last_created_or_assigned_bp_can_be_converted_to_ex(void)
+ {
+ if (last_created_or_assigned_bp==0) return false;
+ if ((last_created_or_assigned_bp->flags &
+ status_flags::dynallocated)==0) return false;
+ if ((last_created_or_assigned_bp->flags &
+ status_flags::evaluated)==0) return false;
+ return true;
+ }
protected:
- void update_last_created_or_assigned_bp(void)
- {
- if (last_created_or_assigned_bp!=0) {
- if (--last_created_or_assigned_bp->refcount == 0) {
- delete last_created_or_assigned_bp;
- }
- }
- last_created_or_assigned_bp=bp;
- ++last_created_or_assigned_bp->refcount;
- last_created_or_assigned_exp=(long)(void *)(this);
- }
+ void update_last_created_or_assigned_bp(void)
+ {
+ if (last_created_or_assigned_bp!=0) {
+ if (--last_created_or_assigned_bp->refcount == 0) {
+ delete last_created_or_assigned_bp;
+ }
+ }
+ last_created_or_assigned_bp=bp;
+ ++last_created_or_assigned_bp->refcount;
+ last_created_or_assigned_exp=(long)(void *)(this);
+ }
#endif // def OBSCURE_CINT_HACK
// member variables
public:
- basic *bp;
+ basic *bp;
#ifdef OBSCURE_CINT_HACK
- static basic * last_created_or_assigned_bp;
- static basic * dummy_bp;
- static long last_created_or_assigned_exp;
+ static basic * last_created_or_assigned_bp;
+ static basic * dummy_bp;
+ static long last_created_or_assigned_exp;
#endif // def OBSCURE_CINT_HACK
};
class expair
{
public:
- expair() {}
- ~expair() {}
- expair(const expair & other) : rest(other.rest), coeff(other.coeff)
- {
- GINAC_ASSERT(is_ex_exactly_of_type(coeff,numeric));
- }
- const expair & operator=(const expair & other)
- {
- if (this != &other) {
- rest=other.rest;
- coeff=other.coeff;
- }
- return *this;
- }
- expair(const ex & r, const ex & c) : rest(r), coeff(c)
- {
- GINAC_ASSERT(is_ex_exactly_of_type(coeff,numeric));
- }
-
- bool is_numeric_with_coeff_1(void) const
- {
- GINAC_ASSERT(is_ex_exactly_of_type(coeff,numeric));
- return is_ex_exactly_of_type(rest,numeric) &&
- (coeff.is_equal(ex(1)));
- }
+ expair() {}
+ ~expair() {}
+ expair(const expair & other) : rest(other.rest), coeff(other.coeff)
+ {
+ GINAC_ASSERT(is_ex_exactly_of_type(coeff,numeric));
+ }
+ const expair & operator=(const expair & other)
+ {
+ if (this != &other) {
+ rest=other.rest;
+ coeff=other.coeff;
+ }
+ return *this;
+ }
+ expair(const ex & r, const ex & c) : rest(r), coeff(c)
+ {
+ GINAC_ASSERT(is_ex_exactly_of_type(coeff,numeric));
+ }
+
+ bool is_numeric_with_coeff_1(void) const
+ {
+ GINAC_ASSERT(is_ex_exactly_of_type(coeff,numeric));
+ return is_ex_exactly_of_type(rest,numeric) &&
+ (coeff.is_equal(ex(1)));
+ }
- bool is_equal(const expair & other) const
- {
- return (rest.is_equal(other.rest) && coeff.is_equal(other.coeff));
- }
- bool is_less(const expair & other) const
- {
- return (rest.compare(other.rest)<0) ||
- (!(other.rest.compare(rest)<0) && (coeff.compare(other.coeff)<0));
- }
- int compare(const expair & other) const
- {
- int cmpval=rest.compare(other.rest);
- if (cmpval!=0) return cmpval;
- cmpval=coeff.compare(other.coeff);
- return cmpval;
- }
+ bool is_equal(const expair & other) const
+ {
+ return (rest.is_equal(other.rest) && coeff.is_equal(other.coeff));
+ }
+ bool is_less(const expair & other) const
+ {
+ return (rest.compare(other.rest)<0) ||
+ (!(other.rest.compare(rest)<0) && (coeff.compare(other.coeff)<0));
+ }
+ int compare(const expair & other) const
+ {
+ int cmpval=rest.compare(other.rest);
+ if (cmpval!=0) return cmpval;
+ cmpval=coeff.compare(other.coeff);
+ return cmpval;
+ }
- bool is_less_old2(const expair & other) const
- {
- /*
- bool this_numeric_with_coeff_1=is_numeric_with_coeff_1();
- bool other_numeric_with_coeff_1=other.is_numeric_with_coeff_1();
- if (this_numeric_with_coeff_1) {
- if (other_numeric_with_coeff_1) {
- // both have coeff 1: compare rests
- return rest.compare(other.rest)<0;
- }
- // only this has coeff 1: >
- return false;
- } else if (other_numeric_with_coeff_1) {
- // only other has coeff 1: <
- return true;
- }
- return (rest.compare(other.rest)<0) ||
- (!(other.rest.compare(rest)<0) &&
- (coeff.compare(other.coeff)<0));
- */
- if (is_ex_exactly_of_type(rest,numeric) &&
- is_ex_exactly_of_type(other.rest,numeric)) {
- if (coeff.is_equal(ex(1))) {
- if ((other.coeff).is_equal(ex(1))) {
- // both have coeff 1: compare rests
- return rest.compare(other.rest)<0;
- }
- // only this has coeff 1: >
- return false;
- } else if ((other.coeff).is_equal(ex(1))) {
- // only other has coeff 1: <
- return true;
- }
- // neither has coeff 1: usual compare
- }
- return (rest.compare(other.rest)<0) ||
- (!(other.rest.compare(rest)<0) &&
- (coeff.compare(other.coeff)<0));
- }
- int compare_old2(const expair & other) const
- {
- if (is_ex_exactly_of_type(rest,numeric) &&
- is_ex_exactly_of_type(other.rest,numeric)) {
- if ((coeff).is_equal(ex(1))) {
- if ((other.coeff).is_equal(ex(1))) {
- // both have coeff 1: compare rests
- return rest.compare(other.rest);
- }
- // only this has coeff 1: >
- return 1;
- } else if ((other.coeff).is_equal(ex(1))) {
- // only other has coeff 1: <
- return -1;
- }
- // neither has coeff 1: usual compare
- }
- /*
- bool this_numeric_with_coeff_1=is_numeric_with_coeff_1();
- bool other_numeric_with_coeff_1=other.is_numeric_with_coeff_1();
- if (this_numeric_with_coeff_1) {
- if (other_numeric_with_coeff_1) {
- // both have coeff 1: compare rests
- return rest.compare(other.rest);
- }
- // only this has coeff 1: >
- return 1;
- } else if (other_numeric_with_coeff_1) {
- // only other has coeff 1: <
- return -1;
- // neither has coeff 1: usual compare
- }
- */
- int cmpval=rest.compare(other.rest);
- if (cmpval!=0) return cmpval;
- return coeff.compare(other.coeff);
- }
- bool is_less_old(const expair & other) const
- {
- return (rest.compare(other.rest)<0) ||
- (!(other.rest.compare(rest)<0) && (coeff.compare(other.coeff)<0));
- }
- int compare_old(const expair & other) const
- {
- int cmpval=rest.compare(other.rest);
- if (cmpval!=0) return cmpval;
- cmpval=coeff.compare(other.coeff);
- return cmpval;
- }
+ bool is_less_old2(const expair & other) const
+ {
+ /*
+ bool this_numeric_with_coeff_1=is_numeric_with_coeff_1();
+ bool other_numeric_with_coeff_1=other.is_numeric_with_coeff_1();
+ if (this_numeric_with_coeff_1) {
+ if (other_numeric_with_coeff_1) {
+ // both have coeff 1: compare rests
+ return rest.compare(other.rest)<0;
+ }
+ // only this has coeff 1: >
+ return false;
+ } else if (other_numeric_with_coeff_1) {
+ // only other has coeff 1: <
+ return true;
+ }
+ return (rest.compare(other.rest)<0) ||
+ (!(other.rest.compare(rest)<0) &&
+ (coeff.compare(other.coeff)<0));
+ */
+ if (is_ex_exactly_of_type(rest,numeric) &&
+ is_ex_exactly_of_type(other.rest,numeric)) {
+ if (coeff.is_equal(ex(1))) {
+ if ((other.coeff).is_equal(ex(1))) {
+ // both have coeff 1: compare rests
+ return rest.compare(other.rest)<0;
+ }
+ // only this has coeff 1: >
+ return false;
+ } else if ((other.coeff).is_equal(ex(1))) {
+ // only other has coeff 1: <
+ return true;
+ }
+ // neither has coeff 1: usual compare
+ }
+ return (rest.compare(other.rest)<0) ||
+ (!(other.rest.compare(rest)<0) &&
+ (coeff.compare(other.coeff)<0));
+ }
+ int compare_old2(const expair & other) const
+ {
+ if (is_ex_exactly_of_type(rest,numeric) &&
+ is_ex_exactly_of_type(other.rest,numeric)) {
+ if ((coeff).is_equal(ex(1))) {
+ if ((other.coeff).is_equal(ex(1))) {
+ // both have coeff 1: compare rests
+ return rest.compare(other.rest);
+ }
+ // only this has coeff 1: >
+ return 1;
+ } else if ((other.coeff).is_equal(ex(1))) {
+ // only other has coeff 1: <
+ return -1;
+ }
+ // neither has coeff 1: usual compare
+ }
+ /*
+ bool this_numeric_with_coeff_1=is_numeric_with_coeff_1();
+ bool other_numeric_with_coeff_1=other.is_numeric_with_coeff_1();
+ if (this_numeric_with_coeff_1) {
+ if (other_numeric_with_coeff_1) {
+ // both have coeff 1: compare rests
+ return rest.compare(other.rest);
+ }
+ // only this has coeff 1: >
+ return 1;
+ } else if (other_numeric_with_coeff_1) {
+ // only other has coeff 1: <
+ return -1;
+ // neither has coeff 1: usual compare
+ }
+ */
+ int cmpval=rest.compare(other.rest);
+ if (cmpval!=0) return cmpval;
+ return coeff.compare(other.coeff);
+ }
+ bool is_less_old(const expair & other) const
+ {
+ return (rest.compare(other.rest)<0) ||
+ (!(other.rest.compare(rest)<0) && (coeff.compare(other.coeff)<0));
+ }
+ int compare_old(const expair & other) const
+ {
+ int cmpval=rest.compare(other.rest);
+ if (cmpval!=0) return cmpval;
+ cmpval=coeff.compare(other.coeff);
+ return cmpval;
+ }
- void printraw(std::ostream & os) const
- {
- os << "expair(";
- rest.printraw(os);
- os << ",";
- coeff.printraw(os);
- os << ")";
- }
+ void printraw(std::ostream & os) const
+ {
+ os << "expair(";
+ rest.printraw(os);
+ os << ",";
+ coeff.printraw(os);
+ os << ")";
+ }
- ex rest;
- ex coeff;
+ ex rest;
+ ex coeff;
};
class expair_is_less
{
public:
- bool operator()(const expair & lh, const expair & rh) const
- {
- return lh.is_less(rh);
- }
+ bool operator()(const expair & lh, const expair & rh) const
+ {
+ return lh.is_less(rh);
+ }
};
class expair_is_less_old
{
public:
- bool operator()(const expair & lh, const expair & rh) const
- {
- return lh.is_less_old(rh);
- }
+ bool operator()(const expair & lh, const expair & rh) const
+ {
+ return lh.is_less_old(rh);
+ }
};
#ifndef NO_NAMESPACE_GINAC
class epp_is_less
{
public:
- bool operator()(const epp & lh, const epp & rh) const
- {
- return (*lh).is_less(*rh);
- }
+ bool operator()(const epp & lh, const epp & rh) const
+ {
+ return (*lh).is_less(*rh);
+ }
};
//////////
expairseq::expairseq(const expairseq & other)
{
- debugmsg("expairseq copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("expairseq copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const expairseq & expairseq::operator=(const expairseq & other)
{
- debugmsg("expairseq operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("expairseq operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void expairseq::copy(const expairseq & other)
{
- inherited::copy(other);
- seq=other.seq;
- overall_coeff=other.overall_coeff;
+ inherited::copy(other);
+ seq=other.seq;
+ overall_coeff=other.overall_coeff;
#ifdef EXPAIRSEQ_USE_HASHTAB
- // copy hashtab
- hashtabsize=other.hashtabsize;
- if (hashtabsize!=0) {
- hashmask=other.hashmask;
- hashtab.resize(hashtabsize);
- epvector::const_iterator osb=other.seq.begin();
- for (unsigned i=0; i<hashtabsize; ++i) {
- hashtab[i].clear();
- for (epplist::const_iterator cit=other.hashtab[i].begin();
- cit!=other.hashtab[i].end(); ++cit) {
- hashtab[i].push_back(seq.begin()+((*cit)-osb));
- }
- }
- } else {
- hashtab.clear();
- }
+ // copy hashtab
+ hashtabsize=other.hashtabsize;
+ if (hashtabsize!=0) {
+ hashmask=other.hashmask;
+ hashtab.resize(hashtabsize);
+ epvector::const_iterator osb=other.seq.begin();
+ for (unsigned i=0; i<hashtabsize; ++i) {
+ hashtab[i].clear();
+ for (epplist::const_iterator cit=other.hashtab[i].begin();
+ cit!=other.hashtab[i].end(); ++cit) {
+ hashtab[i].push_back(seq.begin()+((*cit)-osb));
+ }
+ }
+ } else {
+ hashtab.clear();
+ }
#endif // def EXPAIRSEQ_USE_HASHTAB
}
expairseq::expairseq(const ex & lh, const ex & rh) : inherited(TINFO_expairseq)
{
- debugmsg("expairseq constructor from ex,ex",LOGLEVEL_CONSTRUCT);
- construct_from_2_ex(lh,rh);
- GINAC_ASSERT(is_canonical());
+ debugmsg("expairseq constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+ construct_from_2_ex(lh,rh);
+ GINAC_ASSERT(is_canonical());
}
expairseq::expairseq(const exvector & v) : inherited(TINFO_expairseq)
{
- debugmsg("expairseq constructor from exvector",LOGLEVEL_CONSTRUCT);
- construct_from_exvector(v);
- GINAC_ASSERT(is_canonical());
+ debugmsg("expairseq constructor from exvector",LOGLEVEL_CONSTRUCT);
+ construct_from_exvector(v);
+ GINAC_ASSERT(is_canonical());
}
/*
expairseq::expairseq(const epvector & v, bool do_not_canonicalize) :
- inherited(TINFO_expairseq)
+ inherited(TINFO_expairseq)
{
- debugmsg("expairseq constructor from epvector",LOGLEVEL_CONSTRUCT);
- if (do_not_canonicalize) {
- seq=v;
+ debugmsg("expairseq constructor from epvector",LOGLEVEL_CONSTRUCT);
+ if (do_not_canonicalize) {
+ seq=v;
#ifdef EXPAIRSEQ_USE_HASHTAB
- combine_same_terms(); // to build hashtab
+ combine_same_terms(); // to build hashtab
#endif // def EXPAIRSEQ_USE_HASHTAB
- } else {
- construct_from_epvector(v);
- }
- GINAC_ASSERT(is_canonical());
+ } else {
+ construct_from_epvector(v);
+ }
+ GINAC_ASSERT(is_canonical());
}
*/
expairseq::expairseq(const epvector & v, const ex & oc) :
- inherited(TINFO_expairseq), overall_coeff(oc)
+ inherited(TINFO_expairseq), overall_coeff(oc)
{
- debugmsg("expairseq constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
- construct_from_epvector(v);
- GINAC_ASSERT(is_canonical());
+ debugmsg("expairseq constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
+ construct_from_epvector(v);
+ GINAC_ASSERT(is_canonical());
}
expairseq::expairseq(epvector * vp, const ex & oc) :
- inherited(TINFO_expairseq), overall_coeff(oc)
+ inherited(TINFO_expairseq), overall_coeff(oc)
{
- debugmsg("expairseq constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(vp!=0);
- construct_from_epvector(*vp);
- delete vp;
- GINAC_ASSERT(is_canonical());
+ debugmsg("expairseq constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(vp!=0);
+ construct_from_epvector(*vp);
+ delete vp;
+ GINAC_ASSERT(is_canonical());
}
//////////
/** Construct object from archive_node. */
expairseq::expairseq(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
#ifdef EXPAIRSEQ_USE_HASHTAB
- , hashtabsize(0)
+ , hashtabsize(0)
#endif
{
- debugmsg("expairseq constructor from archive_node", LOGLEVEL_CONSTRUCT);
- for (unsigned int i=0; true; i++) {
- ex rest;
- ex coeff;
- if (n.find_ex("rest", rest, sym_lst, i) && n.find_ex("coeff", coeff, sym_lst, i))
- seq.push_back(expair(rest, coeff));
- else
- break;
- }
- n.find_ex("overall_coeff", overall_coeff, sym_lst);
+ debugmsg("expairseq constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ for (unsigned int i=0; true; i++) {
+ ex rest;
+ ex coeff;
+ if (n.find_ex("rest", rest, sym_lst, i) && n.find_ex("coeff", coeff, sym_lst, i))
+ seq.push_back(expair(rest, coeff));
+ else
+ break;
+ }
+ n.find_ex("overall_coeff", overall_coeff, sym_lst);
}
/** Unarchive the object. */
ex expairseq::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new expairseq(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new expairseq(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void expairseq::archive(archive_node &n) const
{
- inherited::archive(n);
- epvector::const_iterator i = seq.begin(), iend = seq.end();
- while (i != iend) {
- n.add_ex("rest", i->rest);
- n.add_ex("coeff", i->coeff);
- i++;
- }
- n.add_ex("overall_coeff", overall_coeff);
+ inherited::archive(n);
+ epvector::const_iterator i = seq.begin(), iend = seq.end();
+ while (i != iend) {
+ n.add_ex("rest", i->rest);
+ n.add_ex("coeff", i->coeff);
+ i++;
+ }
+ n.add_ex("overall_coeff", overall_coeff);
}
//////////
basic * expairseq::duplicate() const
{
- debugmsg("expairseq duplicate",LOGLEVEL_DUPLICATE);
- return new expairseq(*this);
+ debugmsg("expairseq duplicate",LOGLEVEL_DUPLICATE);
+ return new expairseq(*this);
}
void expairseq::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("expairseq print",LOGLEVEL_PRINT);
- os << "[[";
- printseq(os,',',precedence,upper_precedence);
- os << "]]";
+ debugmsg("expairseq print",LOGLEVEL_PRINT);
+ os << "[[";
+ printseq(os,',',precedence,upper_precedence);
+ os << "]]";
}
void expairseq::printraw(std::ostream & os) const
{
- debugmsg("expairseq printraw",LOGLEVEL_PRINT);
+ 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 << ")";
+ 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(std::ostream & os, unsigned indent) const
{
- debugmsg("expairseq printtree",LOGLEVEL_PRINT);
-
- os << std::string(indent,' ') << "type=" << typeid(*this).name()
- << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags
- << ", nops=" << nops() << std::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 << std::string(indent+delta_indent,' ') << "-----" << std::endl;
- }
- }
- if (!overall_coeff.is_equal(default_overall_coeff())) {
- os << std::string(indent+delta_indent,' ') << "-----" << std::endl;
- os << std::string(indent+delta_indent,' ') << "overall_coeff" << std::endl;
- overall_coeff.printtree(os,indent+delta_indent);
- }
- os << std::string(indent+delta_indent,' ') << "=====" << std::endl;
+ debugmsg("expairseq printtree",LOGLEVEL_PRINT);
+
+ os << std::string(indent,' ') << "type=" << class_name()
+ << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags
+ << ", nops=" << nops() << std::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 << std::string(indent+delta_indent,' ') << "-----" << std::endl;
+ }
+ }
+ if (!overall_coeff.is_equal(default_overall_coeff())) {
+ os << std::string(indent+delta_indent,' ') << "-----" << std::endl;
+ os << std::string(indent+delta_indent,' ') << "overall_coeff" << std::endl;
+ overall_coeff.printtree(os,indent+delta_indent);
+ }
+ os << std::string(indent+delta_indent,' ') << "=====" << std::endl;
#ifdef EXPAIRSEQ_USE_HASHTAB
- os << std::string(indent+delta_indent,' ')
- << "hashtab size " << hashtabsize << std::endl;
- if (hashtabsize==0) return;
+ os << std::string(indent+delta_indent,' ')
+ << "hashtab size " << hashtabsize << std::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 << std::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 << std::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 << std::string(indent+delta_indent,' ') << "bins with " << k << " entries: "
- << int(1000.0*count[k]/hashtabsize)/10.0 << "% (expected: "
- << int(prob*1000)/10.0 << ")" << std::endl;
- }
- os << std::string(indent+delta_indent,' ') << "bins with more entries: "
- << int(1000.0*count[MAXCOUNT]/hashtabsize)/10.0 << "% (expected: "
- << int((1-cum_prob)*1000)/10.0 << ")" << std::endl;
-
- os << std::string(indent+delta_indent,' ') << "variance: "
- << 1.0/hashtabsize*cum_fill_sq-(1.0/hashtabsize*cum_fill)*(1.0/hashtabsize*cum_fill)
- << std::endl;
- os << std::string(indent+delta_indent,' ') << "average fill: "
- << (1.0*cum_fill)/hashtabsize
- << " (should be equal to " << (1.0*seq.size())/hashtabsize << ")" << std::endl;
+ 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 << std::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 << std::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 << std::string(indent+delta_indent,' ') << "bins with " << k << " entries: "
+ << int(1000.0*count[k]/hashtabsize)/10.0 << "% (expected: "
+ << int(prob*1000)/10.0 << ")" << std::endl;
+ }
+ os << std::string(indent+delta_indent,' ') << "bins with more entries: "
+ << int(1000.0*count[MAXCOUNT]/hashtabsize)/10.0 << "% (expected: "
+ << int((1-cum_prob)*1000)/10.0 << ")" << std::endl;
+
+ os << std::string(indent+delta_indent,' ') << "variance: "
+ << 1.0/hashtabsize*cum_fill_sq-(1.0/hashtabsize*cum_fill)*(1.0/hashtabsize*cum_fill)
+ << std::endl;
+ os << std::string(indent+delta_indent,' ') << "average fill: "
+ << (1.0*cum_fill)/hashtabsize
+ << " (should be equal to " << (1.0*seq.size())/hashtabsize << ")" << std::endl;
#endif // def EXPAIRSEQ_USE_HASHTAB
}
bool expairseq::info(unsigned inf) const
{
- return inherited::info(inf);
+ return inherited::info(inf);
}
unsigned expairseq::nops() const
{
- if (overall_coeff.is_equal(default_overall_coeff())) {
- return seq.size();
- }
- return seq.size()+1;
+ if (overall_coeff.is_equal(default_overall_coeff())) {
+ return seq.size();
+ }
+ return seq.size()+1;
}
ex expairseq::op(int i) const
{
- if (unsigned(i)<seq.size()) {
- return recombine_pair_to_ex(seq[i]);
- }
- GINAC_ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
- return overall_coeff;
+ if (unsigned(i)<seq.size()) {
+ return recombine_pair_to_ex(seq[i]);
+ }
+ GINAC_ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
+ return overall_coeff;
}
ex & expairseq::let_op(int i)
{
- throw(std::logic_error("let_op not defined for expairseq and derived classes (add,mul,...)"));
+ throw(std::logic_error("let_op not defined for expairseq and derived classes (add,mul,...)"));
}
ex expairseq::eval(int level) const
{
- if ((level==1)&&(flags & status_flags::evaluated)) {
- return *this;
- }
+ if ((level==1)&&(flags & status_flags::evaluated)) {
+ return *this;
+ }
- epvector * vp=evalchildren(level);
- if (vp==0) {
- return this->hold();
- }
+ epvector * vp=evalchildren(level);
+ if (vp==0) {
+ return this->hold();
+ }
- return (new expairseq(vp,overall_coeff))
- ->setflag(status_flags::dynallocated |
- status_flags::evaluated );
+ return (new expairseq(vp,overall_coeff))
+ ->setflag(status_flags::dynallocated |
+ status_flags::evaluated );
}
ex expairseq::evalf(int level) const
{
- return thisexpairseq(evalfchildren(level),overall_coeff.evalf(level-1));
+ return thisexpairseq(evalfchildren(level),overall_coeff.evalf(level-1));
}
ex expairseq::normal(lst &sym_lst, lst &repl_lst, int level) const
{
- ex n = thisexpairseq(normalchildren(level),overall_coeff);
- return n.bp->basic::normal(sym_lst,repl_lst,level);
+ ex n = thisexpairseq(normalchildren(level),overall_coeff);
+ return n.bp->basic::normal(sym_lst,repl_lst,level);
}
ex expairseq::subs(const lst & ls, const lst & lr) const
{
- epvector * vp=subschildren(ls,lr);
- if (vp==0) {
- return *this;
- }
- return thisexpairseq(vp,overall_coeff);
+ epvector * vp=subschildren(ls,lr);
+ if (vp==0) {
+ return *this;
+ }
+ return thisexpairseq(vp,overall_coeff);
}
// protected
* @see ex::diff */
ex expairseq::derivative(const symbol & s) const
{
- return thisexpairseq(diffchildren(s),overall_coeff);
+ return thisexpairseq(diffchildren(s),overall_coeff);
}
int expairseq::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other, expairseq));
- const expairseq & o = static_cast<const expairseq &>(const_cast<basic &>(other));
+ GINAC_ASSERT(is_of_type(other, expairseq));
+ const expairseq & o = static_cast<const expairseq &>(const_cast<basic &>(other));
- int cmpval;
-
- // compare number of elements
- if (seq.size() != o.seq.size()) {
- return (seq.size()<o.seq.size()) ? -1 : 1;
- }
+ int cmpval;
+
+ // compare number of elements
+ if (seq.size() != o.seq.size()) {
+ return (seq.size()<o.seq.size()) ? -1 : 1;
+ }
- // compare overall_coeff
- cmpval = overall_coeff.compare(o.overall_coeff);
- if (cmpval!=0) return cmpval;
+ // compare overall_coeff
+ cmpval = overall_coeff.compare(o.overall_coeff);
+ if (cmpval!=0) return cmpval;
- //if (seq.size()==0) return 0; // empty expairseq's are equal
+ //if (seq.size()==0) return 0; // empty expairseq's are equal
#ifdef EXPAIRSEQ_USE_HASHTAB
- GINAC_ASSERT(hashtabsize==o.hashtabsize);
- if (hashtabsize==0) {
+ GINAC_ASSERT(hashtabsize==o.hashtabsize);
+ if (hashtabsize==0) {
#endif // def EXPAIRSEQ_USE_HASHTAB
- epvector::const_iterator cit1 = seq.begin();
- epvector::const_iterator cit2 = o.seq.begin();
- epvector::const_iterator last1 = seq.end();
- epvector::const_iterator last2 = o.seq.end();
-
- for (; (cit1!=last1)&&(cit2!=last2); ++cit1, ++cit2) {
- cmpval = (*cit1).compare(*cit2);
- if (cmpval!=0) return cmpval;
- }
-
- GINAC_ASSERT(cit1==last1);
- GINAC_ASSERT(cit2==last2);
-
- return 0;
+ epvector::const_iterator cit1 = seq.begin();
+ epvector::const_iterator cit2 = o.seq.begin();
+ epvector::const_iterator last1 = seq.end();
+ epvector::const_iterator last2 = o.seq.end();
+
+ for (; (cit1!=last1)&&(cit2!=last2); ++cit1, ++cit2) {
+ cmpval = (*cit1).compare(*cit2);
+ if (cmpval!=0) return cmpval;
+ }
+
+ GINAC_ASSERT(cit1==last1);
+ GINAC_ASSERT(cit2==last2);
+
+ return 0;
#ifdef EXPAIRSEQ_USE_HASHTAB
- }
-
- // compare number of elements in each hashtab entry
- for (unsigned i=0; i<hashtabsize; ++i) {
- unsigned cursize=hashtab[i].size();
- if (cursize != o.hashtab[i].size()) {
- return (cursize < o.hashtab[i].size()) ? -1 : 1;
- }
- }
-
- // compare individual (sorted) hashtab entries
- for (unsigned i=0; i<hashtabsize; ++i) {
- unsigned sz=hashtab[i].size();
- if (sz>0) {
- const epplist & eppl1=hashtab[i];
- const epplist & eppl2=o.hashtab[i];
- epplist::const_iterator it1=eppl1.begin();
- epplist::const_iterator it2=eppl2.begin();
- while (it1!=eppl1.end()) {
- cmpval=(*(*it1)).compare(*(*it2));
- if (cmpval!=0) return cmpval;
- ++it1;
- ++it2;
- }
- }
- }
-
- return 0; // equal
+ }
+
+ // compare number of elements in each hashtab entry
+ for (unsigned i=0; i<hashtabsize; ++i) {
+ unsigned cursize=hashtab[i].size();
+ if (cursize != o.hashtab[i].size()) {
+ return (cursize < o.hashtab[i].size()) ? -1 : 1;
+ }
+ }
+
+ // compare individual (sorted) hashtab entries
+ for (unsigned i=0; i<hashtabsize; ++i) {
+ unsigned sz=hashtab[i].size();
+ if (sz>0) {
+ const epplist & eppl1=hashtab[i];
+ const epplist & eppl2=o.hashtab[i];
+ epplist::const_iterator it1=eppl1.begin();
+ epplist::const_iterator it2=eppl2.begin();
+ while (it1!=eppl1.end()) {
+ cmpval=(*(*it1)).compare(*(*it2));
+ if (cmpval!=0) return cmpval;
+ ++it1;
+ ++it2;
+ }
+ }
+ }
+
+ return 0; // equal
#endif // def EXPAIRSEQ_USE_HASHTAB
}
bool expairseq::is_equal_same_type(const basic & other) const
{
- const expairseq & o=dynamic_cast<const expairseq &>(const_cast<basic &>(other));
+ const expairseq & o=dynamic_cast<const expairseq &>(const_cast<basic &>(other));
- // compare number of elements
- if (seq.size() != o.seq.size()) return false;
+ // compare number of elements
+ if (seq.size() != o.seq.size()) return false;
- // compare overall_coeff
- if (!overall_coeff.is_equal(o.overall_coeff)) return false;
+ // compare overall_coeff
+ if (!overall_coeff.is_equal(o.overall_coeff)) return false;
#ifdef EXPAIRSEQ_USE_HASHTAB
- // compare number of elements in each hashtab entry
- if (hashtabsize!=o.hashtabsize) {
- cout << "this:" << std::endl;
- printtree(cout,0);
- cout << "other:" << std::endl;
- other.printtree(cout,0);
- }
-
- GINAC_ASSERT(hashtabsize==o.hashtabsize);
-
- if (hashtabsize==0) {
+ // compare number of elements in each hashtab entry
+ if (hashtabsize!=o.hashtabsize) {
+ cout << "this:" << std::endl;
+ printtree(cout,0);
+ cout << "other:" << std::endl;
+ other.printtree(cout,0);
+ }
+
+ GINAC_ASSERT(hashtabsize==o.hashtabsize);
+
+ if (hashtabsize==0) {
#endif // def EXPAIRSEQ_USE_HASHTAB
- epvector::const_iterator cit1=seq.begin();
- epvector::const_iterator cit2=o.seq.begin();
- epvector::const_iterator last1=seq.end();
-
- while (cit1!=last1) {
- if (!(*cit1).is_equal(*cit2)) return false;
- ++cit1;
- ++cit2;
- }
-
- return true;
+ epvector::const_iterator cit1=seq.begin();
+ epvector::const_iterator cit2=o.seq.begin();
+ epvector::const_iterator last1=seq.end();
+
+ while (cit1!=last1) {
+ if (!(*cit1).is_equal(*cit2)) return false;
+ ++cit1;
+ ++cit2;
+ }
+
+ return true;
#ifdef EXPAIRSEQ_USE_HASHTAB
- }
-
- for (unsigned i=0; i<hashtabsize; ++i) {
- if (hashtab[i].size() != o.hashtab[i].size()) return false;
- }
-
- // compare individual sorted hashtab entries
- for (unsigned i=0; i<hashtabsize; ++i) {
- unsigned sz=hashtab[i].size();
- if (sz>0) {
- const epplist & eppl1=hashtab[i];
- const epplist & eppl2=o.hashtab[i];
- epplist::const_iterator it1=eppl1.begin();
- epplist::const_iterator it2=eppl2.begin();
- while (it1!=eppl1.end()) {
- if (!(*(*it1)).is_equal(*(*it2))) return false;
- ++it1;
- ++it2;
- }
- }
- }
-
- return true;
+ }
+
+ for (unsigned i=0; i<hashtabsize; ++i) {
+ if (hashtab[i].size() != o.hashtab[i].size()) return false;
+ }
+
+ // compare individual sorted hashtab entries
+ for (unsigned i=0; i<hashtabsize; ++i) {
+ unsigned sz=hashtab[i].size();
+ if (sz>0) {
+ const epplist & eppl1=hashtab[i];
+ const epplist & eppl2=o.hashtab[i];
+ epplist::const_iterator it1=eppl1.begin();
+ epplist::const_iterator it2=eppl2.begin();
+ while (it1!=eppl1.end()) {
+ if (!(*(*it1)).is_equal(*(*it2))) return false;
+ ++it1;
+ ++it2;
+ }
+ }
+ }
+
+ return true;
#endif // def EXPAIRSEQ_USE_HASHTAB
}
unsigned expairseq::return_type(void) const
{
- return return_types::noncommutative_composite;
+ return return_types::noncommutative_composite;
}
unsigned expairseq::calchash(void) const
{
- unsigned v=golden_ratio_hash(tinfo());
- epvector::const_iterator last=seq.end();
- for (epvector::const_iterator cit=seq.begin(); cit!=last; ++cit) {
+ unsigned v=golden_ratio_hash(tinfo());
+ epvector::const_iterator last=seq.end();
+ for (epvector::const_iterator cit=seq.begin(); cit!=last; ++cit) {
#ifndef EXPAIRSEQ_USE_HASHTAB
- v=rotate_left_31(v); // rotation would spoil commutativity
+ v=rotate_left_31(v); // rotation would spoil commutativity
#endif // ndef EXPAIRSEQ_USE_HASHTAB
- v ^= (*cit).rest.gethash();
- }
+ v ^= (*cit).rest.gethash();
+ }
- v ^= overall_coeff.gethash();
- v=v & 0x7FFFFFFFU;
-
- // store calculated hash value only if object is already evaluated
- if (flags & status_flags::evaluated) {
- setflag(status_flags::hash_calculated);
- hashvalue=v;
- }
+ v ^= overall_coeff.gethash();
+ v=v & 0x7FFFFFFFU;
+
+ // store calculated hash value only if object is already evaluated
+ if (flags & status_flags::evaluated) {
+ setflag(status_flags::hash_calculated);
+ hashvalue=v;
+ }
- return v;
+ return v;
}
ex expairseq::expand(unsigned options) const
{
- epvector * vp = expandchildren(options);
- if (vp==0) {
- return *this;
- }
- return thisexpairseq(vp,overall_coeff);
+ epvector * vp = expandchildren(options);
+ if (vp==0) {
+ return *this;
+ }
+ return thisexpairseq(vp,overall_coeff);
}
//////////
ex expairseq::thisexpairseq(const epvector & v, const ex & oc) const
{
- return expairseq(v,oc);
+ return expairseq(v,oc);
}
ex expairseq::thisexpairseq(epvector * vp, const ex & oc) const
{
- return expairseq(vp,oc);
+ return expairseq(vp,oc);
}
void expairseq::printpair(std::ostream & os, const expair & p, unsigned upper_precedence) const
{
- os << "[[";
- p.rest.bp->print(os,precedence);
- os << ",";
- p.coeff.bp->print(os,precedence);
- os << "]]";
+ os << "[[";
+ p.rest.bp->print(os,precedence);
+ os << ",";
+ p.coeff.bp->print(os,precedence);
+ os << "]]";
}
void expairseq::printseq(std::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 << ")";
-}
-
+ 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(const ex & e) const
{
- return expair(e,_ex1());
+ return expair(e,_ex1());
}
expair expairseq::combine_ex_with_coeff_to_pair(const ex & e,
- const ex & c) const
+ const ex & c) const
{
- GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
- return expair(e,c);
+ return expair(e,c);
}
expair expairseq::combine_pair_with_coeff_to_pair(const expair & p,
- const ex & c) const
+ const ex & c) const
{
- 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)));
+ 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::recombine_pair_to_ex(const expair & p) const
{
- return lst(p.rest,p.coeff);
+ return lst(p.rest,p.coeff);
}
bool expairseq::expair_needs_further_processing(epp it)
{
- return false;
+ return false;
}
ex expairseq::default_overall_coeff(void) const
{
- return _ex0();
+ return _ex0();
}
void expairseq::combine_overall_coeff(const ex & c)
{
- 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));
+ 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(const ex & c1, const ex & c2)
{
- 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)));
+ 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)));
}
bool expairseq::can_make_flat(const expair & p) const
{
- return true;
+ return true;
}
-
+
//////////
// non-virtual functions in this class
//////////
void expairseq::construct_from_2_ex_via_exvector(const ex & lh, const ex & rh)
{
- exvector v;
- v.reserve(2);
- v.push_back(lh);
- v.push_back(rh);
- construct_from_exvector(v);
+ exvector v;
+ v.reserve(2);
+ v.push_back(lh);
+ v.push_back(rh);
+ construct_from_exvector(v);
#ifdef EXPAIRSEQ_USE_HASHTAB
- GINAC_ASSERT((hashtabsize==0)||(hashtabsize>=minhashtabsize));
- GINAC_ASSERT(hashtabsize==calc_hashtabsize(seq.size()));
+ GINAC_ASSERT((hashtabsize==0)||(hashtabsize>=minhashtabsize));
+ GINAC_ASSERT(hashtabsize==calc_hashtabsize(seq.size()));
#endif // def EXPAIRSEQ_USE_HASHTAB
}
void expairseq::construct_from_2_ex(const ex & lh, const ex & rh)
{
- if (lh.bp->tinfo()==tinfo()) {
- if (rh.bp->tinfo()==tinfo()) {
+ if (lh.bp->tinfo()==tinfo()) {
+ if (rh.bp->tinfo()==tinfo()) {
#ifdef EXPAIRSEQ_USE_HASHTAB
- unsigned totalsize=ex_to_expairseq(lh).seq.size()+
- ex_to_expairseq(rh).seq.size();
- if (calc_hashtabsize(totalsize)!=0) {
- construct_from_2_ex_via_exvector(lh,rh);
- } else {
+ unsigned totalsize=ex_to_expairseq(lh).seq.size()+
+ ex_to_expairseq(rh).seq.size();
+ if (calc_hashtabsize(totalsize)!=0) {
+ construct_from_2_ex_via_exvector(lh,rh);
+ } else {
#endif // def EXPAIRSEQ_USE_HASHTAB
- construct_from_2_expairseq(ex_to_expairseq(lh),
- ex_to_expairseq(rh));
+ construct_from_2_expairseq(ex_to_expairseq(lh),
+ ex_to_expairseq(rh));
#ifdef EXPAIRSEQ_USE_HASHTAB
- }
+ }
#endif // def EXPAIRSEQ_USE_HASHTAB
- return;
- } else {
+ return;
+ } else {
#ifdef EXPAIRSEQ_USE_HASHTAB
- unsigned totalsize=ex_to_expairseq(lh).seq.size()+1;
- if (calc_hashtabsize(totalsize)!=0) {
- construct_from_2_ex_via_exvector(lh,rh);
- } else {
+ unsigned totalsize=ex_to_expairseq(lh).seq.size()+1;
+ if (calc_hashtabsize(totalsize)!=0) {
+ construct_from_2_ex_via_exvector(lh,rh);
+ } else {
#endif // def EXPAIRSEQ_USE_HASHTAB
- construct_from_expairseq_ex(ex_to_expairseq(lh),rh);
+ construct_from_expairseq_ex(ex_to_expairseq(lh),rh);
#ifdef EXPAIRSEQ_USE_HASHTAB
- }
+ }
#endif // def EXPAIRSEQ_USE_HASHTAB
- return;
- }
- } else if (rh.bp->tinfo()==tinfo()) {
+ return;
+ }
+ } else if (rh.bp->tinfo()==tinfo()) {
#ifdef EXPAIRSEQ_USE_HASHTAB
- unsigned totalsize=ex_to_expairseq(rh).seq.size()+1;
- if (calc_hashtabsize(totalsize)!=0) {
- construct_from_2_ex_via_exvector(lh,rh);
- } else {
+ unsigned totalsize=ex_to_expairseq(rh).seq.size()+1;
+ if (calc_hashtabsize(totalsize)!=0) {
+ construct_from_2_ex_via_exvector(lh,rh);
+ } else {
#endif // def EXPAIRSEQ_USE_HASHTAB
- construct_from_expairseq_ex(ex_to_expairseq(rh),lh);
+ construct_from_expairseq_ex(ex_to_expairseq(rh),lh);
#ifdef EXPAIRSEQ_USE_HASHTAB
- }
+ }
#endif // def EXPAIRSEQ_USE_HASHTAB
- return;
- }
+ return;
+ }
#ifdef EXPAIRSEQ_USE_HASHTAB
- if (calc_hashtabsize(2)!=0) {
- construct_from_2_ex_via_exvector(lh,rh);
- return;
- }
- hashtabsize=0;
+ if (calc_hashtabsize(2)!=0) {
+ construct_from_2_ex_via_exvector(lh,rh);
+ return;
+ }
+ hashtabsize=0;
#endif // def EXPAIRSEQ_USE_HASHTAB
-
- if (is_ex_exactly_of_type(lh,numeric)) {
- if (is_ex_exactly_of_type(rh,numeric)) {
- combine_overall_coeff(lh);
- combine_overall_coeff(rh);
- } else {
- combine_overall_coeff(lh);
- seq.push_back(split_ex_to_pair(rh));
- }
- } else {
- if (is_ex_exactly_of_type(rh,numeric)) {
- combine_overall_coeff(rh);
- seq.push_back(split_ex_to_pair(lh));
- } else {
- expair p1=split_ex_to_pair(lh);
- expair p2=split_ex_to_pair(rh);
-
- int cmpval=p1.rest.compare(p2.rest);
- if (cmpval==0) {
- p1.coeff=ex_to_numeric(p1.coeff).add_dyn(ex_to_numeric(p2.coeff));
- if (!ex_to_numeric(p1.coeff).is_zero()) {
- // no further processing is necessary, since this
- // one element will usually be recombined in eval()
- seq.push_back(p1);
- }
- } else {
- seq.reserve(2);
- if (cmpval<0) {
- seq.push_back(p1);
- seq.push_back(p2);
- } else {
- seq.push_back(p2);
- seq.push_back(p1);
- }
- }
- }
- }
+
+ if (is_ex_exactly_of_type(lh,numeric)) {
+ if (is_ex_exactly_of_type(rh,numeric)) {
+ combine_overall_coeff(lh);
+ combine_overall_coeff(rh);
+ } else {
+ combine_overall_coeff(lh);
+ seq.push_back(split_ex_to_pair(rh));
+ }
+ } else {
+ if (is_ex_exactly_of_type(rh,numeric)) {
+ combine_overall_coeff(rh);
+ seq.push_back(split_ex_to_pair(lh));
+ } else {
+ expair p1=split_ex_to_pair(lh);
+ expair p2=split_ex_to_pair(rh);
+
+ int cmpval=p1.rest.compare(p2.rest);
+ if (cmpval==0) {
+ p1.coeff=ex_to_numeric(p1.coeff).add_dyn(ex_to_numeric(p2.coeff));
+ if (!ex_to_numeric(p1.coeff).is_zero()) {
+ // no further processing is necessary, since this
+ // one element will usually be recombined in eval()
+ seq.push_back(p1);
+ }
+ } else {
+ seq.reserve(2);
+ if (cmpval<0) {
+ seq.push_back(p1);
+ seq.push_back(p2);
+ } else {
+ seq.push_back(p2);
+ seq.push_back(p1);
+ }
+ }
+ }
+ }
}
void expairseq::construct_from_2_expairseq(const expairseq & s1,
- const expairseq & s2)
-{
- combine_overall_coeff(s1.overall_coeff);
- combine_overall_coeff(s2.overall_coeff);
-
- epvector::const_iterator first1=s1.seq.begin();
- epvector::const_iterator last1=s1.seq.end();
- epvector::const_iterator first2=s2.seq.begin();
- epvector::const_iterator last2=s2.seq.end();
-
- seq.reserve(s1.seq.size()+s2.seq.size());
-
- bool needs_further_processing=false;
-
- while (first1!=last1 && first2!=last2) {
- int cmpval=(*first1).rest.compare((*first2).rest);
- if (cmpval==0) {
- // combine terms
- const numeric & newcoeff=ex_to_numeric((*first1).coeff).
- add(ex_to_numeric((*first2).coeff));
- if (!newcoeff.is_zero()) {
- seq.push_back(expair((*first1).rest,newcoeff));
- if (expair_needs_further_processing(seq.end()-1)) {
- needs_further_processing = true;
- }
- }
- ++first1;
- ++first2;
- } else if (cmpval<0) {
- seq.push_back(*first1);
- ++first1;
- } else {
- seq.push_back(*first2);
- ++first2;
- }
- }
-
- while (first1!=last1) {
- seq.push_back(*first1);
- ++first1;
- }
- while (first2!=last2) {
- seq.push_back(*first2);
- ++first2;
- }
-
- if (needs_further_processing) {
- epvector v=seq;
- seq.clear();
- construct_from_epvector(v);
- }
+ const expairseq & s2)
+{
+ combine_overall_coeff(s1.overall_coeff);
+ combine_overall_coeff(s2.overall_coeff);
+
+ epvector::const_iterator first1=s1.seq.begin();
+ epvector::const_iterator last1=s1.seq.end();
+ epvector::const_iterator first2=s2.seq.begin();
+ epvector::const_iterator last2=s2.seq.end();
+
+ seq.reserve(s1.seq.size()+s2.seq.size());
+
+ bool needs_further_processing=false;
+
+ while (first1!=last1 && first2!=last2) {
+ int cmpval=(*first1).rest.compare((*first2).rest);
+ if (cmpval==0) {
+ // combine terms
+ const numeric & newcoeff=ex_to_numeric((*first1).coeff).
+ add(ex_to_numeric((*first2).coeff));
+ if (!newcoeff.is_zero()) {
+ seq.push_back(expair((*first1).rest,newcoeff));
+ if (expair_needs_further_processing(seq.end()-1)) {
+ needs_further_processing = true;
+ }
+ }
+ ++first1;
+ ++first2;
+ } else if (cmpval<0) {
+ seq.push_back(*first1);
+ ++first1;
+ } else {
+ seq.push_back(*first2);
+ ++first2;
+ }
+ }
+
+ while (first1!=last1) {
+ seq.push_back(*first1);
+ ++first1;
+ }
+ while (first2!=last2) {
+ seq.push_back(*first2);
+ ++first2;
+ }
+
+ if (needs_further_processing) {
+ epvector v=seq;
+ seq.clear();
+ construct_from_epvector(v);
+ }
}
void expairseq::construct_from_expairseq_ex(const expairseq & s,
- const ex & e)
-{
- combine_overall_coeff(s.overall_coeff);
- if (is_ex_exactly_of_type(e,numeric)) {
- combine_overall_coeff(e);
- seq=s.seq;
- return;
- }
-
- epvector::const_iterator first=s.seq.begin();
- epvector::const_iterator last=s.seq.end();
- expair p=split_ex_to_pair(e);
-
- seq.reserve(s.seq.size()+1);
- bool p_pushed=0;
-
- bool needs_further_processing=false;
-
- // merge p into s.seq
- while (first!=last) {
- int cmpval=(*first).rest.compare(p.rest);
- if (cmpval==0) {
- // combine terms
- const numeric & newcoeff=ex_to_numeric((*first).coeff).
- add(ex_to_numeric(p.coeff));
- if (!newcoeff.is_zero()) {
- seq.push_back(expair((*first).rest,newcoeff));
- if (expair_needs_further_processing(seq.end()-1)) {
- needs_further_processing = true;
- }
- }
- ++first;
- p_pushed=1;
- break;
- } else if (cmpval<0) {
- seq.push_back(*first);
- ++first;
- } else {
- seq.push_back(p);
- p_pushed=1;
- break;
- }
- }
-
- if (p_pushed) {
- // while loop exited because p was pushed, now push rest of s.seq
- while (first!=last) {
- seq.push_back(*first);
- ++first;
- }
- } else {
- // while loop exited because s.seq was pushed, now push p
- seq.push_back(p);
- }
-
- if (needs_further_processing) {
- epvector v=seq;
- seq.clear();
- construct_from_epvector(v);
- }
+ const ex & e)
+{
+ combine_overall_coeff(s.overall_coeff);
+ if (is_ex_exactly_of_type(e,numeric)) {
+ combine_overall_coeff(e);
+ seq=s.seq;
+ return;
+ }
+
+ epvector::const_iterator first=s.seq.begin();
+ epvector::const_iterator last=s.seq.end();
+ expair p=split_ex_to_pair(e);
+
+ seq.reserve(s.seq.size()+1);
+ bool p_pushed=0;
+
+ bool needs_further_processing=false;
+
+ // merge p into s.seq
+ while (first!=last) {
+ int cmpval=(*first).rest.compare(p.rest);
+ if (cmpval==0) {
+ // combine terms
+ const numeric & newcoeff=ex_to_numeric((*first).coeff).
+ add(ex_to_numeric(p.coeff));
+ if (!newcoeff.is_zero()) {
+ seq.push_back(expair((*first).rest,newcoeff));
+ if (expair_needs_further_processing(seq.end()-1)) {
+ needs_further_processing = true;
+ }
+ }
+ ++first;
+ p_pushed=1;
+ break;
+ } else if (cmpval<0) {
+ seq.push_back(*first);
+ ++first;
+ } else {
+ seq.push_back(p);
+ p_pushed=1;
+ break;
+ }
+ }
+
+ if (p_pushed) {
+ // while loop exited because p was pushed, now push rest of s.seq
+ while (first!=last) {
+ seq.push_back(*first);
+ ++first;
+ }
+ } else {
+ // while loop exited because s.seq was pushed, now push p
+ seq.push_back(p);
+ }
+
+ if (needs_further_processing) {
+ epvector v=seq;
+ seq.clear();
+ construct_from_epvector(v);
+ }
}
void expairseq::construct_from_exvector(const exvector & v)
{
- // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
- // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
- // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
- // (same for (+,*) -> (*,^)
+ // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
+ // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
+ // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
+ // (same for (+,*) -> (*,^)
- make_flat(v);
+ make_flat(v);
#ifdef EXPAIRSEQ_USE_HASHTAB
- combine_same_terms();
+ combine_same_terms();
#else
- canonicalize();
- combine_same_terms_sorted_seq();
+ canonicalize();
+ combine_same_terms_sorted_seq();
#endif // def EXPAIRSEQ_USE_HASHTAB
}
void expairseq::construct_from_epvector(const epvector & v)
{
- // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
- // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
- // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
- // (same for (+,*) -> (*,^)
+ // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
+ // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
+ // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
+ // (same for (+,*) -> (*,^)
- make_flat(v);
+ make_flat(v);
#ifdef EXPAIRSEQ_USE_HASHTAB
- combine_same_terms();
+ combine_same_terms();
#else
- canonicalize();
- combine_same_terms_sorted_seq();
+ canonicalize();
+ combine_same_terms_sorted_seq();
#endif // def EXPAIRSEQ_USE_HASHTAB
}
void expairseq::make_flat(const exvector & v)
{
- exvector::const_iterator cit, citend = v.end();
-
- // count number of operands which are of same expairseq derived type
- // and their cumulative number of operands
- int nexpairseqs=0;
- int noperands=0;
- cit=v.begin();
- while (cit!=citend) {
- if (cit->bp->tinfo()==tinfo()) {
- nexpairseqs++;
- noperands+=ex_to_expairseq(*cit).seq.size();
- }
- ++cit;
- }
-
- // reserve seq and coeffseq which will hold all operands
- seq.reserve(v.size()+noperands-nexpairseqs);
-
- // copy elements and split off numerical part
- cit=v.begin();
- while (cit!=citend) {
- if (cit->bp->tinfo()==tinfo()) {
- const expairseq & subseqref=ex_to_expairseq(*cit);
- combine_overall_coeff(subseqref.overall_coeff);
- epvector::const_iterator cit_s=subseqref.seq.begin();
- while (cit_s!=subseqref.seq.end()) {
- seq.push_back(*cit_s);
- ++cit_s;
- }
- } else {
- if (is_ex_exactly_of_type(*cit,numeric)) {
- combine_overall_coeff(*cit);
- } else {
- seq.push_back(split_ex_to_pair(*cit));
- }
- }
- ++cit;
- }
-
- /*
- cout << "after make flat" << std::endl;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- (*cit).printraw(cout);
- }
- cout << std::endl;
- */
+ exvector::const_iterator cit, citend = v.end();
+
+ // count number of operands which are of same expairseq derived type
+ // and their cumulative number of operands
+ int nexpairseqs=0;
+ int noperands=0;
+ cit=v.begin();
+ while (cit!=citend) {
+ if (cit->bp->tinfo()==tinfo()) {
+ nexpairseqs++;
+ noperands+=ex_to_expairseq(*cit).seq.size();
+ }
+ ++cit;
+ }
+
+ // reserve seq and coeffseq which will hold all operands
+ seq.reserve(v.size()+noperands-nexpairseqs);
+
+ // copy elements and split off numerical part
+ cit=v.begin();
+ while (cit!=citend) {
+ if (cit->bp->tinfo()==tinfo()) {
+ const expairseq & subseqref=ex_to_expairseq(*cit);
+ combine_overall_coeff(subseqref.overall_coeff);
+ epvector::const_iterator cit_s=subseqref.seq.begin();
+ while (cit_s!=subseqref.seq.end()) {
+ seq.push_back(*cit_s);
+ ++cit_s;
+ }
+ } else {
+ if (is_ex_exactly_of_type(*cit,numeric)) {
+ combine_overall_coeff(*cit);
+ } else {
+ seq.push_back(split_ex_to_pair(*cit));
+ }
+ }
+ ++cit;
+ }
+
+ /*
+ cout << "after make flat" << std::endl;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ (*cit).printraw(cout);
+ }
+ cout << std::endl;
+ */
}
void expairseq::make_flat(const epvector & v)
{
- epvector::const_iterator cit, citend = v.end();
-
- // count number of operands which are of same expairseq derived type
- // and their cumulative number of operands
- int nexpairseqs=0;
- int noperands=0;
-
- cit = v.begin();
- while (cit!=citend) {
- if (cit->rest.bp->tinfo()==tinfo()) {
- nexpairseqs++;
- noperands += ex_to_expairseq((*cit).rest).seq.size();
- }
- ++cit;
- }
-
- // reserve seq and coeffseq which will hold all operands
- seq.reserve(v.size()+noperands-nexpairseqs);
-
- // copy elements and split off numerical part
- cit = v.begin();
- while (cit!=citend) {
- if ((cit->rest.bp->tinfo()==tinfo())&&can_make_flat(*cit)) {
- const expairseq & subseqref=ex_to_expairseq((*cit).rest);
- combine_overall_coeff(ex_to_numeric(subseqref.overall_coeff),
- ex_to_numeric((*cit).coeff));
- epvector::const_iterator cit_s=subseqref.seq.begin();
- while (cit_s!=subseqref.seq.end()) {
- seq.push_back(expair((*cit_s).rest,
- ex_to_numeric((*cit_s).coeff).mul_dyn(ex_to_numeric((*cit).coeff))));
- //seq.push_back(combine_pair_with_coeff_to_pair(*cit_s,
- // (*cit).coeff));
- ++cit_s;
- }
- } else {
- if ((*cit).is_numeric_with_coeff_1()) {
- combine_overall_coeff((*cit).rest);
- //if (is_ex_exactly_of_type((*cit).rest,numeric)) {
- // combine_overall_coeff(recombine_pair_to_ex(*cit));
- } else {
- seq.push_back(*cit);
- }
- }
- ++cit;
- }
+ epvector::const_iterator cit, citend = v.end();
+
+ // count number of operands which are of same expairseq derived type
+ // and their cumulative number of operands
+ int nexpairseqs=0;
+ int noperands=0;
+
+ cit = v.begin();
+ while (cit!=citend) {
+ if (cit->rest.bp->tinfo()==tinfo()) {
+ nexpairseqs++;
+ noperands += ex_to_expairseq((*cit).rest).seq.size();
+ }
+ ++cit;
+ }
+
+ // reserve seq and coeffseq which will hold all operands
+ seq.reserve(v.size()+noperands-nexpairseqs);
+
+ // copy elements and split off numerical part
+ cit = v.begin();
+ while (cit!=citend) {
+ if ((cit->rest.bp->tinfo()==tinfo())&&can_make_flat(*cit)) {
+ const expairseq & subseqref=ex_to_expairseq((*cit).rest);
+ combine_overall_coeff(ex_to_numeric(subseqref.overall_coeff),
+ ex_to_numeric((*cit).coeff));
+ epvector::const_iterator cit_s=subseqref.seq.begin();
+ while (cit_s!=subseqref.seq.end()) {
+ seq.push_back(expair((*cit_s).rest,
+ ex_to_numeric((*cit_s).coeff).mul_dyn(ex_to_numeric((*cit).coeff))));
+ //seq.push_back(combine_pair_with_coeff_to_pair(*cit_s,
+ // (*cit).coeff));
+ ++cit_s;
+ }
+ } else {
+ if ((*cit).is_numeric_with_coeff_1()) {
+ combine_overall_coeff((*cit).rest);
+ //if (is_ex_exactly_of_type((*cit).rest,numeric)) {
+ // combine_overall_coeff(recombine_pair_to_ex(*cit));
+ } else {
+ seq.push_back(*cit);
+ }
+ }
+ ++cit;
+ }
}
epvector * expairseq::bubblesort(epvector::iterator itbegin, epvector::iterator itend)
{
- unsigned n=itend-itbegin;
+ unsigned n=itend-itbegin;
- epvector * sp=new epvector;
- sp->reserve(n);
+ epvector * sp=new epvector;
+ sp->reserve(n);
- epvector::iterator last=itend-1;
- for (epvector::iterator it1=itbegin; it1!=last; ++it1) {
- for (epvector::iterator it2=it1+1; it2!=itend; ++it2) {
- if ((*it2).rest.compare((*it1).rest)<0) {
- iter_swap(it1,it2);
- }
- }
- sp->push_back(*it1);
- }
- sp->push_back(*last);
- return sp;
+ epvector::iterator last=itend-1;
+ for (epvector::iterator it1=itbegin; it1!=last; ++it1) {
+ for (epvector::iterator it2=it1+1; it2!=itend; ++it2) {
+ if ((*it2).rest.compare((*it1).rest)<0) {
+ iter_swap(it1,it2);
+ }
+ }
+ sp->push_back(*it1);
+ }
+ sp->push_back(*last);
+ return sp;
}
epvector * expairseq::mergesort(epvector::iterator itbegin, epvector::iterator itend)
{
- unsigned n=itend-itbegin;
- /*
- if (n==1) {
- epvector * sp=new epvector;
- sp->push_back(*itbegin);
- return sp;
- }
- */
- if (n<16) return bubblesort(itbegin, itend);
- unsigned m=n/2;
-
- epvector * s1p=mergesort(itbegin, itbegin+m);
- epvector * s2p=mergesort(itbegin+m, itend);
-
- epvector * sp=new epvector;
- sp->reserve(s1p->size()+s2p->size());
-
- epvector::iterator first1=s1p->begin();
- epvector::iterator last1=s1p->end();
-
- epvector::iterator first2=s2p->begin();
- epvector::iterator last2=s2p->end();
-
- while (first1 != last1 && first2 != last2) {
- if ((*first1).rest.compare((*first2).rest)<0) {
- sp->push_back(*first1);
- ++first1;
- } else {
- sp->push_back(*first2);
- ++first2;
- }
- }
-
- if (first1 != last1) {
- while (first1 != last1) {
- sp->push_back(*first1);
- ++first1;
- }
- } else {
- while (first2 != last2) {
- sp->push_back(*first2);
- ++first2;
- }
- }
-
- delete s1p;
- delete s2p;
-
- return sp;
-}
-
+ unsigned n=itend-itbegin;
+ /*
+ if (n==1) {
+ epvector * sp=new epvector;
+ sp->push_back(*itbegin);
+ return sp;
+ }
+ */
+ if (n<16) return bubblesort(itbegin, itend);
+ unsigned m=n/2;
+
+ epvector * s1p=mergesort(itbegin, itbegin+m);
+ epvector * s2p=mergesort(itbegin+m, itend);
+
+ epvector * sp=new epvector;
+ sp->reserve(s1p->size()+s2p->size());
+
+ epvector::iterator first1=s1p->begin();
+ epvector::iterator last1=s1p->end();
+
+ epvector::iterator first2=s2p->begin();
+ epvector::iterator last2=s2p->end();
+
+ while (first1 != last1 && first2 != last2) {
+ if ((*first1).rest.compare((*first2).rest)<0) {
+ sp->push_back(*first1);
+ ++first1;
+ } else {
+ sp->push_back(*first2);
+ ++first2;
+ }
+ }
+
+ if (first1 != last1) {
+ while (first1 != last1) {
+ sp->push_back(*first1);
+ ++first1;
+ }
+ } else {
+ while (first2 != last2) {
+ sp->push_back(*first2);
+ ++first2;
+ }
+ }
+
+ delete s1p;
+ delete s2p;
+
+ return sp;
+}
+
void expairseq::canonicalize(void)
{
- // canonicalize
- sort(seq.begin(),seq.end(),expair_is_less());
- /*
- sort(seq.begin(),seq.end(),expair_is_less_old());
- if (seq.size()>1) {
- if (is_ex_exactly_of_type((*(seq.begin())).rest,numeric)) {
- sort(seq.begin(),seq.end(),expair_is_less());
- } else {
- epvector::iterator last_numeric=seq.end();
- do {
- last_numeric--;
- } while (is_ex_exactly_of_type((*last_numeric).rest,numeric));
- last_numeric++;
- sort(last_numeric,seq.end(),expair_is_less());
- }
- }
- */
-
- /*
- epvector * sorted_seqp=mergesort(seq.begin(),seq.end());
- epvector::iterator last=sorted_seqp->end();
- epvector::iterator it2=seq.begin();
- for (epvector::iterator it1=sorted_seqp->begin(); it1!=last; ++it1, ++it2) {
- iter_swap(it1,it2);
- }
- delete sorted_seqp;
- */
-
- /*
- cout << "after canonicalize" << std::endl;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- (*cit).printraw(cout);
- }
- cout << std::endl;
- cout.flush();
- */
+ // canonicalize
+ sort(seq.begin(),seq.end(),expair_is_less());
+ /*
+ sort(seq.begin(),seq.end(),expair_is_less_old());
+ if (seq.size()>1) {
+ if (is_ex_exactly_of_type((*(seq.begin())).rest,numeric)) {
+ sort(seq.begin(),seq.end(),expair_is_less());
+ } else {
+ epvector::iterator last_numeric=seq.end();
+ do {
+ last_numeric--;
+ } while (is_ex_exactly_of_type((*last_numeric).rest,numeric));
+ last_numeric++;
+ sort(last_numeric,seq.end(),expair_is_less());
+ }
+ }
+ */
+
+ /*
+ epvector * sorted_seqp=mergesort(seq.begin(),seq.end());
+ epvector::iterator last=sorted_seqp->end();
+ epvector::iterator it2=seq.begin();
+ for (epvector::iterator it1=sorted_seqp->begin(); it1!=last; ++it1, ++it2) {
+ iter_swap(it1,it2);
+ }
+ delete sorted_seqp;
+ */
+
+ /*
+ cout << "after canonicalize" << std::endl;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ (*cit).printraw(cout);
+ }
+ cout << std::endl;
+ cout.flush();
+ */
}
void expairseq::combine_same_terms_sorted_seq(void)
{
- bool needs_further_processing=false;
-
- // combine same terms, drop term with coeff 0
- if (seq.size()>1) {
- epvector::iterator itin1=seq.begin();
- epvector::iterator itin2=itin1+1;
- epvector::iterator itout=itin1;
- epvector::iterator last=seq.end();
- // must_copy will be set to true the first time some combination is possible
- // from then on the sequence has changed and must be compacted
- bool must_copy=false;
- while (itin2!=last) {
- if ((*itin1).rest.compare((*itin2).rest)==0) {
- (*itin1).coeff=ex_to_numeric((*itin1).coeff).
- add_dyn(ex_to_numeric((*itin2).coeff));
- if (expair_needs_further_processing(itin1)) {
- needs_further_processing = true;
- }
- must_copy=true;
- } else {
- if (!ex_to_numeric((*itin1).coeff).is_zero()) {
- if (must_copy) {
- *itout=*itin1;
- }
- ++itout;
- }
- itin1=itin2;
- }
- ++itin2;
- }
- if (!ex_to_numeric((*itin1).coeff).is_zero()) {
- if (must_copy) {
- *itout=*itin1;
- }
- ++itout;
- }
- if (itout!=last) {
- seq.erase(itout,last);
- }
- }
-
- /*
- cout << "after combine" << std::endl;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- (*cit).printraw(cout);
- }
- cout << std::endl;
- cout.flush();
- */
-
- if (needs_further_processing) {
- epvector v=seq;
- seq.clear();
- construct_from_epvector(v);
- }
+ bool needs_further_processing=false;
+
+ // combine same terms, drop term with coeff 0
+ if (seq.size()>1) {
+ epvector::iterator itin1=seq.begin();
+ epvector::iterator itin2=itin1+1;
+ epvector::iterator itout=itin1;
+ epvector::iterator last=seq.end();
+ // must_copy will be set to true the first time some combination is possible
+ // from then on the sequence has changed and must be compacted
+ bool must_copy=false;
+ while (itin2!=last) {
+ if ((*itin1).rest.compare((*itin2).rest)==0) {
+ (*itin1).coeff=ex_to_numeric((*itin1).coeff).
+ add_dyn(ex_to_numeric((*itin2).coeff));
+ if (expair_needs_further_processing(itin1)) {
+ needs_further_processing = true;
+ }
+ must_copy=true;
+ } else {
+ if (!ex_to_numeric((*itin1).coeff).is_zero()) {
+ if (must_copy) {
+ *itout=*itin1;
+ }
+ ++itout;
+ }
+ itin1=itin2;
+ }
+ ++itin2;
+ }
+ if (!ex_to_numeric((*itin1).coeff).is_zero()) {
+ if (must_copy) {
+ *itout=*itin1;
+ }
+ ++itout;
+ }
+ if (itout!=last) {
+ seq.erase(itout,last);
+ }
+ }
+
+ /*
+ cout << "after combine" << std::endl;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ (*cit).printraw(cout);
+ }
+ cout << std::endl;
+ cout.flush();
+ */
+
+ if (needs_further_processing) {
+ epvector v=seq;
+ seq.clear();
+ construct_from_epvector(v);
+ }
}
#ifdef EXPAIRSEQ_USE_HASHTAB
unsigned expairseq::calc_hashtabsize(unsigned sz) const
{
- unsigned size;
- unsigned nearest_power_of_2 = 1 << log2(sz);
- // if (nearest_power_of_2 < maxhashtabsize/hashtabfactor) {
- // size=nearest_power_of_2*hashtabfactor;
- size=nearest_power_of_2/hashtabfactor;
- if (size<minhashtabsize) return 0;
- GINAC_ASSERT(hashtabsize<=0x8000000U); // really max size due to 31 bit hashing
- // hashtabsize must be a power of 2
- GINAC_ASSERT((1U << log2(size))==size);
- return size;
+ unsigned size;
+ unsigned nearest_power_of_2 = 1 << log2(sz);
+ // if (nearest_power_of_2 < maxhashtabsize/hashtabfactor) {
+ // size=nearest_power_of_2*hashtabfactor;
+ size=nearest_power_of_2/hashtabfactor;
+ if (size<minhashtabsize) return 0;
+ GINAC_ASSERT(hashtabsize<=0x8000000U); // really max size due to 31 bit hashing
+ // hashtabsize must be a power of 2
+ GINAC_ASSERT((1U << log2(size))==size);
+ return size;
}
unsigned expairseq::calc_hashindex(const ex & e) const
{
- // calculate hashindex
- unsigned hash=e.gethash();
- unsigned hashindex;
- if (is_a_numeric_hash(hash)) {
- hashindex=hashmask;
- } else {
- hashindex=hash & hashmask;
- // last hashtab entry is reserved for numerics
- if (hashindex==hashmask) hashindex=0;
- }
- GINAC_ASSERT(hashindex>=0);
- GINAC_ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
- return hashindex;
+ // calculate hashindex
+ unsigned hash=e.gethash();
+ unsigned hashindex;
+ if (is_a_numeric_hash(hash)) {
+ hashindex=hashmask;
+ } else {
+ hashindex=hash & hashmask;
+ // last hashtab entry is reserved for numerics
+ if (hashindex==hashmask) hashindex=0;
+ }
+ GINAC_ASSERT(hashindex>=0);
+ GINAC_ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
+ return hashindex;
}
void expairseq::shrink_hashtab(void)
{
- unsigned new_hashtabsize;
- while (hashtabsize!=(new_hashtabsize=calc_hashtabsize(seq.size()))) {
- GINAC_ASSERT(new_hashtabsize<hashtabsize);
- if (new_hashtabsize==0) {
- hashtab.clear();
- hashtabsize=0;
- canonicalize();
- return;
- }
-
- // shrink by a factor of 2
- unsigned half_hashtabsize=hashtabsize/2;
- for (unsigned i=0; i<half_hashtabsize-1; ++i) {
- hashtab[i].merge(hashtab[i+half_hashtabsize],epp_is_less());
- }
- // special treatment for numeric hashes
- hashtab[0].merge(hashtab[half_hashtabsize-1],epp_is_less());
- hashtab[half_hashtabsize-1]=hashtab[hashtabsize-1];
- hashtab.resize(half_hashtabsize);
- hashtabsize=half_hashtabsize;
- hashmask=hashtabsize-1;
- }
+ unsigned new_hashtabsize;
+ while (hashtabsize!=(new_hashtabsize=calc_hashtabsize(seq.size()))) {
+ GINAC_ASSERT(new_hashtabsize<hashtabsize);
+ if (new_hashtabsize==0) {
+ hashtab.clear();
+ hashtabsize=0;
+ canonicalize();
+ return;
+ }
+
+ // shrink by a factor of 2
+ unsigned half_hashtabsize=hashtabsize/2;
+ for (unsigned i=0; i<half_hashtabsize-1; ++i) {
+ hashtab[i].merge(hashtab[i+half_hashtabsize],epp_is_less());
+ }
+ // special treatment for numeric hashes
+ hashtab[0].merge(hashtab[half_hashtabsize-1],epp_is_less());
+ hashtab[half_hashtabsize-1]=hashtab[hashtabsize-1];
+ hashtab.resize(half_hashtabsize);
+ hashtabsize=half_hashtabsize;
+ hashmask=hashtabsize-1;
+ }
}
void expairseq::remove_hashtab_entry(epvector::const_iterator element)
{
- if (hashtabsize==0) return; // nothing to do
-
- // calculate hashindex of element to be deleted
- unsigned hashindex=calc_hashindex((*element).rest);
-
- // find it in hashtab and remove it
- epplist & eppl=hashtab[hashindex];
- epplist::iterator epplit=eppl.begin();
- bool erased=false;
- while (epplit!=eppl.end()) {
- if (*epplit == element) {
- eppl.erase(epplit);
- erased=true;
- break;
- }
- ++epplit;
- }
- if (!erased) {
- printtree(cout,0);
- cout << "tried to erase " << element-seq.begin() << std::endl;
- cout << "size " << seq.end()-seq.begin() << std::endl;
-
- unsigned hashindex=calc_hashindex((*element).rest);
- epplist & eppl=hashtab[hashindex];
- epplist::iterator epplit=eppl.begin();
- bool erased=false;
- while (epplit!=eppl.end()) {
- if (*epplit == element) {
- eppl.erase(epplit);
- erased=true;
- break;
- }
- ++epplit;
- }
- GINAC_ASSERT(erased);
- }
- GINAC_ASSERT(erased);
+ if (hashtabsize==0) return; // nothing to do
+
+ // calculate hashindex of element to be deleted
+ unsigned hashindex=calc_hashindex((*element).rest);
+
+ // find it in hashtab and remove it
+ epplist & eppl=hashtab[hashindex];
+ epplist::iterator epplit=eppl.begin();
+ bool erased=false;
+ while (epplit!=eppl.end()) {
+ if (*epplit == element) {
+ eppl.erase(epplit);
+ erased=true;
+ break;
+ }
+ ++epplit;
+ }
+ if (!erased) {
+ printtree(cout,0);
+ cout << "tried to erase " << element-seq.begin() << std::endl;
+ cout << "size " << seq.end()-seq.begin() << std::endl;
+
+ unsigned hashindex=calc_hashindex((*element).rest);
+ epplist & eppl=hashtab[hashindex];
+ epplist::iterator epplit=eppl.begin();
+ bool erased=false;
+ while (epplit!=eppl.end()) {
+ if (*epplit == element) {
+ eppl.erase(epplit);
+ erased=true;
+ break;
+ }
+ ++epplit;
+ }
+ GINAC_ASSERT(erased);
+ }
+ GINAC_ASSERT(erased);
}
void expairseq::move_hashtab_entry(epvector::const_iterator oldpos,
- epvector::iterator newpos)
-{
- GINAC_ASSERT(hashtabsize!=0);
-
- // calculate hashindex of element which was moved
- unsigned hashindex=calc_hashindex((*newpos).rest);
-
- // find it in hashtab and modify it
- epplist & eppl=hashtab[hashindex];
- epplist::iterator epplit=eppl.begin();
- while (epplit!=eppl.end()) {
- if (*epplit == oldpos) {
- *epplit=newpos;
- break;
- }
- ++epplit;
- }
- GINAC_ASSERT(epplit!=eppl.end());
+ epvector::iterator newpos)
+{
+ GINAC_ASSERT(hashtabsize!=0);
+
+ // calculate hashindex of element which was moved
+ unsigned hashindex=calc_hashindex((*newpos).rest);
+
+ // find it in hashtab and modify it
+ epplist & eppl=hashtab[hashindex];
+ epplist::iterator epplit=eppl.begin();
+ while (epplit!=eppl.end()) {
+ if (*epplit == oldpos) {
+ *epplit=newpos;
+ break;
+ }
+ ++epplit;
+ }
+ GINAC_ASSERT(epplit!=eppl.end());
}
void expairseq::sorted_insert(epplist & eppl, epp elem)
{
- epplist::iterator current=eppl.begin();
- while ((current!=eppl.end())&&((*(*current)).is_less(*elem))) {
- ++current;
- }
- eppl.insert(current,elem);
+ epplist::iterator current=eppl.begin();
+ while ((current!=eppl.end())&&((*(*current)).is_less(*elem))) {
+ ++current;
+ }
+ eppl.insert(current,elem);
}
void expairseq::build_hashtab_and_combine(epvector::iterator & first_numeric,
- epvector::iterator & last_non_zero,
- vector<bool> & touched,
- unsigned & number_of_zeroes)
-{
- epp current=seq.begin();
-
- while (current!=first_numeric) {
- if (is_ex_exactly_of_type((*current).rest,numeric)) {
- --first_numeric;
- iter_swap(current,first_numeric);
- } else {
- // calculate hashindex
- unsigned currenthashindex=calc_hashindex((*current).rest);
-
- // test if there is already a matching expair in the hashtab-list
- epplist & eppl=hashtab[currenthashindex];
- epplist::iterator epplit=eppl.begin();
- while (epplit!=eppl.end()) {
- if ((*current).rest.is_equal((*(*epplit)).rest)) break;
- ++epplit;
- }
- if (epplit==eppl.end()) {
- // no matching expair found, append this to end of list
- sorted_insert(eppl,current);
- ++current;
- } else {
- // epplit points to a matching expair, combine it with current
- (*(*epplit)).coeff=ex_to_numeric((*(*epplit)).coeff).
- add_dyn(ex_to_numeric((*current).coeff));
-
- // move obsolete current expair to end by swapping with last_non_zero element
- // if this was a numeric, it is swapped with the expair before first_numeric
- iter_swap(current,last_non_zero);
- --first_numeric;
- if (first_numeric!=last_non_zero) iter_swap(first_numeric,current);
- --last_non_zero;
- ++number_of_zeroes;
- // test if combined term has coeff 0 and can be removed is done later
- touched[(*epplit)-seq.begin()]=true;
- }
- }
- }
+ epvector::iterator & last_non_zero,
+ vector<bool> & touched,
+ unsigned & number_of_zeroes)
+{
+ epp current=seq.begin();
+
+ while (current!=first_numeric) {
+ if (is_ex_exactly_of_type((*current).rest,numeric)) {
+ --first_numeric;
+ iter_swap(current,first_numeric);
+ } else {
+ // calculate hashindex
+ unsigned currenthashindex=calc_hashindex((*current).rest);
+
+ // test if there is already a matching expair in the hashtab-list
+ epplist & eppl=hashtab[currenthashindex];
+ epplist::iterator epplit=eppl.begin();
+ while (epplit!=eppl.end()) {
+ if ((*current).rest.is_equal((*(*epplit)).rest)) break;
+ ++epplit;
+ }
+ if (epplit==eppl.end()) {
+ // no matching expair found, append this to end of list
+ sorted_insert(eppl,current);
+ ++current;
+ } else {
+ // epplit points to a matching expair, combine it with current
+ (*(*epplit)).coeff=ex_to_numeric((*(*epplit)).coeff).
+ add_dyn(ex_to_numeric((*current).coeff));
+
+ // move obsolete current expair to end by swapping with last_non_zero element
+ // if this was a numeric, it is swapped with the expair before first_numeric
+ iter_swap(current,last_non_zero);
+ --first_numeric;
+ if (first_numeric!=last_non_zero) iter_swap(first_numeric,current);
+ --last_non_zero;
+ ++number_of_zeroes;
+ // test if combined term has coeff 0 and can be removed is done later
+ touched[(*epplit)-seq.begin()]=true;
+ }
+ }
+ }
}
void expairseq::drop_coeff_0_terms(epvector::iterator & first_numeric,
- epvector::iterator & last_non_zero,
- vector<bool> & touched,
- unsigned & number_of_zeroes)
-{
- // move terms with coeff 0 to end and remove them from hashtab
- // check only those elements which have been touched
- epp current=seq.begin();
- unsigned i=0;
- while (current!=first_numeric) {
- if (!touched[i]) {
- ++current;
- ++i;
- } else if (!ex_to_numeric((*current).coeff).is_equal(_num0())) {
- ++current;
- ++i;
- } else {
- remove_hashtab_entry(current);
-
- // move element to the end, unless it is already at the end
- if (current!=last_non_zero) {
- iter_swap(current,last_non_zero);
- --first_numeric;
- bool numeric_swapped=first_numeric!=last_non_zero;
- if (numeric_swapped) iter_swap(first_numeric,current);
- epvector::iterator changed_entry;
-
- if (numeric_swapped) {
- changed_entry=first_numeric;
- } else {
- changed_entry=last_non_zero;
- }
-
- --last_non_zero;
- ++number_of_zeroes;
-
- if (first_numeric!=current) {
-
- // change entry in hashtab which referred to first_numeric or last_non_zero to current
- move_hashtab_entry(changed_entry,current);
- touched[current-seq.begin()]=touched[changed_entry-seq.begin()];
- }
- } else {
- --first_numeric;
- --last_non_zero;
- ++number_of_zeroes;
- }
- }
- }
- GINAC_ASSERT(i==current-seq.begin());
+ epvector::iterator & last_non_zero,
+ vector<bool> & touched,
+ unsigned & number_of_zeroes)
+{
+ // move terms with coeff 0 to end and remove them from hashtab
+ // check only those elements which have been touched
+ epp current=seq.begin();
+ unsigned i=0;
+ while (current!=first_numeric) {
+ if (!touched[i]) {
+ ++current;
+ ++i;
+ } else if (!ex_to_numeric((*current).coeff).is_equal(_num0())) {
+ ++current;
+ ++i;
+ } else {
+ remove_hashtab_entry(current);
+
+ // move element to the end, unless it is already at the end
+ if (current!=last_non_zero) {
+ iter_swap(current,last_non_zero);
+ --first_numeric;
+ bool numeric_swapped=first_numeric!=last_non_zero;
+ if (numeric_swapped) iter_swap(first_numeric,current);
+ epvector::iterator changed_entry;
+
+ if (numeric_swapped) {
+ changed_entry=first_numeric;
+ } else {
+ changed_entry=last_non_zero;
+ }
+
+ --last_non_zero;
+ ++number_of_zeroes;
+
+ if (first_numeric!=current) {
+
+ // change entry in hashtab which referred to first_numeric or last_non_zero to current
+ move_hashtab_entry(changed_entry,current);
+ touched[current-seq.begin()]=touched[changed_entry-seq.begin()];
+ }
+ } else {
+ --first_numeric;
+ --last_non_zero;
+ ++number_of_zeroes;
+ }
+ }
+ }
+ 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(_ex0())) {
- return true;
- }
- }
- return false;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ if ((*cit).coeff.is_equal(_ex0())) {
+ return true;
+ }
+ }
+ return false;
}
void expairseq::add_numerics_to_hashtab(epvector::iterator first_numeric,
- epvector::const_iterator last_non_zero)
+ epvector::const_iterator last_non_zero)
{
- if (first_numeric==seq.end()) return; // no numerics
+ if (first_numeric==seq.end()) return; // no numerics
- epvector::iterator current=first_numeric;
- epvector::const_iterator last=last_non_zero+1;
- while (current!=last) {
- sorted_insert(hashtab[hashmask],current);
- ++current;
- }
+ epvector::iterator current=first_numeric;
+ epvector::const_iterator last=last_non_zero+1;
+ while (current!=last) {
+ sorted_insert(hashtab[hashmask],current);
+ ++current;
+ }
}
void expairseq::combine_same_terms(void)
{
- // combine same terms, drop term with coeff 0, move numerics to end
-
- // calculate size of hashtab
- hashtabsize=calc_hashtabsize(seq.size());
-
- // hashtabsize is a power of 2
- hashmask=hashtabsize-1;
-
- // allocate hashtab
- hashtab.clear();
- hashtab.resize(hashtabsize);
-
- if (hashtabsize==0) {
- canonicalize();
- combine_same_terms_sorted_seq();
- GINAC_ASSERT(!has_coeff_0());
- return;
- }
-
- // iterate through seq, move numerics to end,
- // fill hashtab and combine same terms
- epvector::iterator first_numeric=seq.end();
- epvector::iterator last_non_zero=seq.end()-1;
-
- vector<bool> touched;
- touched.reserve(seq.size());
- for (unsigned i=0; i<seq.size(); ++i) touched[i]=false;
-
- unsigned number_of_zeroes=0;
-
- GINAC_ASSERT(!has_coeff_0());
- build_hashtab_and_combine(first_numeric,last_non_zero,touched,number_of_zeroes);
- /*
- cout << "in combine:" << std::endl;
- printtree(cout,0);
- cout << "size=" << seq.end() - seq.begin() << std::endl;
- cout << "first_numeric=" << first_numeric - seq.begin() << std::endl;
- cout << "last_non_zero=" << last_non_zero - seq.begin() << std::endl;
- for (unsigned i=0; i<seq.size(); ++i) {
- if (touched[i]) cout << i << " is touched" << std::endl;
- }
- cout << "end in combine" << std::endl;
- */
-
- // there should not be any terms with coeff 0 from the beginning,
- // so it should be safe to skip this step
- if (number_of_zeroes!=0) {
- drop_coeff_0_terms(first_numeric,last_non_zero,touched,number_of_zeroes);
- /*
- cout << "in combine after drop:" << std::endl;
- printtree(cout,0);
- cout << "size=" << seq.end() - seq.begin() << std::endl;
- cout << "first_numeric=" << first_numeric - seq.begin() << std::endl;
- cout << "last_non_zero=" << last_non_zero - seq.begin() << std::endl;
- for (unsigned i=0; i<seq.size(); ++i) {
- if (touched[i]) cout << i << " is touched" << std::endl;
- }
- cout << "end in combine after drop" << std::endl;
- */
- }
-
- add_numerics_to_hashtab(first_numeric,last_non_zero);
-
- // pop zero elements
- for (unsigned i=0; i<number_of_zeroes; ++i) {
- seq.pop_back();
- }
-
- // shrink hashtabsize to calculated value
- GINAC_ASSERT(!has_coeff_0());
-
- shrink_hashtab();
-
- GINAC_ASSERT(!has_coeff_0());
+ // combine same terms, drop term with coeff 0, move numerics to end
+
+ // calculate size of hashtab
+ hashtabsize=calc_hashtabsize(seq.size());
+
+ // hashtabsize is a power of 2
+ hashmask=hashtabsize-1;
+
+ // allocate hashtab
+ hashtab.clear();
+ hashtab.resize(hashtabsize);
+
+ if (hashtabsize==0) {
+ canonicalize();
+ combine_same_terms_sorted_seq();
+ GINAC_ASSERT(!has_coeff_0());
+ return;
+ }
+
+ // iterate through seq, move numerics to end,
+ // fill hashtab and combine same terms
+ epvector::iterator first_numeric=seq.end();
+ epvector::iterator last_non_zero=seq.end()-1;
+
+ vector<bool> touched;
+ touched.reserve(seq.size());
+ for (unsigned i=0; i<seq.size(); ++i) touched[i]=false;
+
+ unsigned number_of_zeroes=0;
+
+ GINAC_ASSERT(!has_coeff_0());
+ build_hashtab_and_combine(first_numeric,last_non_zero,touched,number_of_zeroes);
+ /*
+ cout << "in combine:" << std::endl;
+ printtree(cout,0);
+ cout << "size=" << seq.end() - seq.begin() << std::endl;
+ cout << "first_numeric=" << first_numeric - seq.begin() << std::endl;
+ cout << "last_non_zero=" << last_non_zero - seq.begin() << std::endl;
+ for (unsigned i=0; i<seq.size(); ++i) {
+ if (touched[i]) cout << i << " is touched" << std::endl;
+ }
+ cout << "end in combine" << std::endl;
+ */
+
+ // there should not be any terms with coeff 0 from the beginning,
+ // so it should be safe to skip this step
+ if (number_of_zeroes!=0) {
+ drop_coeff_0_terms(first_numeric,last_non_zero,touched,number_of_zeroes);
+ /*
+ cout << "in combine after drop:" << std::endl;
+ printtree(cout,0);
+ cout << "size=" << seq.end() - seq.begin() << std::endl;
+ cout << "first_numeric=" << first_numeric - seq.begin() << std::endl;
+ cout << "last_non_zero=" << last_non_zero - seq.begin() << std::endl;
+ for (unsigned i=0; i<seq.size(); ++i) {
+ if (touched[i]) cout << i << " is touched" << std::endl;
+ }
+ cout << "end in combine after drop" << std::endl;
+ */
+ }
+
+ add_numerics_to_hashtab(first_numeric,last_non_zero);
+
+ // pop zero elements
+ for (unsigned i=0; i<number_of_zeroes; ++i) {
+ seq.pop_back();
+ }
+
+ // shrink hashtabsize to calculated value
+ GINAC_ASSERT(!has_coeff_0());
+
+ shrink_hashtab();
+
+ GINAC_ASSERT(!has_coeff_0());
}
#endif // def EXPAIRSEQ_USE_HASHTAB
bool expairseq::is_canonical() const
{
- if (seq.size()<=1) return 1;
+ if (seq.size()<=1) return 1;
#ifdef EXPAIRSEQ_USE_HASHTAB
- if (hashtabsize>0) return 1; // not canoncalized
+ if (hashtabsize>0) return 1; // not canoncalized
#endif // def EXPAIRSEQ_USE_HASHTAB
-
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator it_last = it;
- for (++it; it!=seq.end(); it_last=it, ++it) {
- if (!((*it_last).is_less(*it)||(*it_last).is_equal(*it))) {
- if (!is_ex_exactly_of_type((*it_last).rest,numeric)||
- !is_ex_exactly_of_type((*it).rest,numeric)) {
- // double test makes it easier to set a breakpoint...
- if (!is_ex_exactly_of_type((*it_last).rest,numeric)||
- !is_ex_exactly_of_type((*it).rest,numeric)) {
- printpair(cout,*it_last,0);
- cout << ">";
- printpair(cout,*it,0);
- cout << "\n";
- cout << "pair1:" << std::endl;
- (*it_last).rest.printtree(cout);
- (*it_last).coeff.printtree(cout);
- cout << "pair2:" << std::endl;
- (*it).rest.printtree(cout);
- (*it).coeff.printtree(cout);
- return 0;
- }
- }
- }
- }
- return 1;
+
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator it_last = it;
+ for (++it; it!=seq.end(); it_last=it, ++it) {
+ if (!((*it_last).is_less(*it)||(*it_last).is_equal(*it))) {
+ if (!is_ex_exactly_of_type((*it_last).rest,numeric)||
+ !is_ex_exactly_of_type((*it).rest,numeric)) {
+ // double test makes it easier to set a breakpoint...
+ if (!is_ex_exactly_of_type((*it_last).rest,numeric)||
+ !is_ex_exactly_of_type((*it).rest,numeric)) {
+ printpair(cout,*it_last,0);
+ cout << ">";
+ printpair(cout,*it,0);
+ cout << "\n";
+ cout << "pair1:" << std::endl;
+ (*it_last).rest.printtree(cout);
+ (*it_last).coeff.printtree(cout);
+ cout << "pair2:" << std::endl;
+ (*it).rest.printtree(cout);
+ (*it).coeff.printtree(cout);
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
}
epvector * expairseq::expandchildren(unsigned options) const
{
- epvector::const_iterator last = seq.end();
- epvector::const_iterator cit = seq.begin();
- while (cit!=last) {
- const ex & expanded_ex=(*cit).rest.expand(options);
- if (!are_ex_trivially_equal((*cit).rest,expanded_ex)) {
-
- // something changed, copy seq, eval 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(*cit2);
- ++cit2;
- }
- // copy first changed element
- s->push_back(combine_ex_with_coeff_to_pair(expanded_ex,
- (*cit2).coeff));
- ++cit2;
- // copy rest
- while (cit2!=last) {
- s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.expand(options),
- (*cit2).coeff));
- ++cit2;
- }
- return s;
- }
- ++cit;
- }
-
- return 0; // nothing has changed
+ epvector::const_iterator last = seq.end();
+ epvector::const_iterator cit = seq.begin();
+ while (cit!=last) {
+ const ex & expanded_ex=(*cit).rest.expand(options);
+ if (!are_ex_trivially_equal((*cit).rest,expanded_ex)) {
+
+ // something changed, copy seq, eval 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(*cit2);
+ ++cit2;
+ }
+ // copy first changed element
+ s->push_back(combine_ex_with_coeff_to_pair(expanded_ex,
+ (*cit2).coeff));
+ ++cit2;
+ // copy rest
+ while (cit2!=last) {
+ s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.expand(options),
+ (*cit2).coeff));
+ ++cit2;
+ }
+ return s;
+ }
+ ++cit;
+ }
+
+ return 0; // nothing has changed
}
epvector * expairseq::evalchildren(int level) const
{
- // returns a NULL pointer if nothing had to be evaluated
- // returns a pointer to a newly created epvector otherwise
- // (which has to be deleted somewhere else)
-
- if (level==1) {
- return 0;
- }
- if (level == -max_recursion_level) {
- throw(std::runtime_error("max recursion level reached"));
- }
-
- --level;
- epvector::const_iterator last=seq.end();
- epvector::const_iterator cit=seq.begin();
- while (cit!=last) {
- const ex & evaled_ex=(*cit).rest.eval(level);
- if (!are_ex_trivially_equal((*cit).rest,evaled_ex)) {
-
- // something changed, copy seq, eval 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(*cit2);
- ++cit2;
- }
- // copy first changed element
- s->push_back(combine_ex_with_coeff_to_pair(evaled_ex,
- (*cit2).coeff));
- ++cit2;
- // copy rest
- while (cit2!=last) {
- s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.eval(level),
- (*cit2).coeff));
- ++cit2;
- }
- return s;
- }
- ++cit;
- }
-
- return 0; // nothing has changed
+ // returns a NULL pointer if nothing had to be evaluated
+ // returns a pointer to a newly created epvector otherwise
+ // (which has to be deleted somewhere else)
+
+ if (level==1) {
+ return 0;
+ }
+ if (level == -max_recursion_level) {
+ throw(std::runtime_error("max recursion level reached"));
+ }
+
+ --level;
+ epvector::const_iterator last=seq.end();
+ epvector::const_iterator cit=seq.begin();
+ while (cit!=last) {
+ const ex & evaled_ex=(*cit).rest.eval(level);
+ if (!are_ex_trivially_equal((*cit).rest,evaled_ex)) {
+
+ // something changed, copy seq, eval 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(*cit2);
+ ++cit2;
+ }
+ // copy first changed element
+ s->push_back(combine_ex_with_coeff_to_pair(evaled_ex,
+ (*cit2).coeff));
+ ++cit2;
+ // copy rest
+ while (cit2!=last) {
+ s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.eval(level),
+ (*cit2).coeff));
+ ++cit2;
+ }
+ return s;
+ }
+ ++cit;
+ }
+
+ return 0; // nothing has changed
}
epvector expairseq::evalfchildren(int level) const
{
- if (level==1)
- return seq;
+ if (level==1)
+ return seq;
- if (level==-max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
-
- epvector s;
- s.reserve(seq.size());
-
- --level;
- for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- s.push_back(combine_ex_with_coeff_to_pair((*it).rest.evalf(level),
- (*it).coeff.evalf(level)));
- }
- return s;
+ if (level==-max_recursion_level)
+ throw(std::runtime_error("max recursion level reached"));
+
+ epvector s;
+ s.reserve(seq.size());
+
+ --level;
+ for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ s.push_back(combine_ex_with_coeff_to_pair((*it).rest.evalf(level),
+ (*it).coeff.evalf(level)));
+ }
+ return s;
}
epvector expairseq::normalchildren(int level) const
{
- if (level==1)
- return seq;
-
- if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
+ if (level==1)
+ return seq;
+
+ if (level == -max_recursion_level)
+ throw(std::runtime_error("max recursion level reached"));
- epvector s;
- s.reserve(seq.size());
+ epvector s;
+ s.reserve(seq.size());
- --level;
- for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- s.push_back(combine_ex_with_coeff_to_pair((*it).rest.normal(level),
- (*it).coeff));
- }
- return s;
+ --level;
+ for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ s.push_back(combine_ex_with_coeff_to_pair((*it).rest.normal(level),
+ (*it).coeff));
+ }
+ return s;
}
epvector expairseq::diffchildren(const symbol & y) const
{
- epvector s;
- s.reserve(seq.size());
+ epvector s;
+ s.reserve(seq.size());
- for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- s.push_back(combine_ex_with_coeff_to_pair((*it).rest.diff(y),
- (*it).coeff));
- }
- return s;
+ for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ s.push_back(combine_ex_with_coeff_to_pair((*it).rest.diff(y),
+ (*it).coeff));
+ }
+ return s;
}
epvector * expairseq::subschildren(const lst & ls, const lst & lr) const
{
- // 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) {
- const ex & 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(*cit2);
- ++cit2;
- }
- // copy first changed element
- s->push_back(combine_ex_with_coeff_to_pair(subsed_ex,
- (*cit2).coeff));
- ++cit2;
- // copy rest
- while (cit2!=last) {
- 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
+ // 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) {
+ const ex & 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(*cit2);
+ ++cit2;
+ }
+ // copy first changed element
+ s->push_back(combine_ex_with_coeff_to_pair(subsed_ex,
+ (*cit2).coeff));
+ ++cit2;
+ // copy rest
+ while (cit2!=last) {
+ 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
}
//////////
inline void iter_swap(epvector::iterator it1, epvector::iterator it2)
{
- (*it1).rest.swap((*it2).rest);
- (*it1).coeff.swap((*it2).coeff);
+ (*it1).rest.swap((*it2).rest);
+ (*it1).coeff.swap((*it2).coeff);
}
typedef epvector::iterator epp;
* the same way.) */
class expairseq : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(expairseq, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(expairseq, basic)
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- expairseq() : basic(TINFO_expairseq)
+ expairseq() : basic(TINFO_expairseq)
#ifdef EXPAIRSEQ_USE_HASHTAB
- , hashtabsize(0)
+ , hashtabsize(0)
#endif // def EXPAIRSEQ_USE_HASHTAB
- {
- }
- ~expairseq()
- {
- destroy(0);
- }
- expairseq(const expairseq & other);
- const expairseq & operator=(const expairseq & other);
+ {
+ }
+ ~expairseq()
+ {
+ destroy(0);
+ }
+ expairseq(const expairseq & other);
+ const expairseq & operator=(const expairseq & other);
protected:
- void copy(const expairseq & other);
- void destroy(bool call_parent)
- {
- if (call_parent) basic::destroy(call_parent);
- };
+ void copy(const expairseq & other);
+ void destroy(bool call_parent)
+ {
+ if (call_parent) basic::destroy(call_parent);
+ };
- // other constructors
+ // other constructors
public:
- expairseq(const ex & lh, const ex & rh);
- expairseq(const exvector & v);
- expairseq(const epvector & v, const ex & oc);
- expairseq(epvector * vp, const ex & oc); // vp will be deleted
+ expairseq(const ex & lh, const ex & rh);
+ expairseq(const exvector & v);
+ expairseq(const epvector & v, const ex & oc);
+ expairseq(epvector * vp, const ex & oc); // vp will be deleted
- // functions overriding virtual functions from bases classes
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- bool info(unsigned inf) const;
- unsigned nops() const;
- ex op(int i) const;
- ex & let_op(int i);
- ex eval(int level=0) const;
- ex evalf(int level=0) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
- ex to_rational(lst &repl_lst) const;
- ex subs(const lst & ls, const lst & lr) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ bool info(unsigned inf) const;
+ unsigned nops() const;
+ ex op(int i) const;
+ ex & let_op(int i);
+ ex eval(int level=0) const;
+ ex evalf(int level=0) const;
+ ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+ ex to_rational(lst &repl_lst) const;
+ ex subs(const lst & ls, const lst & lr) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned calchash(void) const;
- ex expand(unsigned options=0) const;
-
- // new virtual functions which can be overridden by derived classes
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned calchash(void) const;
+ ex expand(unsigned options=0) const;
+
+ // new virtual functions which can be overridden by derived classes
protected:
- virtual ex thisexpairseq(const epvector & v, const ex & oc) const;
- virtual ex thisexpairseq(epvector * vp, const ex & oc) const;
- virtual void printseq(std::ostream & os, char delim,
- unsigned this_precedence,
- unsigned upper_precedence) const;
- virtual void printpair(std::ostream & os, const expair & p,
- unsigned upper_precedence) const;
- virtual expair split_ex_to_pair(const ex & e) const;
- virtual expair combine_ex_with_coeff_to_pair(const ex & e,
- const ex & c) const;
- virtual expair combine_pair_with_coeff_to_pair(const expair & p,
- const ex & c) const;
- virtual ex recombine_pair_to_ex(const expair & p) const;
- virtual bool expair_needs_further_processing(epp it);
- virtual ex default_overall_coeff(void) const;
- virtual void combine_overall_coeff(const ex & c);
- virtual void combine_overall_coeff(const ex & c1, const ex & c2);
- virtual bool can_make_flat(const expair & p) const;
-
- // non-virtual functions in this class
+ virtual ex thisexpairseq(const epvector & v, const ex & oc) const;
+ virtual ex thisexpairseq(epvector * vp, const ex & oc) const;
+ virtual void printseq(std::ostream & os, char delim,
+ unsigned this_precedence,
+ unsigned upper_precedence) const;
+ virtual void printpair(std::ostream & os, const expair & p,
+ unsigned upper_precedence) const;
+ virtual expair split_ex_to_pair(const ex & e) const;
+ virtual expair combine_ex_with_coeff_to_pair(const ex & e,
+ const ex & c) const;
+ virtual expair combine_pair_with_coeff_to_pair(const expair & p,
+ const ex & c) const;
+ virtual ex recombine_pair_to_ex(const expair & p) const;
+ virtual bool expair_needs_further_processing(epp it);
+ virtual ex default_overall_coeff(void) const;
+ virtual void combine_overall_coeff(const ex & c);
+ virtual void combine_overall_coeff(const ex & c1, const ex & c2);
+ virtual bool can_make_flat(const expair & p) const;
+
+ // non-virtual functions in this class
protected:
- void construct_from_2_ex_via_exvector(const ex & lh, const ex & rh);
- void construct_from_2_ex(const ex & lh, const ex & rh);
- void construct_from_2_expairseq(const expairseq & s1,
- const expairseq & s2);
- void construct_from_expairseq_ex(const expairseq & s,
- const ex & e);
- void construct_from_exvector(const exvector & v);
- void construct_from_epvector(const epvector & v);
- void make_flat(const exvector & v);
- void make_flat(const epvector & v);
- epvector * bubblesort(epvector::iterator itbegin, epvector::iterator itend);
- epvector * mergesort(epvector::iterator itbegin, epvector::iterator itend);
- void canonicalize(void);
- void combine_same_terms_sorted_seq(void);
+ void construct_from_2_ex_via_exvector(const ex & lh, const ex & rh);
+ void construct_from_2_ex(const ex & lh, const ex & rh);
+ void construct_from_2_expairseq(const expairseq & s1,
+ const expairseq & s2);
+ void construct_from_expairseq_ex(const expairseq & s,
+ const ex & e);
+ void construct_from_exvector(const exvector & v);
+ void construct_from_epvector(const epvector & v);
+ void make_flat(const exvector & v);
+ void make_flat(const epvector & v);
+ epvector * bubblesort(epvector::iterator itbegin, epvector::iterator itend);
+ epvector * mergesort(epvector::iterator itbegin, epvector::iterator itend);
+ void canonicalize(void);
+ void combine_same_terms_sorted_seq(void);
#ifdef EXPAIRSEQ_USE_HASHTAB
- void combine_same_terms(void);
- unsigned calc_hashtabsize(unsigned sz) const;
- unsigned calc_hashindex(const ex & e) const;
- void shrink_hashtab(void);
- void remove_hashtab_entry(epvector::const_iterator element);
- void move_hashtab_entry(epvector::const_iterator oldpos,
- epvector::iterator newpos);
- void sorted_insert(epplist & eppl, epp elem);
- void build_hashtab_and_combine(epvector::iterator & first_numeric,
- epvector::iterator & last_non_zero,
- vector<bool> & touched,
- unsigned & number_of_zeroes);
- void drop_coeff_0_terms(epvector::iterator & first_numeric,
- epvector::iterator & last_non_zero,
- vector<bool> & touched,
- unsigned & number_of_zeroes);
- bool has_coeff_0(void) const;
- void add_numerics_to_hashtab(epvector::iterator first_numeric,
- epvector::const_iterator last_non_zero);
+ void combine_same_terms(void);
+ unsigned calc_hashtabsize(unsigned sz) const;
+ unsigned calc_hashindex(const ex & e) const;
+ void shrink_hashtab(void);
+ void remove_hashtab_entry(epvector::const_iterator element);
+ void move_hashtab_entry(epvector::const_iterator oldpos,
+ epvector::iterator newpos);
+ void sorted_insert(epplist & eppl, epp elem);
+ void build_hashtab_and_combine(epvector::iterator & first_numeric,
+ epvector::iterator & last_non_zero,
+ vector<bool> & touched,
+ unsigned & number_of_zeroes);
+ void drop_coeff_0_terms(epvector::iterator & first_numeric,
+ epvector::iterator & last_non_zero,
+ vector<bool> & touched,
+ unsigned & number_of_zeroes);
+ bool has_coeff_0(void) const;
+ void add_numerics_to_hashtab(epvector::iterator first_numeric,
+ epvector::const_iterator last_non_zero);
#endif // def EXPAIRSEQ_USE_HASHTAB
- bool is_canonical() const;
- epvector * expandchildren(unsigned options) const;
- epvector * evalchildren(int level) const;
- epvector evalfchildren(int level) const;
- epvector normalchildren(int level) const;
- epvector diffchildren(const symbol & s) const;
- epvector * subschildren(const lst & ls, const lst & lr) const;
-
+ bool is_canonical() const;
+ epvector * expandchildren(unsigned options) const;
+ epvector * evalchildren(int level) const;
+ epvector evalfchildren(int level) const;
+ epvector normalchildren(int level) const;
+ epvector diffchildren(const symbol & s) const;
+ epvector * subschildren(const lst & ls, const lst & lr) const;
+
// member variables
-
+
protected:
- epvector seq;
- ex overall_coeff;
- static unsigned precedence;
+ epvector seq;
+ ex overall_coeff;
+ static unsigned precedence;
#ifdef EXPAIRSEQ_USE_HASHTAB
- epplistvector hashtab;
- unsigned hashtabsize;
- unsigned hashmask;
- static unsigned maxhashtabsize;
- static unsigned minhashtabsize;
- static unsigned hashtabfactor;
+ epplistvector hashtab;
+ unsigned hashtabsize;
+ unsigned hashmask;
+ static unsigned maxhashtabsize;
+ static unsigned minhashtabsize;
+ static unsigned hashtabfactor;
#endif // def EXPAIRSEQ_USE_HASHTAB
};
bool exprseq::info(unsigned inf) const
{
- if (inf==info_flags::exprseq) return 1;
- return basic::info(inf);
+ if (inf==info_flags::exprseq) return 1;
+ return basic::info(inf);
}
ex & exprseq::let_op(int i)
{
- GINAC_ASSERT(i>=0);
- GINAC_ASSERT(i<nops());
+ GINAC_ASSERT(i>=0);
+ GINAC_ASSERT(i<nops());
- return seq[i];
+ return seq[i];
}
#ifndef NO_NAMESPACE_GINAC
fail::fail() : inherited(TINFO_fail)
{
- debugmsg("fail default constructor",LOGLEVEL_CONSTRUCT);
+ debugmsg("fail default constructor",LOGLEVEL_CONSTRUCT);
}
fail::~fail()
{
- debugmsg("fail destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("fail destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
fail::fail(const fail & other)
{
- debugmsg("fail copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("fail copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const fail & fail::operator=(const fail & other)
{
- debugmsg("fail operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("fail operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void fail::copy(const fail & other)
{
- inherited::copy(other);
+ inherited::copy(other);
}
void fail::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
/** Construct object from archive_node. */
fail::fail(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("fail constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ debugmsg("fail constructor from archive_node", LOGLEVEL_CONSTRUCT);
}
/** Unarchive the object. */
ex fail::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new fail(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new fail(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void fail::archive(archive_node &n) const
{
- inherited::archive(n);
+ inherited::archive(n);
}
//////////
basic * fail::duplicate() const
{
- debugmsg("fail duplicate",LOGLEVEL_DUPLICATE);
- return new fail(*this);
+ debugmsg("fail duplicate",LOGLEVEL_DUPLICATE);
+ return new fail(*this);
}
void fail::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("fail print",LOGLEVEL_PRINT);
- os << "FAIL";
+ debugmsg("fail print",LOGLEVEL_PRINT);
+ os << "FAIL";
}
void fail::printraw(std::ostream & os) const
{
- debugmsg("fail printraw",LOGLEVEL_PRINT);
- os << "FAIL";
+ debugmsg("fail printraw",LOGLEVEL_PRINT);
+ os << "FAIL";
}
// protected
int fail::compare_same_type(const basic & other) const
{
// two fails are always identical
- return 0;
+ return 0;
}
//////////
class fail : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(fail, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(fail, basic)
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- fail();
- ~fail();
- fail(const fail & other);
- const fail & operator=(const fail & other);
+ fail();
+ ~fail();
+ fail(const fail & other);
+ const fail & operator=(const fail & other);
protected:
- void copy(const fail & other);
- void destroy(bool call_parent);
+ void copy(const fail & other);
+ void destroy(bool call_parent);
- // other constructors
- // none
+ // other constructors
+ // none
- // functions overriding virtual functions from bases classes
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printraw(std::ostream & os) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printraw(std::ostream & os) const;
protected:
- int compare_same_type(const basic & other) const;
- unsigned return_type(void) const { return return_types::noncommutative_composite; };
-
- // new virtual functions which can be overridden by derived classes
- // none
+ int compare_same_type(const basic & other) const;
+ unsigned return_type(void) const { return return_types::noncommutative_composite; };
+
+ // new virtual functions which can be overridden by derived classes
+ // none
- // non-virtual functions in this class
- // none
+ // non-virtual functions in this class
+ // none
// member variables
// none
class expand_options {
public:
- enum { expand_trigonometric = 0x0001
- };
+ enum { expand_trigonometric = 0x0001
+ };
};
class series_options {
public:
- enum { suppress_branchcut = 0x0001
- };
+ enum { suppress_branchcut = 0x0001
+ };
};
class determinant_algo {
public:
- enum { automatic,
- gauss,
- divfree,
- laplace,
- bareiss
- };
+ enum { automatic,
+ gauss,
+ divfree,
+ laplace,
+ bareiss
+ };
};
class solve_algo {
public:
- enum { automatic,
- gauss,
- divfree,
- bareiss
- };
+ enum { automatic,
+ gauss,
+ divfree,
+ bareiss
+ };
};
class status_flags {
public:
- enum { dynallocated = 0x0001,
- evaluated = 0x0002,
- expanded = 0x0004,
- hash_calculated = 0x0008
- };
+ enum { dynallocated = 0x0001,
+ evaluated = 0x0002,
+ expanded = 0x0004,
+ hash_calculated = 0x0008
+ };
};
/** Possible attributes an object can have. */
class info_flags {
public:
- enum {
- // answered by class numeric
- numeric,
- real,
- rational,
- integer,
- crational,
- cinteger,
- positive,
- negative,
- nonnegative,
- posint,
- negint,
- nonnegint,
- even,
- odd,
- prime,
-
- // answered by class relation
- relation,
- relation_equal,
- relation_not_equal,
- relation_less,
- relation_less_or_equal,
- relation_greater,
- relation_greater_or_equal,
-
- // answered by class symbol
- symbol,
-
- // answered by class lst
- list,
-
- // answered by class exprseq
- exprseq,
-
- // answered by classes numeric, symbol, add, mul, power
- polynomial,
- integer_polynomial,
- cinteger_polynomial,
- rational_polynomial,
- crational_polynomial,
- rational_function,
- algebraic,
-
- // answered by class indexed
- indexed, // class can carry indices
- has_indices, // object has at least one index
-
- // answered by class idx
- idx,
-
- // answered by class coloridx
- coloridx,
-
- // answered by class lorentzidx
- lorentzidx
- };
+ enum {
+ // answered by class numeric
+ numeric,
+ real,
+ rational,
+ integer,
+ crational,
+ cinteger,
+ positive,
+ negative,
+ nonnegative,
+ posint,
+ negint,
+ nonnegint,
+ even,
+ odd,
+ prime,
+
+ // answered by class relation
+ relation,
+ relation_equal,
+ relation_not_equal,
+ relation_less,
+ relation_less_or_equal,
+ relation_greater,
+ relation_greater_or_equal,
+
+ // answered by class symbol
+ symbol,
+
+ // answered by class lst
+ list,
+
+ // answered by class exprseq
+ exprseq,
+
+ // answered by classes numeric, symbol, add, mul, power
+ polynomial,
+ integer_polynomial,
+ cinteger_polynomial,
+ rational_polynomial,
+ crational_polynomial,
+ rational_function,
+ algebraic,
+
+ // answered by class indexed
+ indexed, // class can carry indices
+ has_indices, // object has at least one index
+
+ // answered by class idx
+ idx,
+
+ // answered by class coloridx
+ coloridx,
+
+ // answered by class lorentzidx
+ lorentzidx
+ };
};
class return_types {
public:
- enum { commutative, noncommutative, noncommutative_composite};
+ enum { commutative, noncommutative, noncommutative_composite};
};
class csrc_types {
class remember_strategies {
public:
- enum { delete_never, // let table grow undefinitely, not recommmended, but currently default
- delete_lru, // least recently used
- delete_lfu, // least frequently used
- delete_cyclic // first (oldest) one in list
- };
+ enum { delete_never, // let table grow undefinitely, not recommmended, but currently default
+ delete_lru, // least recently used
+ delete_lfu, // least frequently used
+ delete_cyclic // first (oldest) one in list
+ };
};
#ifndef NO_NAMESPACE_GINAC
idx::idx() : inherited(TINFO_idx), symbolic(true), covariant(false)
{
- debugmsg("idx default constructor",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- name="index"+ToString(serial);
+ debugmsg("idx default constructor",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ name="index"+ToString(serial);
}
idx::~idx()
{
- debugmsg("idx destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("idx destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
idx::idx(const idx & other)
{
- debugmsg("idx copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("idx copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const idx & idx::operator=(const idx & other)
{
- debugmsg("idx operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("idx operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void idx::copy(const idx & other)
{
- inherited::copy(other);
- serial=other.serial;
- symbolic=other.symbolic;
- name=other.name;
- value=other.value;
- covariant=other.covariant;
+ inherited::copy(other);
+ serial=other.serial;
+ symbolic=other.symbolic;
+ name=other.name;
+ value=other.value;
+ covariant=other.covariant;
}
void idx::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
//////////
idx::idx(bool cov) : inherited(TINFO_idx), symbolic(true), covariant(cov)
{
- debugmsg("idx constructor from bool",LOGLEVEL_CONSTRUCT);
- serial = next_serial++;
- name = "index"+ToString(serial);
+ debugmsg("idx constructor from bool",LOGLEVEL_CONSTRUCT);
+ serial = next_serial++;
+ name = "index"+ToString(serial);
}
idx::idx(const std::string & n, bool cov) : inherited(TINFO_idx),
- symbolic(true), name(n), covariant(cov)
+ symbolic(true), name(n), covariant(cov)
{
- debugmsg("idx constructor from string,bool",LOGLEVEL_CONSTRUCT);
- serial = next_serial++;
+ debugmsg("idx constructor from string,bool",LOGLEVEL_CONSTRUCT);
+ serial = next_serial++;
}
idx::idx(const char * n, bool cov) : inherited(TINFO_idx),
- symbolic(true), name(n), covariant(cov)
+ symbolic(true), name(n), covariant(cov)
{
- debugmsg("idx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
- serial = next_serial++;
+ debugmsg("idx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
+ serial = next_serial++;
}
idx::idx(unsigned v, bool cov) : inherited(TINFO_idx),
- symbolic(false), value(v), covariant(cov)
+ symbolic(false), value(v), covariant(cov)
{
- debugmsg("idx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
- serial = 0;
+ debugmsg("idx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
+ serial = 0;
}
//////////
/** Construct object from archive_node. */
idx::idx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("idx constructor from archive_node", LOGLEVEL_CONSTRUCT);
- n.find_bool("symbolic", symbolic);
- n.find_bool("covariant", covariant);
- if (symbolic) {
- serial = next_serial++;
- if (!(n.find_string("name", name)))
- name = "index" + ToString(serial);
- } else {
- serial = 0;
- n.find_unsigned("value", value);
- }
+ debugmsg("idx constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ n.find_bool("symbolic", symbolic);
+ n.find_bool("covariant", covariant);
+ if (symbolic) {
+ serial = next_serial++;
+ if (!(n.find_string("name", name)))
+ name = "index" + ToString(serial);
+ } else {
+ serial = 0;
+ n.find_unsigned("value", value);
+ }
}
/** Unarchive the object. */
ex idx::unarchive(const archive_node &n, const lst &sym_lst)
{
- ex s = (new idx(n, sym_lst))->setflag(status_flags::dynallocated);
+ ex s = (new idx(n, sym_lst))->setflag(status_flags::dynallocated);
- if (ex_to_idx(s).symbolic) {
- // If idx is in sym_lst, return the existing idx
- for (unsigned i=0; i<sym_lst.nops(); i++) {
- if (is_ex_of_type(sym_lst.op(i), idx) && (ex_to_idx(sym_lst.op(i)).name == ex_to_idx(s).name))
- return sym_lst.op(i);
- }
- }
- return s;
+ if (ex_to_idx(s).symbolic) {
+ // If idx is in sym_lst, return the existing idx
+ for (unsigned i=0; i<sym_lst.nops(); i++) {
+ if (is_ex_of_type(sym_lst.op(i), idx) && (ex_to_idx(sym_lst.op(i)).name == ex_to_idx(s).name))
+ return sym_lst.op(i);
+ }
+ }
+ return s;
}
/** Archive the object. */
void idx::archive(archive_node &n) const
{
- inherited::archive(n);
- n.add_bool("symbolic", symbolic);
- n.add_bool("covariant", covariant);
- if (symbolic)
- n.add_string("name", name);
- else
- n.add_unsigned("value", value);
+ inherited::archive(n);
+ n.add_bool("symbolic", symbolic);
+ n.add_bool("covariant", covariant);
+ if (symbolic)
+ n.add_string("name", name);
+ else
+ n.add_unsigned("value", value);
}
//////////
basic * idx::duplicate() const
{
- debugmsg("idx duplicate",LOGLEVEL_DUPLICATE);
- return new idx(*this);
+ debugmsg("idx duplicate",LOGLEVEL_DUPLICATE);
+ return new idx(*this);
}
void idx::printraw(std::ostream & os) const
{
- debugmsg("idx printraw",LOGLEVEL_PRINT);
+ debugmsg("idx printraw",LOGLEVEL_PRINT);
- os << "idx(";
+ os << "idx(";
- if (symbolic) {
- os << "symbolic,name=" << name;
- } else {
- os << "non symbolic,value=" << value;
- }
+ if (symbolic) {
+ os << "symbolic,name=" << name;
+ } else {
+ os << "non symbolic,value=" << value;
+ }
- if (covariant) {
- os << ",covariant";
- } else {
- os << ",contravariant";
- }
+ if (covariant) {
+ os << ",covariant";
+ } else {
+ os << ",contravariant";
+ }
- os << ",serial=" << serial;
- os << ",hash=" << hashvalue << ",flags=" << flags;
- os << ")";
+ os << ",serial=" << serial;
+ os << ",hash=" << hashvalue << ",flags=" << flags;
+ os << ")";
}
void idx::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("idx printtree",LOGLEVEL_PRINT);
+ debugmsg("idx printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "idx: ";
+ os << std::string(indent,' ') << "idx: ";
- if (symbolic) {
- os << "symbolic,name=" << name;
- } else {
- os << "non symbolic,value=" << value;
- }
+ if (symbolic) {
+ os << "symbolic,name=" << name;
+ } else {
+ os << "non symbolic,value=" << value;
+ }
- if (covariant) {
- os << ",covariant";
- } else {
- os << ",contravariant";
- }
+ if (covariant) {
+ os << ",covariant";
+ } else {
+ os << ",contravariant";
+ }
- os << ", serial=" << serial
- << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ os << ", serial=" << serial
+ << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void idx::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("idx print",LOGLEVEL_PRINT);
-
- if (covariant) {
- os << "_";
- } else {
- os << "~";
- }
- if (symbolic) {
- os << name;
- } else {
- os << value;
- }
+ debugmsg("idx print",LOGLEVEL_PRINT);
+
+ if (covariant) {
+ os << "_";
+ } else {
+ os << "~";
+ }
+ if (symbolic) {
+ os << name;
+ } else {
+ os << value;
+ }
}
bool idx::info(unsigned inf) const
{
- if (inf==info_flags::idx) return true;
- return inherited::info(inf);
+ if (inf==info_flags::idx) return true;
+ return inherited::info(inf);
}
ex idx::subs(const lst & ls, const lst & lr) const
{
- GINAC_ASSERT(ls.nops()==lr.nops());
+ GINAC_ASSERT(ls.nops()==lr.nops());
#ifdef DO_GINAC_ASSERT
- for (unsigned i=0; i<ls.nops(); i++) {
- GINAC_ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
- is_ex_of_type(ls.op(i),idx));
- }
+ for (unsigned i=0; i<ls.nops(); i++) {
+ GINAC_ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
+ is_ex_of_type(ls.op(i),idx));
+ }
#endif // def DO_GINAC_ASSERT
- for (unsigned i=0; i<ls.nops(); i++) {
- if (is_equal(*(ls.op(i)).bp)) {
- return lr.op(i);
- }
- }
- return *this;
+ for (unsigned i=0; i<ls.nops(); i++) {
+ if (is_equal(*(ls.op(i)).bp)) {
+ return lr.op(i);
+ }
+ }
+ return *this;
}
// protected
int idx::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other,idx));
- const idx & o=static_cast<const idx &>
- (const_cast<basic &>(other));
-
- if (covariant!=o.covariant) {
- // different co/contravariant
- return covariant ? -1 : 1;
- }
- if ((!symbolic) && (!o.symbolic)) {
- // non-symbolic, of equal type: compare values
- if (value==o.value) {
- return 0;
- }
- return value<o.value ? -1 : 1;
- }
- if (symbolic && o.symbolic) {
- // both symbolic: compare serials
- if (serial==o.serial) {
- return 0;
- }
- return serial<o.serial ? -1 : 1;
- }
- // one symbolic, one value: value is sorted first
- return o.symbolic ? -1 : 1;
+ GINAC_ASSERT(is_of_type(other,idx));
+ const idx & o=static_cast<const idx &>
+ (const_cast<basic &>(other));
+
+ if (covariant!=o.covariant) {
+ // different co/contravariant
+ return covariant ? -1 : 1;
+ }
+ if ((!symbolic) && (!o.symbolic)) {
+ // non-symbolic, of equal type: compare values
+ if (value==o.value) {
+ return 0;
+ }
+ return value<o.value ? -1 : 1;
+ }
+ if (symbolic && o.symbolic) {
+ // both symbolic: compare serials
+ if (serial==o.serial) {
+ return 0;
+ }
+ return serial<o.serial ? -1 : 1;
+ }
+ // one symbolic, one value: value is sorted first
+ return o.symbolic ? -1 : 1;
}
bool idx::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other,idx));
- const idx & o=static_cast<const idx &>
- (const_cast<basic &>(other));
+ GINAC_ASSERT(is_of_type(other,idx));
+ const idx & o=static_cast<const idx &>
+ (const_cast<basic &>(other));
- if (covariant!=o.covariant) return false;
- if (symbolic!=o.symbolic) return false;
- if (symbolic && o.symbolic) return serial==o.serial;
- return value==o.value;
+ if (covariant!=o.covariant) return false;
+ if (symbolic!=o.symbolic) return false;
+ if (symbolic && o.symbolic) return serial==o.serial;
+ return value==o.value;
}
unsigned idx::calchash(void) const
{
- hashvalue=golden_ratio_hash(golden_ratio_hash(tinfo_key ^ serial));
- setflag(status_flags::hash_calculated);
- return hashvalue;
+ hashvalue=golden_ratio_hash(golden_ratio_hash(tinfo_key ^ serial));
+ setflag(status_flags::hash_calculated);
+ return hashvalue;
}
//////////
bool idx::is_co_contra_pair(const basic & other) const
{
- // like is_equal_same_type(), but tests for different covariant status
- GINAC_ASSERT(is_of_type(other,idx));
- const idx & o=static_cast<const idx &>
- (const_cast<basic &>(other));
+ // like is_equal_same_type(), but tests for different covariant status
+ GINAC_ASSERT(is_of_type(other,idx));
+ const idx & o=static_cast<const idx &>
+ (const_cast<basic &>(other));
- if (covariant==o.covariant) return false;
- if (symbolic!=o.symbolic) return false;
- if (symbolic && o.symbolic) return serial==o.serial;
- return value==o.value;
+ if (covariant==o.covariant) return false;
+ if (symbolic!=o.symbolic) return false;
+ if (symbolic && o.symbolic) return serial==o.serial;
+ return value==o.value;
}
bool idx::is_symbolic(void) const
{
- return symbolic;
+ return symbolic;
}
unsigned idx::get_value(void) const
{
- return value;
+ return value;
}
bool idx::is_covariant(void) const
{
- return covariant;
+ return covariant;
}
ex idx::toggle_covariant(void) const
{
- idx * i_copy=static_cast<idx *>(duplicate());
- i_copy->covariant = !i_copy->covariant;
- i_copy->clearflag(status_flags::hash_calculated);
- return i_copy->setflag(status_flags::dynallocated);
+ idx * i_copy=static_cast<idx *>(duplicate());
+ i_copy->covariant = !i_copy->covariant;
+ i_copy->clearflag(status_flags::hash_calculated);
+ return i_copy->setflag(status_flags::dynallocated);
}
//////////
int canonicalize_indices(exvector & iv, bool antisymmetric)
{
- if (iv.size()<2) {
- // nothing do to for 0 or 1 indices
- return INT_MAX;
- }
-
- bool something_changed=false;
- int sig=1;
- // simple bubble sort algorithm should be sufficient for the small number of indices needed
- exvector::const_iterator last_idx=iv.end();
- exvector::const_iterator next_to_last_idx=iv.end()-1;
- for (exvector::iterator it1=iv.begin(); it1!=next_to_last_idx; ++it1) {
- for (exvector::iterator it2=it1+1; it2!=last_idx; ++it2) {
- int cmpval=(*it1).compare(*it2);
- if (cmpval==1) {
- iter_swap(it1,it2);
- something_changed=true;
- if (antisymmetric) sig=-sig;
- } else if ((cmpval==0) && antisymmetric) {
- something_changed=true;
- sig=0;
- }
- }
- }
- return something_changed ? sig : INT_MAX;
+ if (iv.size()<2) {
+ // nothing do to for 0 or 1 indices
+ return INT_MAX;
+ }
+
+ bool something_changed=false;
+ int sig=1;
+ // simple bubble sort algorithm should be sufficient for the small number of indices needed
+ exvector::const_iterator last_idx=iv.end();
+ exvector::const_iterator next_to_last_idx=iv.end()-1;
+ for (exvector::iterator it1=iv.begin(); it1!=next_to_last_idx; ++it1) {
+ for (exvector::iterator it2=it1+1; it2!=last_idx; ++it2) {
+ int cmpval=(*it1).compare(*it2);
+ if (cmpval==1) {
+ iter_swap(it1,it2);
+ something_changed=true;
+ if (antisymmetric) sig=-sig;
+ } else if ((cmpval==0) && antisymmetric) {
+ something_changed=true;
+ sig=0;
+ }
+ }
+ }
+ return something_changed ? sig : INT_MAX;
}
exvector idx_intersect(const exvector & iv1, const exvector & iv2)
{
- // build a vector of symbolic indices contained in iv1 and iv2 simultaneously
- // assumes (but does not test) that each index occurs at most twice
- exvector iv_intersect;
- for (exvector::const_iterator cit1=iv1.begin(); cit1!=iv1.end(); ++cit1) {
- GINAC_ASSERT(is_ex_of_type(*cit1,idx));
- if (ex_to_idx(*cit1).is_symbolic()) {
- for (exvector::const_iterator cit2=iv2.begin(); cit2!=iv2.end(); ++cit2) {
- GINAC_ASSERT(is_ex_of_type(*cit2,idx));
- if ((*cit1).is_equal(*cit2)) {
- iv_intersect.push_back(*cit1);
- break;
- }
- }
- }
- }
- return iv_intersect;
+ // build a vector of symbolic indices contained in iv1 and iv2 simultaneously
+ // assumes (but does not test) that each index occurs at most twice
+ exvector iv_intersect;
+ for (exvector::const_iterator cit1=iv1.begin(); cit1!=iv1.end(); ++cit1) {
+ GINAC_ASSERT(is_ex_of_type(*cit1,idx));
+ if (ex_to_idx(*cit1).is_symbolic()) {
+ for (exvector::const_iterator cit2=iv2.begin(); cit2!=iv2.end(); ++cit2) {
+ GINAC_ASSERT(is_ex_of_type(*cit2,idx));
+ if ((*cit1).is_equal(*cit2)) {
+ iv_intersect.push_back(*cit1);
+ break;
+ }
+ }
+ }
+ }
+ return iv_intersect;
}
#define TEST_PERMUTATION(A,B,C,P) \
- if ((iv3[B].is_equal(iv2[0]))&&(iv3[C].is_equal(iv2[1]))) { \
- if (antisymmetric) *sig=P; \
- return iv3[A]; \
- }
+ if ((iv3[B].is_equal(iv2[0]))&&(iv3[C].is_equal(iv2[1]))) { \
+ if (antisymmetric) *sig=P; \
+ return iv3[A]; \
+ }
ex permute_free_index_to_front(const exvector & iv3, const exvector & iv2,
- bool antisymmetric, int * sig)
-{
- // match (return value,iv2) to iv3 by permuting indices
- // iv3 is always cyclic
-
- GINAC_ASSERT(iv3.size()==3);
- GINAC_ASSERT(iv2.size()==2);
-
- *sig=1;
-
- TEST_PERMUTATION(0,1,2, 1);
- TEST_PERMUTATION(0,2,1, -1);
- TEST_PERMUTATION(1,0,2, -1);
- TEST_PERMUTATION(1,2,0, 1);
- TEST_PERMUTATION(2,0,1, 1);
- TEST_PERMUTATION(2,1,0, -1);
- throw(std::logic_error("permute_free_index_to_front(): no valid permutation found"));
+ bool antisymmetric, int * sig)
+{
+ // match (return value,iv2) to iv3 by permuting indices
+ // iv3 is always cyclic
+
+ GINAC_ASSERT(iv3.size()==3);
+ GINAC_ASSERT(iv2.size()==2);
+
+ *sig=1;
+
+ TEST_PERMUTATION(0,1,2, 1);
+ TEST_PERMUTATION(0,2,1, -1);
+ TEST_PERMUTATION(1,0,2, -1);
+ TEST_PERMUTATION(1,2,0, 1);
+ TEST_PERMUTATION(2,0,1, 1);
+ TEST_PERMUTATION(2,1,0, -1);
+ throw(std::logic_error("permute_free_index_to_front(): no valid permutation found"));
}
-
+
unsigned subs_index_in_exvector(exvector & v, const ex & is, const ex & ir)
{
- exvector::iterator it;
- unsigned replacements=0;
- unsigned current_replacements;
+ exvector::iterator it;
+ unsigned replacements=0;
+ unsigned current_replacements;
- GINAC_ASSERT(is_ex_of_type(is,idx));
- GINAC_ASSERT(is_ex_of_type(ir,idx));
+ GINAC_ASSERT(is_ex_of_type(is,idx));
+ GINAC_ASSERT(is_ex_of_type(ir,idx));
- for (it=v.begin(); it!=v.end(); ++it) {
- current_replacements=count_index(*it,is);
- if (current_replacements>0) {
- (*it)=(*it).subs(is==ir);
- }
- replacements += current_replacements;
- }
- return replacements;
+ for (it=v.begin(); it!=v.end(); ++it) {
+ current_replacements=count_index(*it,is);
+ if (current_replacements>0) {
+ (*it)=(*it).subs(is==ir);
+ }
+ replacements += current_replacements;
+ }
+ return replacements;
}
unsigned count_index(const ex & e, const ex & i)
{
- exvector idxv=e.get_indices();
- unsigned count=0;
- for (exvector::const_iterator cit=idxv.begin(); cit!=idxv.end(); ++cit) {
- if ((*cit).is_equal(i)) count++;
- }
- return count;
+ exvector idxv=e.get_indices();
+ unsigned count=0;
+ for (exvector::const_iterator cit=idxv.begin(); cit!=idxv.end(); ++cit) {
+ if ((*cit).is_equal(i)) count++;
+ }
+ return count;
}
ex subs_indices(const ex & e, const exvector & idxv_subs,
- const exvector & idxv_repl)
-{
- GINAC_ASSERT(idxv_subs.size()==idxv_repl.size());
- ex res=e;
- for (unsigned i=0; i<idxv_subs.size(); ++i) {
- res=res.subs(idxv_subs[i]==idxv_repl[i]);
- }
- return res;
+ const exvector & idxv_repl)
+{
+ GINAC_ASSERT(idxv_subs.size()==idxv_repl.size());
+ ex res=e;
+ for (unsigned i=0; i<idxv_subs.size(); ++i) {
+ res=res.subs(idxv_subs[i]==idxv_repl[i]);
+ }
+ return res;
}
#ifndef NO_NAMESPACE_GINAC
class idx : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(idx, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(idx, basic)
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- idx();
- ~idx();
- idx (const idx & other);
- const idx & operator=(const idx & other);
+ idx();
+ ~idx();
+ idx (const idx & other);
+ const idx & operator=(const idx & other);
protected:
- void copy(const idx & other);
- void destroy(bool call_parent);
+ void copy(const idx & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- explicit idx(bool cov);
- explicit idx(const std::string & n, bool cov=false);
- explicit idx(const char * n, bool cov=false);
- explicit idx(unsigned v, bool cov=false);
+ explicit idx(bool cov);
+ explicit idx(const std::string & n, bool cov=false);
+ explicit idx(const char * n, bool cov=false);
+ explicit idx(unsigned v, bool cov=false);
- // functions overriding virtual functions from bases classes
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
protected:
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned calchash(void) const;
- ex subs(const lst & ls, const lst & lr) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned calchash(void) const;
+ ex subs(const lst & ls, const lst & lr) const;
- // new virtual functions which can be overridden by derived classes
+ // new virtual functions which can be overridden by derived classes
public:
- virtual bool is_co_contra_pair(const basic & other) const;
- virtual ex toggle_covariant(void) const;
+ virtual bool is_co_contra_pair(const basic & other) const;
+ virtual ex toggle_covariant(void) const;
- // non-virtual functions in this class
+ // non-virtual functions in this class
public:
- bool is_symbolic(void) const;
- unsigned get_value(void) const;
- bool is_covariant(void) const;
- void setname(const std::string & n) {name=n;}
- std::string getname(void) const {return name;}
+ bool is_symbolic(void) const;
+ unsigned get_value(void) const;
+ bool is_covariant(void) const;
+ void setname(const std::string & n) {name=n;}
+ std::string getname(void) const {return name;}
- // member variables
+ // member variables
protected:
- unsigned serial;
- bool symbolic;
- std::string name;
- unsigned value;
- static unsigned next_serial;
- bool covariant; // x_mu, default is contravariant: x^mu
+ unsigned serial;
+ bool symbolic;
+ std::string name;
+ unsigned value;
+ static unsigned next_serial;
+ bool covariant; // x_mu, default is contravariant: x^mu
};
// global constants
int canonicalize_indices(exvector & iv, bool antisymmetric=false);
exvector idx_intersect(const exvector & iv1, const exvector & iv2);
ex permute_free_index_to_front(const exvector & iv3, const exvector & iv2,
- bool antisymmetric, int * sig);
+ bool antisymmetric, int * sig);
unsigned subs_index_in_exvector(exvector & v, const ex & is, const ex & ir);
ex subs_indices(const ex & e, const exvector & idxv_contra,
- const exvector & idxv_co);
+ const exvector & idxv_co);
unsigned count_index(const ex & e, const ex & i);
#ifndef NO_NAMESPACE_GINAC
indexed::indexed()
{
- debugmsg("indexed default constructor",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_indexed;
+ debugmsg("indexed default constructor",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_indexed;
}
indexed::~indexed()
{
- debugmsg("indexed destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("indexed destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
indexed::indexed(const indexed & other)
{
- debugmsg("indexed copy constructor",LOGLEVEL_CONSTRUCT);
- copy (other);
+ debugmsg("indexed copy constructor",LOGLEVEL_CONSTRUCT);
+ copy (other);
}
const indexed & indexed::operator=(const indexed & other)
{
- debugmsg("indexed operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("indexed operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void indexed::copy(const indexed & other)
{
- inherited::copy(other);
+ inherited::copy(other);
}
void indexed::destroy(bool call_parent)
{
- if (call_parent) {
- inherited::destroy(call_parent);
- }
+ if (call_parent) {
+ inherited::destroy(call_parent);
+ }
}
//////////
indexed::indexed(const ex & i1) : inherited(i1)
{
- debugmsg("indexed constructor from ex",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_indexed;
- GINAC_ASSERT(all_of_type_idx());
+ debugmsg("indexed constructor from ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_indexed;
+ GINAC_ASSERT(all_of_type_idx());
}
indexed::indexed(const ex & i1, const ex & i2) : inherited(i1,i2)
{
- debugmsg("indexed constructor from ex,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_indexed;
- GINAC_ASSERT(all_of_type_idx());
+ debugmsg("indexed constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_indexed;
+ GINAC_ASSERT(all_of_type_idx());
}
indexed::indexed(const ex & i1, const ex & i2, const ex & i3)
- : inherited(i1,i2,i3)
+ : inherited(i1,i2,i3)
{
- debugmsg("indexed constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_indexed;
- GINAC_ASSERT(all_of_type_idx());
+ debugmsg("indexed constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_indexed;
+ GINAC_ASSERT(all_of_type_idx());
}
indexed::indexed(const ex & i1, const ex & i2, const ex & i3, const ex & i4)
- : inherited(i1,i2,i3,i4)
+ : inherited(i1,i2,i3,i4)
{
- debugmsg("indexed constructor from ex,ex,ex,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_indexed;
- GINAC_ASSERT(all_of_type_idx());
+ debugmsg("indexed constructor from ex,ex,ex,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_indexed;
+ GINAC_ASSERT(all_of_type_idx());
}
indexed::indexed(const exvector & iv) : inherited(iv)
{
- debugmsg("indexed constructor from exvector",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_indexed;
- GINAC_ASSERT(all_of_type_idx());
+ debugmsg("indexed constructor from exvector",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_indexed;
+ GINAC_ASSERT(all_of_type_idx());
}
indexed::indexed(exvector * ivp) : inherited(ivp)
{
- debugmsg("indexed constructor from exvector *",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_indexed;
- GINAC_ASSERT(all_of_type_idx());
+ debugmsg("indexed constructor from exvector *",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_indexed;
+ GINAC_ASSERT(all_of_type_idx());
}
//////////
/** Construct object from archive_node. */
indexed::indexed(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("indexed constructor from archive_node", LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_indexed;
+ debugmsg("indexed constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_indexed;
}
/** Unarchive the object. */
ex indexed::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new indexed(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new indexed(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void indexed::archive(archive_node &n) const
{
- inherited::archive(n);
+ inherited::archive(n);
}
//////////
basic * indexed::duplicate() const
{
- debugmsg("indexed duplicate",LOGLEVEL_DUPLICATE);
- return new indexed(*this);
+ debugmsg("indexed duplicate",LOGLEVEL_DUPLICATE);
+ return new indexed(*this);
}
void indexed::printraw(std::ostream & os) const
{
- debugmsg("indexed printraw",LOGLEVEL_PRINT);
- os << "indexed(indices=";
- printrawindices(os);
- os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+ debugmsg("indexed printraw",LOGLEVEL_PRINT);
+ os << "indexed(indices=";
+ printrawindices(os);
+ os << ",hash=" << hashvalue << ",flags=" << flags << ")";
}
void indexed::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("indexed printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "indexed: " << seq.size() << " indices";
- os << ",hash=" << hashvalue << ",flags=" << flags << std::endl;
- printtreeindices(os,indent);
+ debugmsg("indexed printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << "indexed: " << seq.size() << " indices";
+ os << ",hash=" << hashvalue << ",flags=" << flags << std::endl;
+ printtreeindices(os,indent);
}
void indexed::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("indexed print",LOGLEVEL_PRINT);
- os << "UNNAMEDINDEX";
- printindices(os);
+ debugmsg("indexed print",LOGLEVEL_PRINT);
+ os << "UNNAMEDINDEX";
+ printindices(os);
}
void indexed::printcsrc(std::ostream & os, unsigned type,
- unsigned upper_precedence) const
+ unsigned upper_precedence) const
{
- debugmsg("indexed print csrc",LOGLEVEL_PRINT);
- print(os,upper_precedence);
+ debugmsg("indexed print csrc",LOGLEVEL_PRINT);
+ print(os,upper_precedence);
}
bool indexed::info(unsigned inf) const
{
- if (inf==info_flags::indexed) return true;
- if (inf==info_flags::has_indices) return seq.size()!=0;
- return inherited::info(inf);
+ if (inf==info_flags::indexed) return true;
+ if (inf==info_flags::has_indices) return seq.size()!=0;
+ return inherited::info(inf);
}
exvector indexed::get_indices(void) const
{
- return seq;
+ return seq;
- /*
- idxvector filtered_indices;
- filtered_indices.reserve(indices.size());
- for (idxvector::const_iterator cit=indices.begin(); cit!=indices.end(); ++cit) {
- if ((*cit).get_type()==t) {
- filtered_indices.push_back(*cit);
- }
- }
- return filtered_indices;
- */
+ /*
+ idxvector filtered_indices;
+ filtered_indices.reserve(indices.size());
+ for (idxvector::const_iterator cit=indices.begin(); cit!=indices.end(); ++cit) {
+ if ((*cit).get_type()==t) {
+ filtered_indices.push_back(*cit);
+ }
+ }
+ return filtered_indices;
+ */
}
// protected
* @see ex::diff */
ex indexed::derivative(const symbol & s) const
{
- return _ex0();
+ return _ex0();
}
int indexed::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other,indexed));
- return inherited::compare_same_type(other);
+ GINAC_ASSERT(is_of_type(other,indexed));
+ return inherited::compare_same_type(other);
}
bool indexed::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other,indexed));
- return inherited::is_equal_same_type(other);
+ GINAC_ASSERT(is_of_type(other,indexed));
+ return inherited::is_equal_same_type(other);
}
unsigned indexed::return_type(void) const
{
- return return_types::noncommutative;
+ return return_types::noncommutative;
}
unsigned indexed::return_type_tinfo(void) const
{
- return tinfo_key;
+ return tinfo_key;
}
ex indexed::thisexprseq(const exvector & v) const
{
- return indexed(v);
+ return indexed(v);
}
ex indexed::thisexprseq(exvector * vp) const
{
- return indexed(vp);
+ return indexed(vp);
}
//////////
void indexed::printrawindices(std::ostream & os) const
{
- if (seq.size()!=0) {
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- (*cit).printraw(os);
- os << ",";
- }
- }
+ if (seq.size()!=0) {
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ (*cit).printraw(os);
+ os << ",";
+ }
+ }
}
void indexed::printtreeindices(std::ostream & os, unsigned indent) const
{
- if (seq.size()!=0) {
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- os << std::string(indent+delta_indent,' ');
- (*cit).printraw(os);
- os << std::endl;
- }
- }
+ if (seq.size()!=0) {
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ os << std::string(indent+delta_indent,' ');
+ (*cit).printraw(os);
+ os << std::endl;
+ }
+ }
}
void indexed::printindices(std::ostream & os) const
{
- if (seq.size()!=0) {
- if (seq.size()>1) {
- os << "{";
- }
- exvector::const_iterator last=seq.end()-1;
- exvector::const_iterator cit=seq.begin();
- for (; cit!=last; ++cit) {
- (*cit).print(os);
- os << ",";
- }
- (*cit).print(os);
- if (seq.size()>1) {
- os << "}";
- }
- }
+ if (seq.size()!=0) {
+ if (seq.size()>1) {
+ os << "{";
+ }
+ exvector::const_iterator last=seq.end()-1;
+ exvector::const_iterator cit=seq.begin();
+ for (; cit!=last; ++cit) {
+ (*cit).print(os);
+ os << ",";
+ }
+ (*cit).print(os);
+ if (seq.size()>1) {
+ os << "}";
+ }
+ }
}
bool indexed::all_of_type_idx(void) const
{
- // used only inside of ASSERTs
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- if (!is_ex_of_type(*cit,idx)) return false;
- }
- return true;
+ // used only inside of ASSERTs
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ if (!is_ex_of_type(*cit,idx)) return false;
+ }
+ return true;
}
//////////
/** Base class for non-commutative indexed objects */
class indexed : public exprseq
{
- GINAC_DECLARE_REGISTERED_CLASS(indexed, exprseq)
+ GINAC_DECLARE_REGISTERED_CLASS(indexed, exprseq)
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- indexed();
- ~indexed();
- indexed(const indexed & other);
- const indexed & operator=(const indexed & other);
+ indexed();
+ ~indexed();
+ indexed(const indexed & other);
+ const indexed & operator=(const indexed & other);
protected:
- void copy(const indexed & other);
- void destroy(bool call_parent);
+ void copy(const indexed & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- indexed(const ex & i1);
- indexed(const ex & i1, const ex & i2);
- indexed(const ex & i1, const ex & i2, const ex & i3);
- indexed(const ex & i1, const ex & i2, const ex & i3, const ex & i4);
- indexed(const exvector & iv);
- indexed(exvector * iv);
-
- // functions overriding virtual functions from base classes
+ indexed(const ex & i1);
+ indexed(const ex & i1, const ex & i2);
+ indexed(const ex & i1, const ex & i2, const ex & i3);
+ indexed(const ex & i1, const ex & i2, const ex & i3, const ex & i4);
+ indexed(const exvector & iv);
+ indexed(exvector * iv);
+
+ // functions overriding virtual functions from base classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const;
- bool info(unsigned inf) const;
- exvector get_indices(void) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const;
+ bool info(unsigned inf) const;
+ exvector get_indices(void) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+ ex thisexprseq(const exvector & v) const;
+ ex thisexprseq(exvector * vp) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
protected:
- void printrawindices(std::ostream & os) const;
- void printtreeindices(std::ostream & os, unsigned indent) const;
- void printindices(std::ostream & os) const;
- bool all_of_type_idx(void) const;
+ void printrawindices(std::ostream & os) const;
+ void printtreeindices(std::ostream & os, unsigned indent) const;
+ void printindices(std::ostream & os) const;
+ bool all_of_type_idx(void) const;
// member variables
- // none
+ // none
};
// global constants
static ex abs_evalf(const ex & arg)
{
- BEGIN_TYPECHECK
- TYPECHECK(arg,numeric)
- END_TYPECHECK(abs(arg))
-
- return abs(ex_to_numeric(arg));
+ BEGIN_TYPECHECK
+ TYPECHECK(arg,numeric)
+ END_TYPECHECK(abs(arg))
+
+ return abs(ex_to_numeric(arg));
}
static ex abs_eval(const ex & arg)
{
- if (is_ex_exactly_of_type(arg, numeric))
- return abs(ex_to_numeric(arg));
- else
- return abs(arg).hold();
+ if (is_ex_exactly_of_type(arg, numeric))
+ return abs(ex_to_numeric(arg));
+ else
+ return abs(arg).hold();
}
REGISTER_FUNCTION(abs, eval_func(abs_eval).
- evalf_func(abs_evalf));
+ evalf_func(abs_evalf));
//////////
static ex csgn_evalf(const ex & arg)
{
- BEGIN_TYPECHECK
- TYPECHECK(arg,numeric)
- END_TYPECHECK(csgn(arg))
-
- return csgn(ex_to_numeric(arg));
+ BEGIN_TYPECHECK
+ TYPECHECK(arg,numeric)
+ END_TYPECHECK(csgn(arg))
+
+ return csgn(ex_to_numeric(arg));
}
static ex csgn_eval(const ex & arg)
{
- if (is_ex_exactly_of_type(arg, numeric))
- return csgn(ex_to_numeric(arg));
-
- else if (is_ex_exactly_of_type(arg, mul)) {
- numeric oc = ex_to_numeric(arg.op(arg.nops()-1));
- if (oc.is_real()) {
- if (oc > 0)
- // csgn(42*x) -> csgn(x)
- return csgn(arg/oc).hold();
- else
- // csgn(-42*x) -> -csgn(x)
- return -csgn(arg/oc).hold();
- }
- if (oc.real().is_zero()) {
- if (oc.imag() > 0)
- // csgn(42*I*x) -> csgn(I*x)
- return csgn(I*arg/oc).hold();
- else
- // csgn(-42*I*x) -> -csgn(I*x)
- return -csgn(I*arg/oc).hold();
- }
+ if (is_ex_exactly_of_type(arg, numeric))
+ return csgn(ex_to_numeric(arg));
+
+ else if (is_ex_exactly_of_type(arg, mul)) {
+ numeric oc = ex_to_numeric(arg.op(arg.nops()-1));
+ if (oc.is_real()) {
+ if (oc > 0)
+ // csgn(42*x) -> csgn(x)
+ return csgn(arg/oc).hold();
+ else
+ // csgn(-42*x) -> -csgn(x)
+ return -csgn(arg/oc).hold();
+ }
+ if (oc.real().is_zero()) {
+ if (oc.imag() > 0)
+ // csgn(42*I*x) -> csgn(I*x)
+ return csgn(I*arg/oc).hold();
+ else
+ // csgn(-42*I*x) -> -csgn(I*x)
+ return -csgn(I*arg/oc).hold();
+ }
}
- return csgn(arg).hold();
+ return csgn(arg).hold();
}
static ex csgn_series(const ex & arg,
- const relational & rel,
- int order,
- unsigned options)
+ const relational & rel,
+ int order,
+ unsigned options)
{
- const ex arg_pt = arg.subs(rel);
- if (arg_pt.info(info_flags::numeric) &&
- ex_to_numeric(arg_pt).real().is_zero())
- throw (std::domain_error("csgn_series(): on imaginary axis"));
-
- epvector seq;
- seq.push_back(expair(csgn(arg_pt), _ex0()));
- return pseries(rel,seq);
+ const ex arg_pt = arg.subs(rel);
+ if (arg_pt.info(info_flags::numeric) &&
+ ex_to_numeric(arg_pt).real().is_zero())
+ throw (std::domain_error("csgn_series(): on imaginary axis"));
+
+ epvector seq;
+ seq.push_back(expair(csgn(arg_pt), _ex0()));
+ return pseries(rel,seq);
}
REGISTER_FUNCTION(csgn, eval_func(csgn_eval).
- evalf_func(csgn_evalf).
- series_func(csgn_series));
+ evalf_func(csgn_evalf).
+ series_func(csgn_series));
//////////
static ex eta_evalf(const ex & x, const ex & y)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- TYPECHECK(y,numeric)
- END_TYPECHECK(eta(x,y))
-
- numeric xim = imag(ex_to_numeric(x));
- numeric yim = imag(ex_to_numeric(y));
- numeric xyim = imag(ex_to_numeric(x*y));
- return evalf(I/4*Pi)*((csgn(-xim)+1)*(csgn(-yim)+1)*(csgn(xyim)+1)-(csgn(xim)+1)*(csgn(yim)+1)*(csgn(-xyim)+1));
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ TYPECHECK(y,numeric)
+ END_TYPECHECK(eta(x,y))
+
+ numeric xim = imag(ex_to_numeric(x));
+ numeric yim = imag(ex_to_numeric(y));
+ numeric xyim = imag(ex_to_numeric(x*y));
+ return evalf(I/4*Pi)*((csgn(-xim)+1)*(csgn(-yim)+1)*(csgn(xyim)+1)-(csgn(xim)+1)*(csgn(yim)+1)*(csgn(-xyim)+1));
}
static ex eta_eval(const ex & x, const ex & y)
{
- if (is_ex_exactly_of_type(x, numeric) &&
- is_ex_exactly_of_type(y, numeric)) {
- // don't call eta_evalf here because it would call Pi.evalf()!
- numeric xim = imag(ex_to_numeric(x));
- numeric yim = imag(ex_to_numeric(y));
- numeric xyim = imag(ex_to_numeric(x*y));
- return (I/4)*Pi*((csgn(-xim)+1)*(csgn(-yim)+1)*(csgn(xyim)+1)-(csgn(xim)+1)*(csgn(yim)+1)*(csgn(-xyim)+1));
- }
-
- return eta(x,y).hold();
+ if (is_ex_exactly_of_type(x, numeric) &&
+ is_ex_exactly_of_type(y, numeric)) {
+ // don't call eta_evalf here because it would call Pi.evalf()!
+ numeric xim = imag(ex_to_numeric(x));
+ numeric yim = imag(ex_to_numeric(y));
+ numeric xyim = imag(ex_to_numeric(x*y));
+ return (I/4)*Pi*((csgn(-xim)+1)*(csgn(-yim)+1)*(csgn(xyim)+1)-(csgn(xim)+1)*(csgn(yim)+1)*(csgn(-xyim)+1));
+ }
+
+ return eta(x,y).hold();
}
static ex eta_series(const ex & arg1,
- const ex & arg2,
- const relational & rel,
- int order,
- unsigned options)
+ const ex & arg2,
+ const relational & rel,
+ int order,
+ unsigned options)
{
- const ex arg1_pt = arg1.subs(rel);
- const ex arg2_pt = arg2.subs(rel);
- if (ex_to_numeric(arg1_pt).imag().is_zero() ||
- ex_to_numeric(arg2_pt).imag().is_zero() ||
- ex_to_numeric(arg1_pt*arg2_pt).imag().is_zero()) {
- throw (std::domain_error("eta_series(): on discontinuity"));
- }
- epvector seq;
- seq.push_back(expair(eta(arg1_pt,arg2_pt), _ex0()));
- return pseries(rel,seq);
+ const ex arg1_pt = arg1.subs(rel);
+ const ex arg2_pt = arg2.subs(rel);
+ if (ex_to_numeric(arg1_pt).imag().is_zero() ||
+ ex_to_numeric(arg2_pt).imag().is_zero() ||
+ ex_to_numeric(arg1_pt*arg2_pt).imag().is_zero()) {
+ throw (std::domain_error("eta_series(): on discontinuity"));
+ }
+ epvector seq;
+ seq.push_back(expair(eta(arg1_pt,arg2_pt), _ex0()));
+ return pseries(rel,seq);
}
REGISTER_FUNCTION(eta, eval_func(eta_eval).
- evalf_func(eta_evalf).
- series_func(eta_series));
+ evalf_func(eta_evalf).
+ series_func(eta_series));
//////////
static ex Li2_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(Li2(x))
-
- return Li2(ex_to_numeric(x)); // -> numeric Li2(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(Li2(x))
+
+ return Li2(ex_to_numeric(x)); // -> numeric Li2(numeric)
}
static ex Li2_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // Li2(0) -> 0
- if (x.is_zero())
- return _ex0();
- // Li2(1) -> Pi^2/6
- if (x.is_equal(_ex1()))
- return power(Pi,_ex2())/_ex6();
- // Li2(1/2) -> Pi^2/12 - log(2)^2/2
- if (x.is_equal(_ex1_2()))
- return power(Pi,_ex2())/_ex12() + power(log(_ex2()),_ex2())*_ex_1_2();
- // Li2(-1) -> -Pi^2/12
- if (x.is_equal(_ex_1()))
- return -power(Pi,_ex2())/_ex12();
- // Li2(I) -> -Pi^2/48+Catalan*I
- if (x.is_equal(I))
- return power(Pi,_ex2())/_ex_48() + Catalan*I;
- // Li2(-I) -> -Pi^2/48-Catalan*I
- if (x.is_equal(-I))
- return power(Pi,_ex2())/_ex_48() - Catalan*I;
- // Li2(float)
- if (!x.info(info_flags::crational))
- return Li2_evalf(x);
- }
-
- return Li2(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // Li2(0) -> 0
+ if (x.is_zero())
+ return _ex0();
+ // Li2(1) -> Pi^2/6
+ if (x.is_equal(_ex1()))
+ return power(Pi,_ex2())/_ex6();
+ // Li2(1/2) -> Pi^2/12 - log(2)^2/2
+ if (x.is_equal(_ex1_2()))
+ return power(Pi,_ex2())/_ex12() + power(log(_ex2()),_ex2())*_ex_1_2();
+ // Li2(-1) -> -Pi^2/12
+ if (x.is_equal(_ex_1()))
+ return -power(Pi,_ex2())/_ex12();
+ // Li2(I) -> -Pi^2/48+Catalan*I
+ if (x.is_equal(I))
+ return power(Pi,_ex2())/_ex_48() + Catalan*I;
+ // Li2(-I) -> -Pi^2/48-Catalan*I
+ if (x.is_equal(-I))
+ return power(Pi,_ex2())/_ex_48() - Catalan*I;
+ // Li2(float)
+ if (!x.info(info_flags::crational))
+ return Li2_evalf(x);
+ }
+
+ return Li2(x).hold();
}
static ex Li2_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx Li2(x) -> -log(1-x)/x
- return -log(1-x)/x;
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx Li2(x) -> -log(1-x)/x
+ return -log(1-x)/x;
}
static ex Li2_series(const ex &x, const relational &rel, int order, unsigned options)
{
- const ex x_pt = x.subs(rel);
- if (x_pt.info(info_flags::numeric)) {
- // First special case: x==0 (derivatives have poles)
- if (x_pt.is_zero()) {
- // method:
- // The problem is that in d/dx Li2(x==0) == -log(1-x)/x we cannot
- // simply substitute x==0. The limit, however, exists: it is 1.
- // We also know all higher derivatives' limits:
- // (d/dx)^n Li2(x) == n!/n^2.
- // So the primitive series expansion is
- // Li2(x==0) == x + x^2/4 + x^3/9 + ...
- // and so on.
- // We first construct such a primitive series expansion manually in
- // a dummy symbol s and then insert the argument's series expansion
- // for s. Reexpanding the resulting series returns the desired
- // result.
- const symbol s;
- ex ser;
- // manually construct the primitive expansion
- for (int i=1; i<order; ++i)
- ser += pow(s,i) / pow(numeric(i), _num2());
- // substitute the argument's series expansion
- ser = ser.subs(s==x.series(rel, order));
- // maybe that was terminating, so add a proper order term
- epvector nseq;
- nseq.push_back(expair(Order(_ex1()), order));
- ser += pseries(rel, nseq);
- // reexpanding it will collapse the series again
- return ser.series(rel, order);
- // NB: Of course, this still does not allow us to compute anything
- // like sin(Li2(x)).series(x==0,2), since then this code here is
- // not reached and the derivative of sin(Li2(x)) doesn't allow the
- // substitution x==0. Probably limits *are* needed for the general
- // cases. In case L'Hospital's rule is implemented for limits and
- // basic::series() takes care of this, this whole block is probably
- // obsolete!
- }
- // second special case: x==1 (branch point)
- if (x_pt == _ex1()) {
- // method:
- // construct series manually in a dummy symbol s
- const symbol s;
- ex ser = zeta(2);
- // manually construct the primitive expansion
- for (int i=1; i<order; ++i)
- ser += pow(1-s,i) * (numeric(1,i)*(I*Pi+log(s-1)) - numeric(1,i*i));
- // substitute the argument's series expansion
- ser = ser.subs(s==x.series(rel, order));
- // maybe that was terminating, so add a proper order term
- epvector nseq;
- nseq.push_back(expair(Order(_ex1()), order));
- ser += pseries(rel, nseq);
- // reexpanding it will collapse the series again
- return ser.series(rel, order);
- }
- // third special case: x real, >=1 (branch cut)
- if (!(options & series_options::suppress_branchcut) &&
- ex_to_numeric(x_pt).is_real() && ex_to_numeric(x_pt)>1) {
- // method:
- // This is the branch cut: assemble the primitive series manually
- // and then add the corresponding complex step function.
- const symbol *s = static_cast<symbol *>(rel.lhs().bp);
- const ex point = rel.rhs();
- const symbol foo;
- epvector seq;
- // zeroth order term:
- seq.push_back(expair(Li2(x_pt), _ex0()));
- // compute the intermediate terms:
- ex replarg = series(Li2(x), *s==foo, order);
- for (unsigned i=1; i<replarg.nops()-1; ++i)
- seq.push_back(expair((replarg.op(i)/power(*s-foo,i)).series(foo==point,1,options).op(0).subs(foo==*s),i));
- // append an order term:
- seq.push_back(expair(Order(_ex1()), replarg.nops()-1));
- return pseries(rel, seq);
- }
- }
- // all other cases should be safe, by now:
- throw do_taylor(); // caught by function::series()
+ const ex x_pt = x.subs(rel);
+ if (x_pt.info(info_flags::numeric)) {
+ // First special case: x==0 (derivatives have poles)
+ if (x_pt.is_zero()) {
+ // method:
+ // The problem is that in d/dx Li2(x==0) == -log(1-x)/x we cannot
+ // simply substitute x==0. The limit, however, exists: it is 1.
+ // We also know all higher derivatives' limits:
+ // (d/dx)^n Li2(x) == n!/n^2.
+ // So the primitive series expansion is
+ // Li2(x==0) == x + x^2/4 + x^3/9 + ...
+ // and so on.
+ // We first construct such a primitive series expansion manually in
+ // a dummy symbol s and then insert the argument's series expansion
+ // for s. Reexpanding the resulting series returns the desired
+ // result.
+ const symbol s;
+ ex ser;
+ // manually construct the primitive expansion
+ for (int i=1; i<order; ++i)
+ ser += pow(s,i) / pow(numeric(i), _num2());
+ // substitute the argument's series expansion
+ ser = ser.subs(s==x.series(rel, order));
+ // maybe that was terminating, so add a proper order term
+ epvector nseq;
+ nseq.push_back(expair(Order(_ex1()), order));
+ ser += pseries(rel, nseq);
+ // reexpanding it will collapse the series again
+ return ser.series(rel, order);
+ // NB: Of course, this still does not allow us to compute anything
+ // like sin(Li2(x)).series(x==0,2), since then this code here is
+ // not reached and the derivative of sin(Li2(x)) doesn't allow the
+ // substitution x==0. Probably limits *are* needed for the general
+ // cases. In case L'Hospital's rule is implemented for limits and
+ // basic::series() takes care of this, this whole block is probably
+ // obsolete!
+ }
+ // second special case: x==1 (branch point)
+ if (x_pt == _ex1()) {
+ // method:
+ // construct series manually in a dummy symbol s
+ const symbol s;
+ ex ser = zeta(2);
+ // manually construct the primitive expansion
+ for (int i=1; i<order; ++i)
+ ser += pow(1-s,i) * (numeric(1,i)*(I*Pi+log(s-1)) - numeric(1,i*i));
+ // substitute the argument's series expansion
+ ser = ser.subs(s==x.series(rel, order));
+ // maybe that was terminating, so add a proper order term
+ epvector nseq;
+ nseq.push_back(expair(Order(_ex1()), order));
+ ser += pseries(rel, nseq);
+ // reexpanding it will collapse the series again
+ return ser.series(rel, order);
+ }
+ // third special case: x real, >=1 (branch cut)
+ if (!(options & series_options::suppress_branchcut) &&
+ ex_to_numeric(x_pt).is_real() && ex_to_numeric(x_pt)>1) {
+ // method:
+ // This is the branch cut: assemble the primitive series manually
+ // and then add the corresponding complex step function.
+ const symbol *s = static_cast<symbol *>(rel.lhs().bp);
+ const ex point = rel.rhs();
+ const symbol foo;
+ epvector seq;
+ // zeroth order term:
+ seq.push_back(expair(Li2(x_pt), _ex0()));
+ // compute the intermediate terms:
+ ex replarg = series(Li2(x), *s==foo, order);
+ for (unsigned i=1; i<replarg.nops()-1; ++i)
+ seq.push_back(expair((replarg.op(i)/power(*s-foo,i)).series(foo==point,1,options).op(0).subs(foo==*s),i));
+ // append an order term:
+ seq.push_back(expair(Order(_ex1()), replarg.nops()-1));
+ return pseries(rel, seq);
+ }
+ }
+ // all other cases should be safe, by now:
+ throw do_taylor(); // caught by function::series()
}
REGISTER_FUNCTION(Li2, eval_func(Li2_eval).
- evalf_func(Li2_evalf).
- derivative_func(Li2_deriv).
- series_func(Li2_series));
+ evalf_func(Li2_evalf).
+ derivative_func(Li2_deriv).
+ series_func(Li2_series));
//////////
// trilogarithm
static ex Li3_eval(const ex & x)
{
- if (x.is_zero())
- return x;
- return Li3(x).hold();
+ if (x.is_zero())
+ return x;
+ return Li3(x).hold();
}
REGISTER_FUNCTION(Li3, eval_func(Li3_eval));
static ex factorial_evalf(const ex & x)
{
- return factorial(x).hold();
+ return factorial(x).hold();
}
static ex factorial_eval(const ex & x)
{
- if (is_ex_exactly_of_type(x, numeric))
- return factorial(ex_to_numeric(x));
- else
- return factorial(x).hold();
+ if (is_ex_exactly_of_type(x, numeric))
+ return factorial(ex_to_numeric(x));
+ else
+ return factorial(x).hold();
}
REGISTER_FUNCTION(factorial, eval_func(factorial_eval).
- evalf_func(factorial_evalf));
+ evalf_func(factorial_evalf));
//////////
// binomial
static ex binomial_evalf(const ex & x, const ex & y)
{
- return binomial(x, y).hold();
+ return binomial(x, y).hold();
}
static ex binomial_eval(const ex & x, const ex &y)
{
- if (is_ex_exactly_of_type(x, numeric) && is_ex_exactly_of_type(y, numeric))
- return binomial(ex_to_numeric(x), ex_to_numeric(y));
- else
- return binomial(x, y).hold();
+ if (is_ex_exactly_of_type(x, numeric) && is_ex_exactly_of_type(y, numeric))
+ return binomial(ex_to_numeric(x), ex_to_numeric(y));
+ else
+ return binomial(x, y).hold();
}
REGISTER_FUNCTION(binomial, eval_func(binomial_eval).
- evalf_func(binomial_evalf));
+ evalf_func(binomial_evalf));
//////////
// Order term function (for truncated power series)
static ex Order_eval(const ex & x)
{
- if (is_ex_exactly_of_type(x, numeric)) {
- // O(c) -> O(1) or 0
- if (!x.is_zero())
- return Order(_ex1()).hold();
- else
- return _ex0();
- } else if (is_ex_exactly_of_type(x, mul)) {
- mul *m = static_cast<mul *>(x.bp);
- // O(c*expr) -> O(expr)
- if (is_ex_exactly_of_type(m->op(m->nops() - 1), numeric))
- return Order(x / m->op(m->nops() - 1)).hold();
- }
- return Order(x).hold();
+ if (is_ex_exactly_of_type(x, numeric)) {
+ // O(c) -> O(1) or 0
+ if (!x.is_zero())
+ return Order(_ex1()).hold();
+ else
+ return _ex0();
+ } else if (is_ex_exactly_of_type(x, mul)) {
+ mul *m = static_cast<mul *>(x.bp);
+ // O(c*expr) -> O(expr)
+ if (is_ex_exactly_of_type(m->op(m->nops() - 1), numeric))
+ return Order(x / m->op(m->nops() - 1)).hold();
+ }
+ return Order(x).hold();
}
static ex Order_series(const ex & x, const relational & r, int order, unsigned options)
{
// Just wrap the function into a pseries object
epvector new_seq;
- GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
- const symbol *s = static_cast<symbol *>(r.lhs().bp);
+ GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
+ const symbol *s = static_cast<symbol *>(r.lhs().bp);
new_seq.push_back(expair(Order(_ex1()), numeric(std::min(x.ldegree(*s), order))));
return pseries(r, new_seq);
}
// Differentiation is handled in function::derivative because of its special requirements
REGISTER_FUNCTION(Order, eval_func(Order_eval).
- series_func(Order_series));
+ series_func(Order_series));
//////////
// Inert partial differentiation operator
static ex Derivative_eval(const ex & f, const ex & l)
{
if (!is_ex_exactly_of_type(f, function)) {
- throw(std::invalid_argument("Derivative(): 1st argument must be a function"));
+ throw(std::invalid_argument("Derivative(): 1st argument must be a function"));
+ }
+ if (!is_ex_exactly_of_type(l, lst)) {
+ throw(std::invalid_argument("Derivative(): 2nd argument must be a list"));
}
- if (!is_ex_exactly_of_type(l, lst)) {
- throw(std::invalid_argument("Derivative(): 2nd argument must be a list"));
- }
return Derivative(f, l).hold();
}
ex lsolve(const ex &eqns, const ex &symbols)
{
- // solve a system of linear equations
- if (eqns.info(info_flags::relation_equal)) {
- if (!symbols.info(info_flags::symbol))
- throw(std::invalid_argument("lsolve(): 2nd argument must be a symbol"));
- ex sol=lsolve(lst(eqns),lst(symbols));
-
- GINAC_ASSERT(sol.nops()==1);
- GINAC_ASSERT(is_ex_exactly_of_type(sol.op(0),relational));
-
- return sol.op(0).op(1); // return rhs of first solution
- }
-
- // syntax checks
- if (!eqns.info(info_flags::list)) {
- throw(std::invalid_argument("lsolve(): 1st argument must be a list"));
- }
- for (unsigned i=0; i<eqns.nops(); i++) {
- if (!eqns.op(i).info(info_flags::relation_equal)) {
- throw(std::invalid_argument("lsolve(): 1st argument must be a list of equations"));
- }
- }
- if (!symbols.info(info_flags::list)) {
- throw(std::invalid_argument("lsolve(): 2nd argument must be a list"));
- }
- for (unsigned i=0; i<symbols.nops(); i++) {
- if (!symbols.op(i).info(info_flags::symbol)) {
- throw(std::invalid_argument("lsolve(): 2nd argument must be a list of symbols"));
- }
- }
-
- // build matrix from equation system
- matrix sys(eqns.nops(),symbols.nops());
- matrix rhs(eqns.nops(),1);
- matrix vars(symbols.nops(),1);
-
- for (unsigned r=0; r<eqns.nops(); r++) {
- ex eq = eqns.op(r).op(0)-eqns.op(r).op(1); // lhs-rhs==0
- ex linpart = eq;
- for (unsigned c=0; c<symbols.nops(); c++) {
- ex co = eq.coeff(ex_to_symbol(symbols.op(c)),1);
- linpart -= co*symbols.op(c);
- sys.set(r,c,co);
- }
- linpart = linpart.expand();
- rhs.set(r,0,-linpart);
- }
-
- // test if system is linear and fill vars matrix
- for (unsigned i=0; i<symbols.nops(); i++) {
- vars.set(i,0,symbols.op(i));
- if (sys.has(symbols.op(i)))
- throw(std::logic_error("lsolve: system is not linear"));
- if (rhs.has(symbols.op(i)))
- throw(std::logic_error("lsolve: system is not linear"));
- }
-
- matrix solution;
- try {
- solution = sys.solve(vars,rhs);
- } catch (const runtime_error & e) {
- // Probably singular matrix or otherwise overdetermined system:
- // It is consistent to return an empty list
- return lst();
- }
- GINAC_ASSERT(solution.cols()==1);
- GINAC_ASSERT(solution.rows()==symbols.nops());
-
- // return list of equations of the form lst(var1==sol1,var2==sol2,...)
- lst sollist;
- for (unsigned i=0; i<symbols.nops(); i++)
- sollist.append(symbols.op(i)==solution(i,0));
-
- return sollist;
+ // solve a system of linear equations
+ if (eqns.info(info_flags::relation_equal)) {
+ if (!symbols.info(info_flags::symbol))
+ throw(std::invalid_argument("lsolve(): 2nd argument must be a symbol"));
+ ex sol=lsolve(lst(eqns),lst(symbols));
+
+ GINAC_ASSERT(sol.nops()==1);
+ GINAC_ASSERT(is_ex_exactly_of_type(sol.op(0),relational));
+
+ return sol.op(0).op(1); // return rhs of first solution
+ }
+
+ // syntax checks
+ if (!eqns.info(info_flags::list)) {
+ throw(std::invalid_argument("lsolve(): 1st argument must be a list"));
+ }
+ for (unsigned i=0; i<eqns.nops(); i++) {
+ if (!eqns.op(i).info(info_flags::relation_equal)) {
+ throw(std::invalid_argument("lsolve(): 1st argument must be a list of equations"));
+ }
+ }
+ if (!symbols.info(info_flags::list)) {
+ throw(std::invalid_argument("lsolve(): 2nd argument must be a list"));
+ }
+ for (unsigned i=0; i<symbols.nops(); i++) {
+ if (!symbols.op(i).info(info_flags::symbol)) {
+ throw(std::invalid_argument("lsolve(): 2nd argument must be a list of symbols"));
+ }
+ }
+
+ // build matrix from equation system
+ matrix sys(eqns.nops(),symbols.nops());
+ matrix rhs(eqns.nops(),1);
+ matrix vars(symbols.nops(),1);
+
+ for (unsigned r=0; r<eqns.nops(); r++) {
+ ex eq = eqns.op(r).op(0)-eqns.op(r).op(1); // lhs-rhs==0
+ ex linpart = eq;
+ for (unsigned c=0; c<symbols.nops(); c++) {
+ ex co = eq.coeff(ex_to_symbol(symbols.op(c)),1);
+ linpart -= co*symbols.op(c);
+ sys.set(r,c,co);
+ }
+ linpart = linpart.expand();
+ rhs.set(r,0,-linpart);
+ }
+
+ // test if system is linear and fill vars matrix
+ for (unsigned i=0; i<symbols.nops(); i++) {
+ vars.set(i,0,symbols.op(i));
+ if (sys.has(symbols.op(i)))
+ throw(std::logic_error("lsolve: system is not linear"));
+ if (rhs.has(symbols.op(i)))
+ throw(std::logic_error("lsolve: system is not linear"));
+ }
+
+ matrix solution;
+ try {
+ solution = sys.solve(vars,rhs);
+ } catch (const runtime_error & e) {
+ // Probably singular matrix or otherwise overdetermined system:
+ // It is consistent to return an empty list
+ return lst();
+ }
+ GINAC_ASSERT(solution.cols()==1);
+ GINAC_ASSERT(solution.rows()==symbols.nops());
+
+ // return list of equations of the form lst(var1==sol1,var2==sol2,...)
+ lst sollist;
+ for (unsigned i=0; i<symbols.nops(); i++)
+ sollist.append(symbols.op(i)==solution(i,0));
+
+ return sollist;
}
/** non-commutative power. */
ex ncpower(const ex &basis, unsigned exponent)
{
- if (exponent==0) {
- return _ex1();
- }
+ if (exponent==0) {
+ return _ex1();
+ }
- exvector v;
- v.reserve(exponent);
- for (unsigned i=0; i<exponent; ++i) {
- v.push_back(basis);
- }
+ exvector v;
+ v.reserve(exponent);
+ for (unsigned i=0; i<exponent; ++i) {
+ v.push_back(basis);
+ }
- return ncmul(v,1);
+ return ncmul(v,1);
}
/** Force inclusion of functions from initcns_gamma and inifcns_zeta
/** Absolute value. */
DECLARE_FUNCTION_1P(abs)
-
+
/** Complex sign. */
DECLARE_FUNCTION_1P(csgn)
/** Riemann's Zeta-function. */
extern const unsigned function_index_zeta1;
inline function zeta(const ex & p1) {
- return function(function_index_zeta1, p1);
+ return function(function_index_zeta1, p1);
}
/** Derivatives of Riemann's Zeta-function. */
extern const unsigned function_index_zeta2;
inline function zeta(const ex & p1, const ex & p2) {
- return function(function_index_zeta2, p1, p2);
+ return function(function_index_zeta2, p1, p2);
}
/** Gamma-function. */
/** Psi-function (aka digamma-function). */
extern const unsigned function_index_psi1;
inline function psi(const ex & p1) {
- return function(function_index_psi1, p1);
+ return function(function_index_psi1, p1);
}
/** Derivatives of Psi-function (aka polygamma-functions). */
extern const unsigned function_index_psi2;
inline function psi(const ex & p1, const ex & p2) {
- return function(function_index_psi2, p1, p2);
+ return function(function_index_psi2, p1, p2);
}
-
+
/** Factorial function. */
DECLARE_FUNCTION_1P(factorial)
inline bool is_order_function(const ex & e)
{
- return is_ex_the_function(e, Order);
+ return is_ex_the_function(e, Order);
}
#ifndef NO_NAMESPACE_GINAC
static ex lgamma_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(lgamma(x))
-
- return lgamma(ex_to_numeric(x));
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(lgamma(x))
+
+ return lgamma(ex_to_numeric(x));
}
* @exception GiNaC::pole_error("lgamma_eval(): logarithmic pole",0) */
static ex lgamma_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // trap integer arguments:
- if (x.info(info_flags::integer)) {
- // lgamma(n) -> log((n-1)!) for postitive n
- if (x.info(info_flags::posint))
- return log(factorial(x.exadd(_ex_1())));
- else
- throw (pole_error("lgamma_eval(): logarithmic pole",0));
- }
- // lgamma_evalf should be called here once it becomes available
- }
-
- return lgamma(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // trap integer arguments:
+ if (x.info(info_flags::integer)) {
+ // lgamma(n) -> log((n-1)!) for postitive n
+ if (x.info(info_flags::posint))
+ return log(factorial(x.exadd(_ex_1())));
+ else
+ throw (pole_error("lgamma_eval(): logarithmic pole",0));
+ }
+ // lgamma_evalf should be called here once it becomes available
+ }
+
+ return lgamma(x).hold();
}
static ex lgamma_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx lgamma(x) -> psi(x)
- return psi(x);
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx lgamma(x) -> psi(x)
+ return psi(x);
}
static ex lgamma_series(const ex & arg,
- const relational & rel,
- int order,
- unsigned options)
+ const relational & rel,
+ int order,
+ unsigned options)
{
- // method:
- // Taylor series where there is no pole falls back to psi function
- // evaluation.
- // On a pole at -m we could use the recurrence relation
- // lgamma(x) == lgamma(x+1)-log(x)
- // from which follows
- // series(lgamma(x),x==-m,order) ==
- // series(lgamma(x+m+1)-log(x)...-log(x+m)),x==-m,order);
- const ex arg_pt = arg.subs(rel);
- if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive))
- throw do_taylor(); // caught by function::series()
- // if we got here we have to care for a simple pole of tgamma(-m):
- numeric m = -ex_to_numeric(arg_pt);
- ex recur;
- for (numeric p; p<=m; ++p)
- recur += log(arg+p);
- cout << recur << endl;
- return (lgamma(arg+m+_ex1())-recur).series(rel, order, options);
+ // method:
+ // Taylor series where there is no pole falls back to psi function
+ // evaluation.
+ // On a pole at -m we could use the recurrence relation
+ // lgamma(x) == lgamma(x+1)-log(x)
+ // from which follows
+ // series(lgamma(x),x==-m,order) ==
+ // series(lgamma(x+m+1)-log(x)...-log(x+m)),x==-m,order);
+ const ex arg_pt = arg.subs(rel);
+ if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive))
+ throw do_taylor(); // caught by function::series()
+ // if we got here we have to care for a simple pole of tgamma(-m):
+ numeric m = -ex_to_numeric(arg_pt);
+ ex recur;
+ for (numeric p; p<=m; ++p)
+ recur += log(arg+p);
+ cout << recur << endl;
+ return (lgamma(arg+m+_ex1())-recur).series(rel, order, options);
}
REGISTER_FUNCTION(lgamma, eval_func(lgamma_eval).
- evalf_func(lgamma_evalf).
- derivative_func(lgamma_deriv).
- series_func(lgamma_series));
+ evalf_func(lgamma_evalf).
+ derivative_func(lgamma_deriv).
+ series_func(lgamma_series));
//////////
static ex tgamma_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(tgamma(x))
-
- return tgamma(ex_to_numeric(x));
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(tgamma(x))
+
+ return tgamma(ex_to_numeric(x));
}
* @exception pole_error("tgamma_eval(): simple pole",0) */
static ex tgamma_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // trap integer arguments:
- if (x.info(info_flags::integer)) {
- // tgamma(n) -> (n-1)! for postitive n
- if (x.info(info_flags::posint)) {
- return factorial(ex_to_numeric(x).sub(_num1()));
- } else {
- throw (pole_error("tgamma_eval(): simple pole",1));
- }
- }
- // trap half integer arguments:
- if ((x*2).info(info_flags::integer)) {
- // trap positive x==(n+1/2)
- // tgamma(n+1/2) -> Pi^(1/2)*(1*3*..*(2*n-1))/(2^n)
- if ((x*_ex2()).info(info_flags::posint)) {
- numeric n = ex_to_numeric(x).sub(_num1_2());
- numeric coefficient = doublefactorial(n.mul(_num2()).sub(_num1()));
- coefficient = coefficient.div(pow(_num2(),n));
- return coefficient * pow(Pi,_ex1_2());
- } else {
- // trap negative x==(-n+1/2)
- // tgamma(-n+1/2) -> Pi^(1/2)*(-2)^n/(1*3*..*(2*n-1))
- numeric n = abs(ex_to_numeric(x).sub(_num1_2()));
- numeric coefficient = pow(_num_2(), n);
- coefficient = coefficient.div(doublefactorial(n.mul(_num2()).sub(_num1())));;
- return coefficient*power(Pi,_ex1_2());
- }
- }
- // tgamma_evalf should be called here once it becomes available
- }
-
- return tgamma(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // trap integer arguments:
+ if (x.info(info_flags::integer)) {
+ // tgamma(n) -> (n-1)! for postitive n
+ if (x.info(info_flags::posint)) {
+ return factorial(ex_to_numeric(x).sub(_num1()));
+ } else {
+ throw (pole_error("tgamma_eval(): simple pole",1));
+ }
+ }
+ // trap half integer arguments:
+ if ((x*2).info(info_flags::integer)) {
+ // trap positive x==(n+1/2)
+ // tgamma(n+1/2) -> Pi^(1/2)*(1*3*..*(2*n-1))/(2^n)
+ if ((x*_ex2()).info(info_flags::posint)) {
+ numeric n = ex_to_numeric(x).sub(_num1_2());
+ numeric coefficient = doublefactorial(n.mul(_num2()).sub(_num1()));
+ coefficient = coefficient.div(pow(_num2(),n));
+ return coefficient * pow(Pi,_ex1_2());
+ } else {
+ // trap negative x==(-n+1/2)
+ // tgamma(-n+1/2) -> Pi^(1/2)*(-2)^n/(1*3*..*(2*n-1))
+ numeric n = abs(ex_to_numeric(x).sub(_num1_2()));
+ numeric coefficient = pow(_num_2(), n);
+ coefficient = coefficient.div(doublefactorial(n.mul(_num2()).sub(_num1())));;
+ return coefficient*power(Pi,_ex1_2());
+ }
+ }
+ // tgamma_evalf should be called here once it becomes available
+ }
+
+ return tgamma(x).hold();
}
static ex tgamma_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx tgamma(x) -> psi(x)*tgamma(x)
- return psi(x)*tgamma(x);
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx tgamma(x) -> psi(x)*tgamma(x)
+ return psi(x)*tgamma(x);
}
static ex tgamma_series(const ex & arg,
- const relational & rel,
- int order,
- unsigned options)
+ const relational & rel,
+ int order,
+ unsigned options)
{
- // method:
- // Taylor series where there is no pole falls back to psi function
- // evaluation.
- // On a pole at -m use the recurrence relation
- // tgamma(x) == tgamma(x+1) / x
- // from which follows
- // series(tgamma(x),x==-m,order) ==
- // series(tgamma(x+m+1)/(x*(x+1)*...*(x+m)),x==-m,order+1);
- const ex arg_pt = arg.subs(rel);
- if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive))
- throw do_taylor(); // caught by function::series()
- // if we got here we have to care for a simple pole at -m:
- numeric m = -ex_to_numeric(arg_pt);
- ex ser_denom = _ex1();
- for (numeric p; p<=m; ++p)
- ser_denom *= arg+p;
- return (tgamma(arg+m+_ex1())/ser_denom).series(rel, order+1, options);
+ // method:
+ // Taylor series where there is no pole falls back to psi function
+ // evaluation.
+ // On a pole at -m use the recurrence relation
+ // tgamma(x) == tgamma(x+1) / x
+ // from which follows
+ // series(tgamma(x),x==-m,order) ==
+ // series(tgamma(x+m+1)/(x*(x+1)*...*(x+m)),x==-m,order+1);
+ const ex arg_pt = arg.subs(rel);
+ if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive))
+ throw do_taylor(); // caught by function::series()
+ // if we got here we have to care for a simple pole at -m:
+ numeric m = -ex_to_numeric(arg_pt);
+ ex ser_denom = _ex1();
+ for (numeric p; p<=m; ++p)
+ ser_denom *= arg+p;
+ return (tgamma(arg+m+_ex1())/ser_denom).series(rel, order+1, options);
}
REGISTER_FUNCTION(tgamma, eval_func(tgamma_eval).
- evalf_func(tgamma_evalf).
- derivative_func(tgamma_deriv).
- series_func(tgamma_series));
+ evalf_func(tgamma_evalf).
+ derivative_func(tgamma_deriv).
+ series_func(tgamma_series));
//////////
static ex beta_evalf(const ex & x, const ex & y)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- TYPECHECK(y,numeric)
- END_TYPECHECK(beta(x,y))
-
- return tgamma(ex_to_numeric(x))*tgamma(ex_to_numeric(y))/tgamma(ex_to_numeric(x+y));
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ TYPECHECK(y,numeric)
+ END_TYPECHECK(beta(x,y))
+
+ return tgamma(ex_to_numeric(x))*tgamma(ex_to_numeric(y))/tgamma(ex_to_numeric(x+y));
}
static ex beta_eval(const ex & x, const ex & y)
{
- if (x.info(info_flags::numeric) && y.info(info_flags::numeric)) {
- // treat all problematic x and y that may not be passed into tgamma,
- // because they would throw there although beta(x,y) is well-defined
- // using the formula beta(x,y) == (-1)^y * beta(1-x-y, y)
- numeric nx(ex_to_numeric(x));
- numeric ny(ex_to_numeric(y));
- if (nx.is_real() && nx.is_integer() &&
- ny.is_real() && ny.is_integer()) {
- if (nx.is_negative()) {
- if (nx<=-ny)
- return pow(_num_1(), ny)*beta(1-x-y, y);
- else
- throw (pole_error("beta_eval(): simple pole",1));
- }
- if (ny.is_negative()) {
- if (ny<=-nx)
- return pow(_num_1(), nx)*beta(1-y-x, x);
- else
- throw (pole_error("beta_eval(): simple pole",1));
- }
- return tgamma(x)*tgamma(y)/tgamma(x+y);
- }
- // no problem in numerator, but denominator has pole:
- if ((nx+ny).is_real() &&
- (nx+ny).is_integer() &&
- !(nx+ny).is_positive())
- return _ex0();
- // everything is ok:
- return tgamma(x)*tgamma(y)/tgamma(x+y);
- }
-
- return beta(x,y).hold();
+ if (x.info(info_flags::numeric) && y.info(info_flags::numeric)) {
+ // treat all problematic x and y that may not be passed into tgamma,
+ // because they would throw there although beta(x,y) is well-defined
+ // using the formula beta(x,y) == (-1)^y * beta(1-x-y, y)
+ numeric nx(ex_to_numeric(x));
+ numeric ny(ex_to_numeric(y));
+ if (nx.is_real() && nx.is_integer() &&
+ ny.is_real() && ny.is_integer()) {
+ if (nx.is_negative()) {
+ if (nx<=-ny)
+ return pow(_num_1(), ny)*beta(1-x-y, y);
+ else
+ throw (pole_error("beta_eval(): simple pole",1));
+ }
+ if (ny.is_negative()) {
+ if (ny<=-nx)
+ return pow(_num_1(), nx)*beta(1-y-x, x);
+ else
+ throw (pole_error("beta_eval(): simple pole",1));
+ }
+ return tgamma(x)*tgamma(y)/tgamma(x+y);
+ }
+ // no problem in numerator, but denominator has pole:
+ if ((nx+ny).is_real() &&
+ (nx+ny).is_integer() &&
+ !(nx+ny).is_positive())
+ return _ex0();
+ // everything is ok:
+ return tgamma(x)*tgamma(y)/tgamma(x+y);
+ }
+
+ return beta(x,y).hold();
}
static ex beta_deriv(const ex & x, const ex & y, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param<2);
- ex retval;
-
- // d/dx beta(x,y) -> (psi(x)-psi(x+y)) * beta(x,y)
- if (deriv_param==0)
- retval = (psi(x)-psi(x+y))*beta(x,y);
- // d/dy beta(x,y) -> (psi(y)-psi(x+y)) * beta(x,y)
- if (deriv_param==1)
- retval = (psi(y)-psi(x+y))*beta(x,y);
- return retval;
+ GINAC_ASSERT(deriv_param<2);
+ ex retval;
+
+ // d/dx beta(x,y) -> (psi(x)-psi(x+y)) * beta(x,y)
+ if (deriv_param==0)
+ retval = (psi(x)-psi(x+y))*beta(x,y);
+ // d/dy beta(x,y) -> (psi(y)-psi(x+y)) * beta(x,y)
+ if (deriv_param==1)
+ retval = (psi(y)-psi(x+y))*beta(x,y);
+ return retval;
}
static ex beta_series(const ex & arg1,
- const ex & arg2,
- const relational & rel,
- int order,
- unsigned options)
+ const ex & arg2,
+ const relational & rel,
+ int order,
+ unsigned options)
{
- // method:
- // Taylor series where there is no pole of one of the tgamma functions
- // falls back to beta function evaluation. Otherwise, fall back to
- // tgamma series directly.
- const ex arg1_pt = arg1.subs(rel);
- const ex arg2_pt = arg2.subs(rel);
- GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
- const symbol *s = static_cast<symbol *>(rel.lhs().bp);
- ex arg1_ser, arg2_ser, arg1arg2_ser;
- if ((!arg1_pt.info(info_flags::integer) || arg1_pt.info(info_flags::positive)) &&
- (!arg2_pt.info(info_flags::integer) || arg2_pt.info(info_flags::positive)))
- throw do_taylor(); // caught by function::series()
- // trap the case where arg1 is on a pole:
- if (arg1.info(info_flags::integer) && !arg1.info(info_flags::positive))
- arg1_ser = tgamma(arg1+*s).series(rel, order, options);
- else
- arg1_ser = tgamma(arg1).series(rel,order);
- // trap the case where arg2 is on a pole:
- if (arg2.info(info_flags::integer) && !arg2.info(info_flags::positive))
- arg2_ser = tgamma(arg2+*s).series(rel, order, options);
- else
- arg2_ser = tgamma(arg2).series(rel,order);
- // trap the case where arg1+arg2 is on a pole:
- if ((arg1+arg2).info(info_flags::integer) && !(arg1+arg2).info(info_flags::positive))
- arg1arg2_ser = tgamma(arg2+arg1+*s).series(rel, order, options);
- else
- arg1arg2_ser = tgamma(arg2+arg1).series(rel,order);
- // compose the result (expanding all the terms):
- return (arg1_ser*arg2_ser/arg1arg2_ser).series(rel, order, options).expand();
+ // method:
+ // Taylor series where there is no pole of one of the tgamma functions
+ // falls back to beta function evaluation. Otherwise, fall back to
+ // tgamma series directly.
+ const ex arg1_pt = arg1.subs(rel);
+ const ex arg2_pt = arg2.subs(rel);
+ GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
+ const symbol *s = static_cast<symbol *>(rel.lhs().bp);
+ ex arg1_ser, arg2_ser, arg1arg2_ser;
+ if ((!arg1_pt.info(info_flags::integer) || arg1_pt.info(info_flags::positive)) &&
+ (!arg2_pt.info(info_flags::integer) || arg2_pt.info(info_flags::positive)))
+ throw do_taylor(); // caught by function::series()
+ // trap the case where arg1 is on a pole:
+ if (arg1.info(info_flags::integer) && !arg1.info(info_flags::positive))
+ arg1_ser = tgamma(arg1+*s).series(rel, order, options);
+ else
+ arg1_ser = tgamma(arg1).series(rel,order);
+ // trap the case where arg2 is on a pole:
+ if (arg2.info(info_flags::integer) && !arg2.info(info_flags::positive))
+ arg2_ser = tgamma(arg2+*s).series(rel, order, options);
+ else
+ arg2_ser = tgamma(arg2).series(rel,order);
+ // trap the case where arg1+arg2 is on a pole:
+ if ((arg1+arg2).info(info_flags::integer) && !(arg1+arg2).info(info_flags::positive))
+ arg1arg2_ser = tgamma(arg2+arg1+*s).series(rel, order, options);
+ else
+ arg1arg2_ser = tgamma(arg2+arg1).series(rel,order);
+ // compose the result (expanding all the terms):
+ return (arg1_ser*arg2_ser/arg1arg2_ser).series(rel, order, options).expand();
}
REGISTER_FUNCTION(beta, eval_func(beta_eval).
- evalf_func(beta_evalf).
- derivative_func(beta_deriv).
- series_func(beta_series));
+ evalf_func(beta_evalf).
+ derivative_func(beta_deriv).
+ series_func(beta_series));
//////////
static ex psi1_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(psi(x))
-
- return psi(ex_to_numeric(x));
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(psi(x))
+
+ return psi(ex_to_numeric(x));
}
/** Evaluation of digamma-function psi(x).
* Somebody ought to provide some good numerical evaluation some day... */
static ex psi1_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- numeric nx = ex_to_numeric(x);
- if (nx.is_integer()) {
- // integer case
- if (nx.is_positive()) {
- // psi(n) -> 1 + 1/2 +...+ 1/(n-1) - Euler
- numeric rat(0);
- for (numeric i(nx+_num_1()); i.is_positive(); --i)
- rat += i.inverse();
- return rat-Euler;
- } else {
- // for non-positive integers there is a pole:
- throw (pole_error("psi_eval(): simple pole",1));
- }
- }
- if ((_num2()*nx).is_integer()) {
- // half integer case
- if (nx.is_positive()) {
- // psi((2m+1)/2) -> 2/(2m+1) + 2/2m +...+ 2/1 - Euler - 2log(2)
- numeric rat(0);
- for (numeric i((nx+_num_1())*_num2()); i.is_positive(); i-=_num2())
- rat += _num2()*i.inverse();
- return rat-Euler-_ex2()*log(_ex2());
- } else {
- // use the recurrence relation
- // psi(-m-1/2) == psi(-m-1/2+1) - 1 / (-m-1/2)
- // to relate psi(-m-1/2) to psi(1/2):
- // psi(-m-1/2) == psi(1/2) + r
- // where r == ((-1/2)^(-1) + ... + (-m-1/2)^(-1))
- numeric recur(0);
- for (numeric p(nx); p<0; ++p)
- recur -= pow(p, _num_1());
- return recur+psi(_ex1_2());
- }
- }
- // psi1_evalf should be called here once it becomes available
- }
-
- return psi(x).hold();
+ if (x.info(info_flags::numeric)) {
+ numeric nx = ex_to_numeric(x);
+ if (nx.is_integer()) {
+ // integer case
+ if (nx.is_positive()) {
+ // psi(n) -> 1 + 1/2 +...+ 1/(n-1) - Euler
+ numeric rat(0);
+ for (numeric i(nx+_num_1()); i.is_positive(); --i)
+ rat += i.inverse();
+ return rat-Euler;
+ } else {
+ // for non-positive integers there is a pole:
+ throw (pole_error("psi_eval(): simple pole",1));
+ }
+ }
+ if ((_num2()*nx).is_integer()) {
+ // half integer case
+ if (nx.is_positive()) {
+ // psi((2m+1)/2) -> 2/(2m+1) + 2/2m +...+ 2/1 - Euler - 2log(2)
+ numeric rat(0);
+ for (numeric i((nx+_num_1())*_num2()); i.is_positive(); i-=_num2())
+ rat += _num2()*i.inverse();
+ return rat-Euler-_ex2()*log(_ex2());
+ } else {
+ // use the recurrence relation
+ // psi(-m-1/2) == psi(-m-1/2+1) - 1 / (-m-1/2)
+ // to relate psi(-m-1/2) to psi(1/2):
+ // psi(-m-1/2) == psi(1/2) + r
+ // where r == ((-1/2)^(-1) + ... + (-m-1/2)^(-1))
+ numeric recur(0);
+ for (numeric p(nx); p<0; ++p)
+ recur -= pow(p, _num_1());
+ return recur+psi(_ex1_2());
+ }
+ }
+ // psi1_evalf should be called here once it becomes available
+ }
+
+ return psi(x).hold();
}
static ex psi1_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx psi(x) -> psi(1,x)
- return psi(_ex1(), x);
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx psi(x) -> psi(1,x)
+ return psi(_ex1(), x);
}
static ex psi1_series(const ex & arg,
- const relational & rel,
- int order,
- unsigned options)
+ const relational & rel,
+ int order,
+ unsigned options)
{
- // method:
- // Taylor series where there is no pole falls back to polygamma function
- // evaluation.
- // On a pole at -m use the recurrence relation
- // psi(x) == psi(x+1) - 1/z
- // from which follows
- // series(psi(x),x==-m,order) ==
- // series(psi(x+m+1) - 1/x - 1/(x+1) - 1/(x+m)),x==-m,order);
- const ex arg_pt = arg.subs(rel);
- if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive))
- throw do_taylor(); // caught by function::series()
- // if we got here we have to care for a simple pole at -m:
- numeric m = -ex_to_numeric(arg_pt);
- ex recur;
- for (numeric p; p<=m; ++p)
- recur += power(arg+p,_ex_1());
- return (psi(arg+m+_ex1())-recur).series(rel, order, options);
+ // method:
+ // Taylor series where there is no pole falls back to polygamma function
+ // evaluation.
+ // On a pole at -m use the recurrence relation
+ // psi(x) == psi(x+1) - 1/z
+ // from which follows
+ // series(psi(x),x==-m,order) ==
+ // series(psi(x+m+1) - 1/x - 1/(x+1) - 1/(x+m)),x==-m,order);
+ const ex arg_pt = arg.subs(rel);
+ if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive))
+ throw do_taylor(); // caught by function::series()
+ // if we got here we have to care for a simple pole at -m:
+ numeric m = -ex_to_numeric(arg_pt);
+ ex recur;
+ for (numeric p; p<=m; ++p)
+ recur += power(arg+p,_ex_1());
+ return (psi(arg+m+_ex1())-recur).series(rel, order, options);
}
const unsigned function_index_psi1 =
- function::register_new(function_options("psi").
- eval_func(psi1_eval).
- evalf_func(psi1_evalf).
+ function::register_new(function_options("psi").
+ eval_func(psi1_eval).
+ evalf_func(psi1_evalf).
derivative_func(psi1_deriv).
series_func(psi1_series).
overloaded(2));
static ex psi2_evalf(const ex & n, const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(n,numeric)
- TYPECHECK(x,numeric)
- END_TYPECHECK(psi(n,x))
-
- return psi(ex_to_numeric(n), ex_to_numeric(x));
+ BEGIN_TYPECHECK
+ TYPECHECK(n,numeric)
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(psi(n,x))
+
+ return psi(ex_to_numeric(n), ex_to_numeric(x));
}
/** Evaluation of polygamma-function psi(n,x).
* Somebody ought to provide some good numerical evaluation some day... */
static ex psi2_eval(const ex & n, const ex & x)
{
- // psi(0,x) -> psi(x)
- if (n.is_zero())
- return psi(x);
- // psi(-1,x) -> log(tgamma(x))
- if (n.is_equal(_ex_1()))
- return log(tgamma(x));
- if (n.info(info_flags::numeric) && n.info(info_flags::posint) &&
- x.info(info_flags::numeric)) {
- numeric nn = ex_to_numeric(n);
- numeric nx = ex_to_numeric(x);
- if (nx.is_integer()) {
- // integer case
- if (nx.is_equal(_num1()))
- // use psi(n,1) == (-)^(n+1) * n! * zeta(n+1)
- return pow(_num_1(),nn+_num1())*factorial(nn)*zeta(ex(nn+_num1()));
- if (nx.is_positive()) {
- // use the recurrence relation
- // psi(n,m) == psi(n,m+1) - (-)^n * n! / m^(n+1)
- // to relate psi(n,m) to psi(n,1):
- // psi(n,m) == psi(n,1) + r
- // where r == (-)^n * n! * (1^(-n-1) + ... + (m-1)^(-n-1))
- numeric recur(0);
- for (numeric p(1); p<nx; ++p)
- recur += pow(p, -nn+_num_1());
- recur *= factorial(nn)*pow(_num_1(), nn);
- return recur+psi(n,_ex1());
- } else {
- // for non-positive integers there is a pole:
- throw (pole_error("psi2_eval(): pole",1));
- }
- }
- if ((_num2()*nx).is_integer()) {
- // half integer case
- if (nx.is_equal(_num1_2()))
- // use psi(n,1/2) == (-)^(n+1) * n! * (2^(n+1)-1) * zeta(n+1)
- return pow(_num_1(),nn+_num1())*factorial(nn)*(pow(_num2(),nn+_num1()) + _num_1())*zeta(ex(nn+_num1()));
- if (nx.is_positive()) {
- numeric m = nx - _num1_2();
- // use the multiplication formula
- // psi(n,2*m) == (psi(n,m) + psi(n,m+1/2)) / 2^(n+1)
- // to revert to positive integer case
- return psi(n,_num2()*m)*pow(_num2(),nn+_num1())-psi(n,m);
- } else {
- // use the recurrence relation
- // psi(n,-m-1/2) == psi(n,-m-1/2+1) - (-)^n * n! / (-m-1/2)^(n+1)
- // to relate psi(n,-m-1/2) to psi(n,1/2):
- // psi(n,-m-1/2) == psi(n,1/2) + r
- // where r == (-)^(n+1) * n! * ((-1/2)^(-n-1) + ... + (-m-1/2)^(-n-1))
- numeric recur(0);
- for (numeric p(nx); p<0; ++p)
- recur += pow(p, -nn+_num_1());
- recur *= factorial(nn)*pow(_num_1(), nn+_num_1());
- return recur+psi(n,_ex1_2());
- }
- }
- // psi2_evalf should be called here once it becomes available
- }
-
- return psi(n, x).hold();
+ // psi(0,x) -> psi(x)
+ if (n.is_zero())
+ return psi(x);
+ // psi(-1,x) -> log(tgamma(x))
+ if (n.is_equal(_ex_1()))
+ return log(tgamma(x));
+ if (n.info(info_flags::numeric) && n.info(info_flags::posint) &&
+ x.info(info_flags::numeric)) {
+ numeric nn = ex_to_numeric(n);
+ numeric nx = ex_to_numeric(x);
+ if (nx.is_integer()) {
+ // integer case
+ if (nx.is_equal(_num1()))
+ // use psi(n,1) == (-)^(n+1) * n! * zeta(n+1)
+ return pow(_num_1(),nn+_num1())*factorial(nn)*zeta(ex(nn+_num1()));
+ if (nx.is_positive()) {
+ // use the recurrence relation
+ // psi(n,m) == psi(n,m+1) - (-)^n * n! / m^(n+1)
+ // to relate psi(n,m) to psi(n,1):
+ // psi(n,m) == psi(n,1) + r
+ // where r == (-)^n * n! * (1^(-n-1) + ... + (m-1)^(-n-1))
+ numeric recur(0);
+ for (numeric p(1); p<nx; ++p)
+ recur += pow(p, -nn+_num_1());
+ recur *= factorial(nn)*pow(_num_1(), nn);
+ return recur+psi(n,_ex1());
+ } else {
+ // for non-positive integers there is a pole:
+ throw (pole_error("psi2_eval(): pole",1));
+ }
+ }
+ if ((_num2()*nx).is_integer()) {
+ // half integer case
+ if (nx.is_equal(_num1_2()))
+ // use psi(n,1/2) == (-)^(n+1) * n! * (2^(n+1)-1) * zeta(n+1)
+ return pow(_num_1(),nn+_num1())*factorial(nn)*(pow(_num2(),nn+_num1()) + _num_1())*zeta(ex(nn+_num1()));
+ if (nx.is_positive()) {
+ numeric m = nx - _num1_2();
+ // use the multiplication formula
+ // psi(n,2*m) == (psi(n,m) + psi(n,m+1/2)) / 2^(n+1)
+ // to revert to positive integer case
+ return psi(n,_num2()*m)*pow(_num2(),nn+_num1())-psi(n,m);
+ } else {
+ // use the recurrence relation
+ // psi(n,-m-1/2) == psi(n,-m-1/2+1) - (-)^n * n! / (-m-1/2)^(n+1)
+ // to relate psi(n,-m-1/2) to psi(n,1/2):
+ // psi(n,-m-1/2) == psi(n,1/2) + r
+ // where r == (-)^(n+1) * n! * ((-1/2)^(-n-1) + ... + (-m-1/2)^(-n-1))
+ numeric recur(0);
+ for (numeric p(nx); p<0; ++p)
+ recur += pow(p, -nn+_num_1());
+ recur *= factorial(nn)*pow(_num_1(), nn+_num_1());
+ return recur+psi(n,_ex1_2());
+ }
+ }
+ // psi2_evalf should be called here once it becomes available
+ }
+
+ return psi(n, x).hold();
}
static ex psi2_deriv(const ex & n, const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param<2);
-
- if (deriv_param==0) {
- // d/dn psi(n,x)
- throw(std::logic_error("cannot diff psi(n,x) with respect to n"));
- }
- // d/dx psi(n,x) -> psi(n+1,x)
- return psi(n+_ex1(), x);
+ GINAC_ASSERT(deriv_param<2);
+
+ if (deriv_param==0) {
+ // d/dn psi(n,x)
+ throw(std::logic_error("cannot diff psi(n,x) with respect to n"));
+ }
+ // d/dx psi(n,x) -> psi(n+1,x)
+ return psi(n+_ex1(), x);
}
static ex psi2_series(const ex & n,
- const ex & arg,
- const relational & rel,
- int order,
- unsigned options)
+ const ex & arg,
+ const relational & rel,
+ int order,
+ unsigned options)
{
- // method:
- // Taylor series where there is no pole falls back to polygamma function
- // evaluation.
- // On a pole at -m use the recurrence relation
- // psi(n,x) == psi(n,x+1) - (-)^n * n! / x^(n+1)
- // from which follows
- // series(psi(x),x==-m,order) ==
- // series(psi(x+m+1) - (-1)^n * n! * ((x)^(-n-1) + (x+1)^(-n-1) + ...
- // ... + (x+m)^(-n-1))),x==-m,order);
- const ex arg_pt = arg.subs(rel);
- if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive))
- throw do_taylor(); // caught by function::series()
- // if we got here we have to care for a pole of order n+1 at -m:
- numeric m = -ex_to_numeric(arg_pt);
- ex recur;
- for (numeric p; p<=m; ++p)
- recur += power(arg+p,-n+_ex_1());
- recur *= factorial(n)*power(_ex_1(),n);
- return (psi(n, arg+m+_ex1())-recur).series(rel, order, options);
+ // method:
+ // Taylor series where there is no pole falls back to polygamma function
+ // evaluation.
+ // On a pole at -m use the recurrence relation
+ // psi(n,x) == psi(n,x+1) - (-)^n * n! / x^(n+1)
+ // from which follows
+ // series(psi(x),x==-m,order) ==
+ // series(psi(x+m+1) - (-1)^n * n! * ((x)^(-n-1) + (x+1)^(-n-1) + ...
+ // ... + (x+m)^(-n-1))),x==-m,order);
+ const ex arg_pt = arg.subs(rel);
+ if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive))
+ throw do_taylor(); // caught by function::series()
+ // if we got here we have to care for a pole of order n+1 at -m:
+ numeric m = -ex_to_numeric(arg_pt);
+ ex recur;
+ for (numeric p; p<=m; ++p)
+ recur += power(arg+p,-n+_ex_1());
+ recur *= factorial(n)*power(_ex_1(),n);
+ return (psi(n, arg+m+_ex1())-recur).series(rel, order, options);
}
const unsigned function_index_psi2 =
- function::register_new(function_options("psi").
- eval_func(psi2_eval).
- evalf_func(psi2_evalf).
- derivative_func(psi2_deriv).
+ function::register_new(function_options("psi").
+ eval_func(psi2_eval).
+ evalf_func(psi2_evalf).
+ derivative_func(psi2_deriv).
series_func(psi2_series).
overloaded(2));
static ex exp_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(exp(x))
-
- return exp(ex_to_numeric(x)); // -> numeric exp(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(exp(x))
+
+ return exp(ex_to_numeric(x)); // -> numeric exp(numeric)
}
static ex exp_eval(const ex & x)
{
- // exp(0) -> 1
- if (x.is_zero()) {
- return _ex1();
- }
- // exp(n*Pi*I/2) -> {+1|+I|-1|-I}
- ex TwoExOverPiI=(_ex2()*x)/(Pi*I);
- if (TwoExOverPiI.info(info_flags::integer)) {
- numeric z=mod(ex_to_numeric(TwoExOverPiI),_num4());
- if (z.is_equal(_num0()))
- return _ex1();
- if (z.is_equal(_num1()))
- return ex(I);
- if (z.is_equal(_num2()))
- return _ex_1();
- if (z.is_equal(_num3()))
- return ex(-I);
- }
- // exp(log(x)) -> x
- if (is_ex_the_function(x, log))
- return x.op(0);
-
- // exp(float)
- if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
- return exp_evalf(x);
-
- return exp(x).hold();
+ // exp(0) -> 1
+ if (x.is_zero()) {
+ return _ex1();
+ }
+ // exp(n*Pi*I/2) -> {+1|+I|-1|-I}
+ ex TwoExOverPiI=(_ex2()*x)/(Pi*I);
+ if (TwoExOverPiI.info(info_flags::integer)) {
+ numeric z=mod(ex_to_numeric(TwoExOverPiI),_num4());
+ if (z.is_equal(_num0()))
+ return _ex1();
+ if (z.is_equal(_num1()))
+ return ex(I);
+ if (z.is_equal(_num2()))
+ return _ex_1();
+ if (z.is_equal(_num3()))
+ return ex(-I);
+ }
+ // exp(log(x)) -> x
+ if (is_ex_the_function(x, log))
+ return x.op(0);
+
+ // exp(float)
+ if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
+ return exp_evalf(x);
+
+ return exp(x).hold();
}
static ex exp_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
+ GINAC_ASSERT(deriv_param==0);
- // d/dx exp(x) -> exp(x)
- return exp(x);
+ // d/dx exp(x) -> exp(x)
+ return exp(x);
}
REGISTER_FUNCTION(exp, eval_func(exp_eval).
- evalf_func(exp_evalf).
- derivative_func(exp_deriv));
+ evalf_func(exp_evalf).
+ derivative_func(exp_deriv));
//////////
// natural logarithm
static ex log_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(log(x))
-
- return log(ex_to_numeric(x)); // -> numeric log(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(log(x))
+
+ return log(ex_to_numeric(x)); // -> numeric log(numeric)
}
static ex log_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- if (x.is_equal(_ex0())) // log(0) -> infinity
- throw(pole_error("log_eval(): log(0)",0));
- if (x.info(info_flags::real) && x.info(info_flags::negative))
- return (log(-x)+I*Pi);
- if (x.is_equal(_ex1())) // log(1) -> 0
- return _ex0();
- if (x.is_equal(I)) // log(I) -> Pi*I/2
- return (Pi*I*_num1_2());
- if (x.is_equal(-I)) // log(-I) -> -Pi*I/2
- return (Pi*I*_num_1_2());
- // log(float)
- if (!x.info(info_flags::crational))
- return log_evalf(x);
- }
- // log(exp(t)) -> t (if -Pi < t.imag() <= Pi):
- if (is_ex_the_function(x, exp)) {
- ex t = x.op(0);
- if (t.info(info_flags::numeric)) {
- numeric nt = ex_to_numeric(t);
- if (nt.is_real())
- return t;
- }
- }
-
- return log(x).hold();
+ if (x.info(info_flags::numeric)) {
+ if (x.is_equal(_ex0())) // log(0) -> infinity
+ throw(pole_error("log_eval(): log(0)",0));
+ if (x.info(info_flags::real) && x.info(info_flags::negative))
+ return (log(-x)+I*Pi);
+ if (x.is_equal(_ex1())) // log(1) -> 0
+ return _ex0();
+ if (x.is_equal(I)) // log(I) -> Pi*I/2
+ return (Pi*I*_num1_2());
+ if (x.is_equal(-I)) // log(-I) -> -Pi*I/2
+ return (Pi*I*_num_1_2());
+ // log(float)
+ if (!x.info(info_flags::crational))
+ return log_evalf(x);
+ }
+ // log(exp(t)) -> t (if -Pi < t.imag() <= Pi):
+ if (is_ex_the_function(x, exp)) {
+ ex t = x.op(0);
+ if (t.info(info_flags::numeric)) {
+ numeric nt = ex_to_numeric(t);
+ if (nt.is_real())
+ return t;
+ }
+ }
+
+ return log(x).hold();
}
static ex log_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx log(x) -> 1/x
- return power(x, _ex_1());
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx log(x) -> 1/x
+ return power(x, _ex_1());
}
static ex log_series(const ex &arg,
- const relational &rel,
- int order,
- unsigned options)
-{
- GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
- ex arg_pt;
- bool must_expand_arg = false;
- // maybe substitution of rel into arg fails because of a pole
- try {
- arg_pt = arg.subs(rel);
- } catch (pole_error) {
- must_expand_arg = true;
- }
- // or we are at the branch cut anyways
- if (arg_pt.is_zero())
- must_expand_arg = true;
-
- if (must_expand_arg) {
- // method:
- // This is the branch point: Series expand the argument first, then
- // trivially factorize it to isolate that part which has constant
- // leading coefficient in this fashion:
- // x^n + Order(x^(n+m)) -> x^n * (1 + Order(x^m)).
- // Return a plain n*log(x) for the x^n part and series expand the
- // other part. Add them together and reexpand again in order to have
- // one unnested pseries object. All this also works for negative n.
- const pseries argser = ex_to_pseries(arg.series(rel, order, options));
- const symbol *s = static_cast<symbol *>(rel.lhs().bp);
- const ex point = rel.rhs();
- const int n = argser.ldegree(*s);
- epvector seq;
- seq.push_back(expair(n*log(*s-point), _ex0()));
- if (!argser.is_terminating() || argser.nops()!=1) {
- // in this case n more terms are needed
- ex newarg = ex_to_pseries(arg.series(rel, order+n, options)).shift_exponents(-n).convert_to_poly(true);
- return pseries(rel, seq).add_series(ex_to_pseries(log(newarg).series(rel, order, options)));
- } else // it was a monomial
- return pseries(rel, seq);
- }
- if (!(options & series_options::suppress_branchcut) &&
- arg_pt.info(info_flags::negative)) {
- // method:
- // This is the branch cut: assemble the primitive series manually and
- // then add the corresponding complex step function.
- const symbol *s = static_cast<symbol *>(rel.lhs().bp);
- const ex point = rel.rhs();
- const symbol foo;
- ex replarg = series(log(arg), *s==foo, order, false).subs(foo==point);
- epvector seq;
- seq.push_back(expair(-I*csgn(arg*I)*Pi, _ex0()));
- seq.push_back(expair(Order(_ex1()), order));
- return series(replarg - I*Pi + pseries(rel, seq), rel, order);
- }
- throw do_taylor(); // caught by function::series()
+ const relational &rel,
+ int order,
+ unsigned options)
+{
+ GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
+ ex arg_pt;
+ bool must_expand_arg = false;
+ // maybe substitution of rel into arg fails because of a pole
+ try {
+ arg_pt = arg.subs(rel);
+ } catch (pole_error) {
+ must_expand_arg = true;
+ }
+ // or we are at the branch cut anyways
+ if (arg_pt.is_zero())
+ must_expand_arg = true;
+
+ if (must_expand_arg) {
+ // method:
+ // This is the branch point: Series expand the argument first, then
+ // trivially factorize it to isolate that part which has constant
+ // leading coefficient in this fashion:
+ // x^n + Order(x^(n+m)) -> x^n * (1 + Order(x^m)).
+ // Return a plain n*log(x) for the x^n part and series expand the
+ // other part. Add them together and reexpand again in order to have
+ // one unnested pseries object. All this also works for negative n.
+ const pseries argser = ex_to_pseries(arg.series(rel, order, options));
+ const symbol *s = static_cast<symbol *>(rel.lhs().bp);
+ const ex point = rel.rhs();
+ const int n = argser.ldegree(*s);
+ epvector seq;
+ seq.push_back(expair(n*log(*s-point), _ex0()));
+ if (!argser.is_terminating() || argser.nops()!=1) {
+ // in this case n more terms are needed
+ ex newarg = ex_to_pseries(arg.series(rel, order+n, options)).shift_exponents(-n).convert_to_poly(true);
+ return pseries(rel, seq).add_series(ex_to_pseries(log(newarg).series(rel, order, options)));
+ } else // it was a monomial
+ return pseries(rel, seq);
+ }
+ if (!(options & series_options::suppress_branchcut) &&
+ arg_pt.info(info_flags::negative)) {
+ // method:
+ // This is the branch cut: assemble the primitive series manually and
+ // then add the corresponding complex step function.
+ const symbol *s = static_cast<symbol *>(rel.lhs().bp);
+ const ex point = rel.rhs();
+ const symbol foo;
+ ex replarg = series(log(arg), *s==foo, order, false).subs(foo==point);
+ epvector seq;
+ seq.push_back(expair(-I*csgn(arg*I)*Pi, _ex0()));
+ seq.push_back(expair(Order(_ex1()), order));
+ return series(replarg - I*Pi + pseries(rel, seq), rel, order);
+ }
+ throw do_taylor(); // caught by function::series()
}
REGISTER_FUNCTION(log, eval_func(log_eval).
- evalf_func(log_evalf).
- derivative_func(log_deriv).
- series_func(log_series));
+ evalf_func(log_evalf).
+ derivative_func(log_deriv).
+ series_func(log_series));
//////////
// sine (trigonometric function)
static ex sin_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(sin(x))
-
- return sin(ex_to_numeric(x)); // -> numeric sin(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(sin(x))
+
+ return sin(ex_to_numeric(x)); // -> numeric sin(numeric)
}
static ex sin_eval(const ex & x)
{
- // sin(n/d*Pi) -> { all known non-nested radicals }
- ex SixtyExOverPi = _ex60()*x/Pi;
- ex sign = _ex1();
- if (SixtyExOverPi.info(info_flags::integer)) {
- numeric z = mod(ex_to_numeric(SixtyExOverPi),_num120());
- if (z>=_num60()) {
- // wrap to interval [0, Pi)
- z -= _num60();
- sign = _ex_1();
- }
- if (z>_num30()) {
- // wrap to interval [0, Pi/2)
- z = _num60()-z;
- }
- if (z.is_equal(_num0())) // sin(0) -> 0
- return _ex0();
- if (z.is_equal(_num5())) // sin(Pi/12) -> sqrt(6)/4*(1-sqrt(3)/3)
- return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex_1_3()*power(_ex3(),_ex1_2()));
- if (z.is_equal(_num6())) // sin(Pi/10) -> sqrt(5)/4-1/4
- return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex_1_4());
- if (z.is_equal(_num10())) // sin(Pi/6) -> 1/2
- return sign*_ex1_2();
- if (z.is_equal(_num15())) // sin(Pi/4) -> sqrt(2)/2
- return sign*_ex1_2()*power(_ex2(),_ex1_2());
- if (z.is_equal(_num18())) // sin(3/10*Pi) -> sqrt(5)/4+1/4
- return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex1_4());
- if (z.is_equal(_num20())) // sin(Pi/3) -> sqrt(3)/2
- return sign*_ex1_2()*power(_ex3(),_ex1_2());
- if (z.is_equal(_num25())) // sin(5/12*Pi) -> sqrt(6)/4*(1+sqrt(3)/3)
- return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex1_3()*power(_ex3(),_ex1_2()));
- if (z.is_equal(_num30())) // sin(Pi/2) -> 1
- return sign*_ex1();
- }
-
- if (is_ex_exactly_of_type(x, function)) {
- ex t = x.op(0);
- // sin(asin(x)) -> x
- if (is_ex_the_function(x, asin))
- return t;
- // sin(acos(x)) -> sqrt(1-x^2)
- if (is_ex_the_function(x, acos))
- return power(_ex1()-power(t,_ex2()),_ex1_2());
- // sin(atan(x)) -> x*(1+x^2)^(-1/2)
- if (is_ex_the_function(x, atan))
- return t*power(_ex1()+power(t,_ex2()),_ex_1_2());
- }
-
- // sin(float) -> float
- if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
- return sin_evalf(x);
-
- return sin(x).hold();
+ // sin(n/d*Pi) -> { all known non-nested radicals }
+ ex SixtyExOverPi = _ex60()*x/Pi;
+ ex sign = _ex1();
+ if (SixtyExOverPi.info(info_flags::integer)) {
+ numeric z = mod(ex_to_numeric(SixtyExOverPi),_num120());
+ if (z>=_num60()) {
+ // wrap to interval [0, Pi)
+ z -= _num60();
+ sign = _ex_1();
+ }
+ if (z>_num30()) {
+ // wrap to interval [0, Pi/2)
+ z = _num60()-z;
+ }
+ if (z.is_equal(_num0())) // sin(0) -> 0
+ return _ex0();
+ if (z.is_equal(_num5())) // sin(Pi/12) -> sqrt(6)/4*(1-sqrt(3)/3)
+ return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex_1_3()*power(_ex3(),_ex1_2()));
+ if (z.is_equal(_num6())) // sin(Pi/10) -> sqrt(5)/4-1/4
+ return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex_1_4());
+ if (z.is_equal(_num10())) // sin(Pi/6) -> 1/2
+ return sign*_ex1_2();
+ if (z.is_equal(_num15())) // sin(Pi/4) -> sqrt(2)/2
+ return sign*_ex1_2()*power(_ex2(),_ex1_2());
+ if (z.is_equal(_num18())) // sin(3/10*Pi) -> sqrt(5)/4+1/4
+ return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex1_4());
+ if (z.is_equal(_num20())) // sin(Pi/3) -> sqrt(3)/2
+ return sign*_ex1_2()*power(_ex3(),_ex1_2());
+ if (z.is_equal(_num25())) // sin(5/12*Pi) -> sqrt(6)/4*(1+sqrt(3)/3)
+ return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex1_3()*power(_ex3(),_ex1_2()));
+ if (z.is_equal(_num30())) // sin(Pi/2) -> 1
+ return sign*_ex1();
+ }
+
+ if (is_ex_exactly_of_type(x, function)) {
+ ex t = x.op(0);
+ // sin(asin(x)) -> x
+ if (is_ex_the_function(x, asin))
+ return t;
+ // sin(acos(x)) -> sqrt(1-x^2)
+ if (is_ex_the_function(x, acos))
+ return power(_ex1()-power(t,_ex2()),_ex1_2());
+ // sin(atan(x)) -> x*(1+x^2)^(-1/2)
+ if (is_ex_the_function(x, atan))
+ return t*power(_ex1()+power(t,_ex2()),_ex_1_2());
+ }
+
+ // sin(float) -> float
+ if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
+ return sin_evalf(x);
+
+ return sin(x).hold();
}
static ex sin_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx sin(x) -> cos(x)
- return cos(x);
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx sin(x) -> cos(x)
+ return cos(x);
}
REGISTER_FUNCTION(sin, eval_func(sin_eval).
- evalf_func(sin_evalf).
- derivative_func(sin_deriv));
+ evalf_func(sin_evalf).
+ derivative_func(sin_deriv));
//////////
// cosine (trigonometric function)
static ex cos_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(cos(x))
-
- return cos(ex_to_numeric(x)); // -> numeric cos(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(cos(x))
+
+ return cos(ex_to_numeric(x)); // -> numeric cos(numeric)
}
static ex cos_eval(const ex & x)
{
- // cos(n/d*Pi) -> { all known non-nested radicals }
- ex SixtyExOverPi = _ex60()*x/Pi;
- ex sign = _ex1();
- if (SixtyExOverPi.info(info_flags::integer)) {
- numeric z = mod(ex_to_numeric(SixtyExOverPi),_num120());
- if (z>=_num60()) {
- // wrap to interval [0, Pi)
- z = _num120()-z;
- }
- if (z>=_num30()) {
- // wrap to interval [0, Pi/2)
- z = _num60()-z;
- sign = _ex_1();
- }
- if (z.is_equal(_num0())) // cos(0) -> 1
- return sign*_ex1();
- if (z.is_equal(_num5())) // cos(Pi/12) -> sqrt(6)/4*(1+sqrt(3)/3)
- return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex1_3()*power(_ex3(),_ex1_2()));
- if (z.is_equal(_num10())) // cos(Pi/6) -> sqrt(3)/2
- return sign*_ex1_2()*power(_ex3(),_ex1_2());
- if (z.is_equal(_num12())) // cos(Pi/5) -> sqrt(5)/4+1/4
- return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex1_4());
- if (z.is_equal(_num15())) // cos(Pi/4) -> sqrt(2)/2
- return sign*_ex1_2()*power(_ex2(),_ex1_2());
- if (z.is_equal(_num20())) // cos(Pi/3) -> 1/2
- return sign*_ex1_2();
- if (z.is_equal(_num24())) // cos(2/5*Pi) -> sqrt(5)/4-1/4x
- return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex_1_4());
- if (z.is_equal(_num25())) // cos(5/12*Pi) -> sqrt(6)/4*(1-sqrt(3)/3)
- return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex_1_3()*power(_ex3(),_ex1_2()));
- if (z.is_equal(_num30())) // cos(Pi/2) -> 0
- return sign*_ex0();
- }
-
- if (is_ex_exactly_of_type(x, function)) {
- ex t = x.op(0);
- // cos(acos(x)) -> x
- if (is_ex_the_function(x, acos))
- return t;
- // cos(asin(x)) -> (1-x^2)^(1/2)
- if (is_ex_the_function(x, asin))
- return power(_ex1()-power(t,_ex2()),_ex1_2());
- // cos(atan(x)) -> (1+x^2)^(-1/2)
- if (is_ex_the_function(x, atan))
- return power(_ex1()+power(t,_ex2()),_ex_1_2());
- }
-
- // cos(float) -> float
- if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
- return cos_evalf(x);
-
- return cos(x).hold();
+ // cos(n/d*Pi) -> { all known non-nested radicals }
+ ex SixtyExOverPi = _ex60()*x/Pi;
+ ex sign = _ex1();
+ if (SixtyExOverPi.info(info_flags::integer)) {
+ numeric z = mod(ex_to_numeric(SixtyExOverPi),_num120());
+ if (z>=_num60()) {
+ // wrap to interval [0, Pi)
+ z = _num120()-z;
+ }
+ if (z>=_num30()) {
+ // wrap to interval [0, Pi/2)
+ z = _num60()-z;
+ sign = _ex_1();
+ }
+ if (z.is_equal(_num0())) // cos(0) -> 1
+ return sign*_ex1();
+ if (z.is_equal(_num5())) // cos(Pi/12) -> sqrt(6)/4*(1+sqrt(3)/3)
+ return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex1_3()*power(_ex3(),_ex1_2()));
+ if (z.is_equal(_num10())) // cos(Pi/6) -> sqrt(3)/2
+ return sign*_ex1_2()*power(_ex3(),_ex1_2());
+ if (z.is_equal(_num12())) // cos(Pi/5) -> sqrt(5)/4+1/4
+ return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex1_4());
+ if (z.is_equal(_num15())) // cos(Pi/4) -> sqrt(2)/2
+ return sign*_ex1_2()*power(_ex2(),_ex1_2());
+ if (z.is_equal(_num20())) // cos(Pi/3) -> 1/2
+ return sign*_ex1_2();
+ if (z.is_equal(_num24())) // cos(2/5*Pi) -> sqrt(5)/4-1/4x
+ return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex_1_4());
+ if (z.is_equal(_num25())) // cos(5/12*Pi) -> sqrt(6)/4*(1-sqrt(3)/3)
+ return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex_1_3()*power(_ex3(),_ex1_2()));
+ if (z.is_equal(_num30())) // cos(Pi/2) -> 0
+ return sign*_ex0();
+ }
+
+ if (is_ex_exactly_of_type(x, function)) {
+ ex t = x.op(0);
+ // cos(acos(x)) -> x
+ if (is_ex_the_function(x, acos))
+ return t;
+ // cos(asin(x)) -> (1-x^2)^(1/2)
+ if (is_ex_the_function(x, asin))
+ return power(_ex1()-power(t,_ex2()),_ex1_2());
+ // cos(atan(x)) -> (1+x^2)^(-1/2)
+ if (is_ex_the_function(x, atan))
+ return power(_ex1()+power(t,_ex2()),_ex_1_2());
+ }
+
+ // cos(float) -> float
+ if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
+ return cos_evalf(x);
+
+ return cos(x).hold();
}
static ex cos_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
+ GINAC_ASSERT(deriv_param==0);
- // d/dx cos(x) -> -sin(x)
- return _ex_1()*sin(x);
+ // d/dx cos(x) -> -sin(x)
+ return _ex_1()*sin(x);
}
REGISTER_FUNCTION(cos, eval_func(cos_eval).
- evalf_func(cos_evalf).
- derivative_func(cos_deriv));
+ evalf_func(cos_evalf).
+ derivative_func(cos_deriv));
//////////
// tangent (trigonometric function)
static ex tan_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
-
- return tan(ex_to_numeric(x));
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
+
+ return tan(ex_to_numeric(x));
}
static ex tan_eval(const ex & x)
{
- // tan(n/d*Pi) -> { all known non-nested radicals }
- ex SixtyExOverPi = _ex60()*x/Pi;
- ex sign = _ex1();
- if (SixtyExOverPi.info(info_flags::integer)) {
- numeric z = mod(ex_to_numeric(SixtyExOverPi),_num60());
- if (z>=_num60()) {
- // wrap to interval [0, Pi)
- z -= _num60();
- }
- if (z>=_num30()) {
- // wrap to interval [0, Pi/2)
- z = _num60()-z;
- sign = _ex_1();
- }
- if (z.is_equal(_num0())) // tan(0) -> 0
- return _ex0();
- if (z.is_equal(_num5())) // tan(Pi/12) -> 2-sqrt(3)
- return sign*(_ex2()-power(_ex3(),_ex1_2()));
- if (z.is_equal(_num10())) // tan(Pi/6) -> sqrt(3)/3
- return sign*_ex1_3()*power(_ex3(),_ex1_2());
- if (z.is_equal(_num15())) // tan(Pi/4) -> 1
- return sign*_ex1();
- if (z.is_equal(_num20())) // tan(Pi/3) -> sqrt(3)
- return sign*power(_ex3(),_ex1_2());
- if (z.is_equal(_num25())) // tan(5/12*Pi) -> 2+sqrt(3)
- return sign*(power(_ex3(),_ex1_2())+_ex2());
- if (z.is_equal(_num30())) // tan(Pi/2) -> infinity
- throw (pole_error("tan_eval(): simple pole",1));
- }
-
- if (is_ex_exactly_of_type(x, function)) {
- ex t = x.op(0);
- // tan(atan(x)) -> x
- if (is_ex_the_function(x, atan))
- return t;
- // tan(asin(x)) -> x*(1+x^2)^(-1/2)
- if (is_ex_the_function(x, asin))
- return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
- // tan(acos(x)) -> (1-x^2)^(1/2)/x
- if (is_ex_the_function(x, acos))
- return power(t,_ex_1())*power(_ex1()-power(t,_ex2()),_ex1_2());
- }
-
- // tan(float) -> float
- if (x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
- return tan_evalf(x);
- }
-
- return tan(x).hold();
+ // tan(n/d*Pi) -> { all known non-nested radicals }
+ ex SixtyExOverPi = _ex60()*x/Pi;
+ ex sign = _ex1();
+ if (SixtyExOverPi.info(info_flags::integer)) {
+ numeric z = mod(ex_to_numeric(SixtyExOverPi),_num60());
+ if (z>=_num60()) {
+ // wrap to interval [0, Pi)
+ z -= _num60();
+ }
+ if (z>=_num30()) {
+ // wrap to interval [0, Pi/2)
+ z = _num60()-z;
+ sign = _ex_1();
+ }
+ if (z.is_equal(_num0())) // tan(0) -> 0
+ return _ex0();
+ if (z.is_equal(_num5())) // tan(Pi/12) -> 2-sqrt(3)
+ return sign*(_ex2()-power(_ex3(),_ex1_2()));
+ if (z.is_equal(_num10())) // tan(Pi/6) -> sqrt(3)/3
+ return sign*_ex1_3()*power(_ex3(),_ex1_2());
+ if (z.is_equal(_num15())) // tan(Pi/4) -> 1
+ return sign*_ex1();
+ if (z.is_equal(_num20())) // tan(Pi/3) -> sqrt(3)
+ return sign*power(_ex3(),_ex1_2());
+ if (z.is_equal(_num25())) // tan(5/12*Pi) -> 2+sqrt(3)
+ return sign*(power(_ex3(),_ex1_2())+_ex2());
+ if (z.is_equal(_num30())) // tan(Pi/2) -> infinity
+ throw (pole_error("tan_eval(): simple pole",1));
+ }
+
+ if (is_ex_exactly_of_type(x, function)) {
+ ex t = x.op(0);
+ // tan(atan(x)) -> x
+ if (is_ex_the_function(x, atan))
+ return t;
+ // tan(asin(x)) -> x*(1+x^2)^(-1/2)
+ if (is_ex_the_function(x, asin))
+ return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
+ // tan(acos(x)) -> (1-x^2)^(1/2)/x
+ if (is_ex_the_function(x, acos))
+ return power(t,_ex_1())*power(_ex1()-power(t,_ex2()),_ex1_2());
+ }
+
+ // tan(float) -> float
+ if (x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
+ return tan_evalf(x);
+ }
+
+ return tan(x).hold();
}
static ex tan_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx tan(x) -> 1+tan(x)^2;
- return (_ex1()+power(tan(x),_ex2()));
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx tan(x) -> 1+tan(x)^2;
+ return (_ex1()+power(tan(x),_ex2()));
}
static ex tan_series(const ex &x,
- const relational &rel,
- int order,
- unsigned options)
+ const relational &rel,
+ int order,
+ unsigned options)
{
- // method:
- // Taylor series where there is no pole falls back to tan_deriv.
- // On a pole simply expand sin(x)/cos(x).
- const ex x_pt = x.subs(rel);
- if (!(2*x_pt/Pi).info(info_flags::odd))
- throw do_taylor(); // caught by function::series()
- // if we got here we have to care for a simple pole
- return (sin(x)/cos(x)).series(rel, order+2);
+ // method:
+ // Taylor series where there is no pole falls back to tan_deriv.
+ // On a pole simply expand sin(x)/cos(x).
+ const ex x_pt = x.subs(rel);
+ if (!(2*x_pt/Pi).info(info_flags::odd))
+ throw do_taylor(); // caught by function::series()
+ // if we got here we have to care for a simple pole
+ return (sin(x)/cos(x)).series(rel, order+2);
}
REGISTER_FUNCTION(tan, eval_func(tan_eval).
- evalf_func(tan_evalf).
- derivative_func(tan_deriv).
- series_func(tan_series));
+ evalf_func(tan_evalf).
+ derivative_func(tan_deriv).
+ series_func(tan_series));
//////////
// inverse sine (arc sine)
static ex asin_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(asin(x))
-
- return asin(ex_to_numeric(x)); // -> numeric asin(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(asin(x))
+
+ return asin(ex_to_numeric(x)); // -> numeric asin(numeric)
}
static ex asin_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // asin(0) -> 0
- if (x.is_zero())
- return x;
- // asin(1/2) -> Pi/6
- if (x.is_equal(_ex1_2()))
- return numeric(1,6)*Pi;
- // asin(1) -> Pi/2
- if (x.is_equal(_ex1()))
- return _num1_2()*Pi;
- // asin(-1/2) -> -Pi/6
- if (x.is_equal(_ex_1_2()))
- return numeric(-1,6)*Pi;
- // asin(-1) -> -Pi/2
- if (x.is_equal(_ex_1()))
- return _num_1_2()*Pi;
- // asin(float) -> float
- if (!x.info(info_flags::crational))
- return asin_evalf(x);
- }
-
- return asin(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // asin(0) -> 0
+ if (x.is_zero())
+ return x;
+ // asin(1/2) -> Pi/6
+ if (x.is_equal(_ex1_2()))
+ return numeric(1,6)*Pi;
+ // asin(1) -> Pi/2
+ if (x.is_equal(_ex1()))
+ return _num1_2()*Pi;
+ // asin(-1/2) -> -Pi/6
+ if (x.is_equal(_ex_1_2()))
+ return numeric(-1,6)*Pi;
+ // asin(-1) -> -Pi/2
+ if (x.is_equal(_ex_1()))
+ return _num_1_2()*Pi;
+ // asin(float) -> float
+ if (!x.info(info_flags::crational))
+ return asin_evalf(x);
+ }
+
+ return asin(x).hold();
}
static ex asin_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx asin(x) -> 1/sqrt(1-x^2)
- return power(1-power(x,_ex2()),_ex_1_2());
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx asin(x) -> 1/sqrt(1-x^2)
+ return power(1-power(x,_ex2()),_ex_1_2());
}
REGISTER_FUNCTION(asin, eval_func(asin_eval).
- evalf_func(asin_evalf).
- derivative_func(asin_deriv));
+ evalf_func(asin_evalf).
+ derivative_func(asin_deriv));
//////////
// inverse cosine (arc cosine)
static ex acos_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(acos(x))
-
- return acos(ex_to_numeric(x)); // -> numeric acos(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(acos(x))
+
+ return acos(ex_to_numeric(x)); // -> numeric acos(numeric)
}
static ex acos_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // acos(1) -> 0
- if (x.is_equal(_ex1()))
- return _ex0();
- // acos(1/2) -> Pi/3
- if (x.is_equal(_ex1_2()))
- return _ex1_3()*Pi;
- // acos(0) -> Pi/2
- if (x.is_zero())
- return _ex1_2()*Pi;
- // acos(-1/2) -> 2/3*Pi
- if (x.is_equal(_ex_1_2()))
- return numeric(2,3)*Pi;
- // acos(-1) -> Pi
- if (x.is_equal(_ex_1()))
- return Pi;
- // acos(float) -> float
- if (!x.info(info_flags::crational))
- return acos_evalf(x);
- }
-
- return acos(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // acos(1) -> 0
+ if (x.is_equal(_ex1()))
+ return _ex0();
+ // acos(1/2) -> Pi/3
+ if (x.is_equal(_ex1_2()))
+ return _ex1_3()*Pi;
+ // acos(0) -> Pi/2
+ if (x.is_zero())
+ return _ex1_2()*Pi;
+ // acos(-1/2) -> 2/3*Pi
+ if (x.is_equal(_ex_1_2()))
+ return numeric(2,3)*Pi;
+ // acos(-1) -> Pi
+ if (x.is_equal(_ex_1()))
+ return Pi;
+ // acos(float) -> float
+ if (!x.info(info_flags::crational))
+ return acos_evalf(x);
+ }
+
+ return acos(x).hold();
}
static ex acos_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx acos(x) -> -1/sqrt(1-x^2)
- return _ex_1()*power(1-power(x,_ex2()),_ex_1_2());
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx acos(x) -> -1/sqrt(1-x^2)
+ return _ex_1()*power(1-power(x,_ex2()),_ex_1_2());
}
REGISTER_FUNCTION(acos, eval_func(acos_eval).
- evalf_func(acos_evalf).
- derivative_func(acos_deriv));
+ evalf_func(acos_evalf).
+ derivative_func(acos_deriv));
//////////
// inverse tangent (arc tangent)
static ex atan_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(atan(x))
-
- return atan(ex_to_numeric(x)); // -> numeric atan(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(atan(x))
+
+ return atan(ex_to_numeric(x)); // -> numeric atan(numeric)
}
static ex atan_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // atan(0) -> 0
- if (x.is_equal(_ex0()))
- return _ex0();
- // atan(float) -> float
- if (!x.info(info_flags::crational))
- return atan_evalf(x);
- }
-
- return atan(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // atan(0) -> 0
+ if (x.is_equal(_ex0()))
+ return _ex0();
+ // atan(float) -> float
+ if (!x.info(info_flags::crational))
+ return atan_evalf(x);
+ }
+
+ return atan(x).hold();
}
static ex atan_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
+ GINAC_ASSERT(deriv_param==0);
- // d/dx atan(x) -> 1/(1+x^2)
- return power(_ex1()+power(x,_ex2()), _ex_1());
+ // d/dx atan(x) -> 1/(1+x^2)
+ return power(_ex1()+power(x,_ex2()), _ex_1());
}
REGISTER_FUNCTION(atan, eval_func(atan_eval).
- evalf_func(atan_evalf).
- derivative_func(atan_deriv));
+ evalf_func(atan_evalf).
+ derivative_func(atan_deriv));
//////////
// inverse tangent (atan2(y,x))
static ex atan2_evalf(const ex & y, const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(y,numeric)
- TYPECHECK(x,numeric)
- END_TYPECHECK(atan2(y,x))
-
- return atan(ex_to_numeric(y),ex_to_numeric(x)); // -> numeric atan(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(y,numeric)
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(atan2(y,x))
+
+ return atan(ex_to_numeric(y),ex_to_numeric(x)); // -> numeric atan(numeric)
}
static ex atan2_eval(const ex & y, const ex & x)
{
- if (y.info(info_flags::numeric) && !y.info(info_flags::crational) &&
- x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
- return atan2_evalf(y,x);
- }
-
- return atan2(y,x).hold();
+ if (y.info(info_flags::numeric) && !y.info(info_flags::crational) &&
+ x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
+ return atan2_evalf(y,x);
+ }
+
+ return atan2(y,x).hold();
}
static ex atan2_deriv(const ex & y, const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param<2);
-
- if (deriv_param==0) {
- // d/dy atan(y,x)
- return x*power(power(x,_ex2())+power(y,_ex2()),_ex_1());
- }
- // d/dx atan(y,x)
- return -y*power(power(x,_ex2())+power(y,_ex2()),_ex_1());
+ GINAC_ASSERT(deriv_param<2);
+
+ if (deriv_param==0) {
+ // d/dy atan(y,x)
+ return x*power(power(x,_ex2())+power(y,_ex2()),_ex_1());
+ }
+ // d/dx atan(y,x)
+ return -y*power(power(x,_ex2())+power(y,_ex2()),_ex_1());
}
REGISTER_FUNCTION(atan2, eval_func(atan2_eval).
- evalf_func(atan2_evalf).
- derivative_func(atan2_deriv));
+ evalf_func(atan2_evalf).
+ derivative_func(atan2_deriv));
//////////
// hyperbolic sine (trigonometric function)
static ex sinh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(sinh(x))
-
- return sinh(ex_to_numeric(x)); // -> numeric sinh(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(sinh(x))
+
+ return sinh(ex_to_numeric(x)); // -> numeric sinh(numeric)
}
static ex sinh_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- if (x.is_zero()) // sinh(0) -> 0
- return _ex0();
- if (!x.info(info_flags::crational)) // sinh(float) -> float
- return sinh_evalf(x);
- }
-
- if ((x/Pi).info(info_flags::numeric) &&
- ex_to_numeric(x/Pi).real().is_zero()) // sinh(I*x) -> I*sin(x)
- return I*sin(x/I);
-
- if (is_ex_exactly_of_type(x, function)) {
- ex t = x.op(0);
- // sinh(asinh(x)) -> x
- if (is_ex_the_function(x, asinh))
- return t;
- // sinh(acosh(x)) -> (x-1)^(1/2) * (x+1)^(1/2)
- if (is_ex_the_function(x, acosh))
- return power(t-_ex1(),_ex1_2())*power(t+_ex1(),_ex1_2());
- // sinh(atanh(x)) -> x*(1-x^2)^(-1/2)
- if (is_ex_the_function(x, atanh))
- return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
- }
-
- return sinh(x).hold();
+ if (x.info(info_flags::numeric)) {
+ if (x.is_zero()) // sinh(0) -> 0
+ return _ex0();
+ if (!x.info(info_flags::crational)) // sinh(float) -> float
+ return sinh_evalf(x);
+ }
+
+ if ((x/Pi).info(info_flags::numeric) &&
+ ex_to_numeric(x/Pi).real().is_zero()) // sinh(I*x) -> I*sin(x)
+ return I*sin(x/I);
+
+ if (is_ex_exactly_of_type(x, function)) {
+ ex t = x.op(0);
+ // sinh(asinh(x)) -> x
+ if (is_ex_the_function(x, asinh))
+ return t;
+ // sinh(acosh(x)) -> (x-1)^(1/2) * (x+1)^(1/2)
+ if (is_ex_the_function(x, acosh))
+ return power(t-_ex1(),_ex1_2())*power(t+_ex1(),_ex1_2());
+ // sinh(atanh(x)) -> x*(1-x^2)^(-1/2)
+ if (is_ex_the_function(x, atanh))
+ return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
+ }
+
+ return sinh(x).hold();
}
static ex sinh_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx sinh(x) -> cosh(x)
- return cosh(x);
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx sinh(x) -> cosh(x)
+ return cosh(x);
}
REGISTER_FUNCTION(sinh, eval_func(sinh_eval).
- evalf_func(sinh_evalf).
- derivative_func(sinh_deriv));
+ evalf_func(sinh_evalf).
+ derivative_func(sinh_deriv));
//////////
// hyperbolic cosine (trigonometric function)
static ex cosh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(cosh(x))
-
- return cosh(ex_to_numeric(x)); // -> numeric cosh(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(cosh(x))
+
+ return cosh(ex_to_numeric(x)); // -> numeric cosh(numeric)
}
static ex cosh_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- if (x.is_zero()) // cosh(0) -> 1
- return _ex1();
- if (!x.info(info_flags::crational)) // cosh(float) -> float
- return cosh_evalf(x);
- }
-
- if ((x/Pi).info(info_flags::numeric) &&
- ex_to_numeric(x/Pi).real().is_zero()) // cosh(I*x) -> cos(x)
- return cos(x/I);
-
- if (is_ex_exactly_of_type(x, function)) {
- ex t = x.op(0);
- // cosh(acosh(x)) -> x
- if (is_ex_the_function(x, acosh))
- return t;
- // cosh(asinh(x)) -> (1+x^2)^(1/2)
- if (is_ex_the_function(x, asinh))
- return power(_ex1()+power(t,_ex2()),_ex1_2());
- // cosh(atanh(x)) -> (1-x^2)^(-1/2)
- if (is_ex_the_function(x, atanh))
- return power(_ex1()-power(t,_ex2()),_ex_1_2());
- }
-
- return cosh(x).hold();
+ if (x.info(info_flags::numeric)) {
+ if (x.is_zero()) // cosh(0) -> 1
+ return _ex1();
+ if (!x.info(info_flags::crational)) // cosh(float) -> float
+ return cosh_evalf(x);
+ }
+
+ if ((x/Pi).info(info_flags::numeric) &&
+ ex_to_numeric(x/Pi).real().is_zero()) // cosh(I*x) -> cos(x)
+ return cos(x/I);
+
+ if (is_ex_exactly_of_type(x, function)) {
+ ex t = x.op(0);
+ // cosh(acosh(x)) -> x
+ if (is_ex_the_function(x, acosh))
+ return t;
+ // cosh(asinh(x)) -> (1+x^2)^(1/2)
+ if (is_ex_the_function(x, asinh))
+ return power(_ex1()+power(t,_ex2()),_ex1_2());
+ // cosh(atanh(x)) -> (1-x^2)^(-1/2)
+ if (is_ex_the_function(x, atanh))
+ return power(_ex1()-power(t,_ex2()),_ex_1_2());
+ }
+
+ return cosh(x).hold();
}
static ex cosh_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx cosh(x) -> sinh(x)
- return sinh(x);
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx cosh(x) -> sinh(x)
+ return sinh(x);
}
REGISTER_FUNCTION(cosh, eval_func(cosh_eval).
- evalf_func(cosh_evalf).
- derivative_func(cosh_deriv));
+ evalf_func(cosh_evalf).
+ derivative_func(cosh_deriv));
//////////
static ex tanh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(tanh(x))
-
- return tanh(ex_to_numeric(x)); // -> numeric tanh(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(tanh(x))
+
+ return tanh(ex_to_numeric(x)); // -> numeric tanh(numeric)
}
static ex tanh_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- if (x.is_zero()) // tanh(0) -> 0
- return _ex0();
- if (!x.info(info_flags::crational)) // tanh(float) -> float
- return tanh_evalf(x);
- }
-
- if ((x/Pi).info(info_flags::numeric) &&
- ex_to_numeric(x/Pi).real().is_zero()) // tanh(I*x) -> I*tan(x);
- return I*tan(x/I);
-
- if (is_ex_exactly_of_type(x, function)) {
- ex t = x.op(0);
- // tanh(atanh(x)) -> x
- if (is_ex_the_function(x, atanh))
- return t;
- // tanh(asinh(x)) -> x*(1+x^2)^(-1/2)
- if (is_ex_the_function(x, asinh))
- return t*power(_ex1()+power(t,_ex2()),_ex_1_2());
- // tanh(acosh(x)) -> (x-1)^(1/2)*(x+1)^(1/2)/x
- if (is_ex_the_function(x, acosh))
- return power(t-_ex1(),_ex1_2())*power(t+_ex1(),_ex1_2())*power(t,_ex_1());
- }
-
- return tanh(x).hold();
+ if (x.info(info_flags::numeric)) {
+ if (x.is_zero()) // tanh(0) -> 0
+ return _ex0();
+ if (!x.info(info_flags::crational)) // tanh(float) -> float
+ return tanh_evalf(x);
+ }
+
+ if ((x/Pi).info(info_flags::numeric) &&
+ ex_to_numeric(x/Pi).real().is_zero()) // tanh(I*x) -> I*tan(x);
+ return I*tan(x/I);
+
+ if (is_ex_exactly_of_type(x, function)) {
+ ex t = x.op(0);
+ // tanh(atanh(x)) -> x
+ if (is_ex_the_function(x, atanh))
+ return t;
+ // tanh(asinh(x)) -> x*(1+x^2)^(-1/2)
+ if (is_ex_the_function(x, asinh))
+ return t*power(_ex1()+power(t,_ex2()),_ex_1_2());
+ // tanh(acosh(x)) -> (x-1)^(1/2)*(x+1)^(1/2)/x
+ if (is_ex_the_function(x, acosh))
+ return power(t-_ex1(),_ex1_2())*power(t+_ex1(),_ex1_2())*power(t,_ex_1());
+ }
+
+ return tanh(x).hold();
}
static ex tanh_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx tanh(x) -> 1-tanh(x)^2
- return _ex1()-power(tanh(x),_ex2());
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx tanh(x) -> 1-tanh(x)^2
+ return _ex1()-power(tanh(x),_ex2());
}
static ex tanh_series(const ex &x,
- const relational &rel,
- int order,
- unsigned options)
+ const relational &rel,
+ int order,
+ unsigned options)
{
- // method:
- // Taylor series where there is no pole falls back to tanh_deriv.
- // On a pole simply expand sinh(x)/cosh(x).
- const ex x_pt = x.subs(rel);
- if (!(2*I*x_pt/Pi).info(info_flags::odd))
- throw do_taylor(); // caught by function::series()
- // if we got here we have to care for a simple pole
- return (sinh(x)/cosh(x)).series(rel, order+2);
+ // method:
+ // Taylor series where there is no pole falls back to tanh_deriv.
+ // On a pole simply expand sinh(x)/cosh(x).
+ const ex x_pt = x.subs(rel);
+ if (!(2*I*x_pt/Pi).info(info_flags::odd))
+ throw do_taylor(); // caught by function::series()
+ // if we got here we have to care for a simple pole
+ return (sinh(x)/cosh(x)).series(rel, order+2);
}
REGISTER_FUNCTION(tanh, eval_func(tanh_eval).
- evalf_func(tanh_evalf).
- derivative_func(tanh_deriv).
- series_func(tanh_series));
+ evalf_func(tanh_evalf).
+ derivative_func(tanh_deriv).
+ series_func(tanh_series));
//////////
// inverse hyperbolic sine (trigonometric function)
static ex asinh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(asinh(x))
-
- return asinh(ex_to_numeric(x)); // -> numeric asinh(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(asinh(x))
+
+ return asinh(ex_to_numeric(x)); // -> numeric asinh(numeric)
}
static ex asinh_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // asinh(0) -> 0
- if (x.is_zero())
- return _ex0();
- // asinh(float) -> float
- if (!x.info(info_flags::crational))
- return asinh_evalf(x);
- }
-
- return asinh(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // asinh(0) -> 0
+ if (x.is_zero())
+ return _ex0();
+ // asinh(float) -> float
+ if (!x.info(info_flags::crational))
+ return asinh_evalf(x);
+ }
+
+ return asinh(x).hold();
}
static ex asinh_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx asinh(x) -> 1/sqrt(1+x^2)
- return power(_ex1()+power(x,_ex2()),_ex_1_2());
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx asinh(x) -> 1/sqrt(1+x^2)
+ return power(_ex1()+power(x,_ex2()),_ex_1_2());
}
REGISTER_FUNCTION(asinh, eval_func(asinh_eval).
- evalf_func(asinh_evalf).
- derivative_func(asinh_deriv));
+ evalf_func(asinh_evalf).
+ derivative_func(asinh_deriv));
//////////
// inverse hyperbolic cosine (trigonometric function)
static ex acosh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(acosh(x))
-
- return acosh(ex_to_numeric(x)); // -> numeric acosh(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(acosh(x))
+
+ return acosh(ex_to_numeric(x)); // -> numeric acosh(numeric)
}
static ex acosh_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // acosh(0) -> Pi*I/2
- if (x.is_zero())
- return Pi*I*numeric(1,2);
- // acosh(1) -> 0
- if (x.is_equal(_ex1()))
- return _ex0();
- // acosh(-1) -> Pi*I
- if (x.is_equal(_ex_1()))
- return Pi*I;
- // acosh(float) -> float
- if (!x.info(info_flags::crational))
- return acosh_evalf(x);
- }
-
- return acosh(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // acosh(0) -> Pi*I/2
+ if (x.is_zero())
+ return Pi*I*numeric(1,2);
+ // acosh(1) -> 0
+ if (x.is_equal(_ex1()))
+ return _ex0();
+ // acosh(-1) -> Pi*I
+ if (x.is_equal(_ex_1()))
+ return Pi*I;
+ // acosh(float) -> float
+ if (!x.info(info_flags::crational))
+ return acosh_evalf(x);
+ }
+
+ return acosh(x).hold();
}
static ex acosh_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx acosh(x) -> 1/(sqrt(x-1)*sqrt(x+1))
- return power(x+_ex_1(),_ex_1_2())*power(x+_ex1(),_ex_1_2());
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx acosh(x) -> 1/(sqrt(x-1)*sqrt(x+1))
+ return power(x+_ex_1(),_ex_1_2())*power(x+_ex1(),_ex_1_2());
}
REGISTER_FUNCTION(acosh, eval_func(acosh_eval).
- evalf_func(acosh_evalf).
- derivative_func(acosh_deriv));
+ evalf_func(acosh_evalf).
+ derivative_func(acosh_deriv));
//////////
// inverse hyperbolic tangent (trigonometric function)
static ex atanh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(atanh(x))
-
- return atanh(ex_to_numeric(x)); // -> numeric atanh(numeric)
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(atanh(x))
+
+ return atanh(ex_to_numeric(x)); // -> numeric atanh(numeric)
}
static ex atanh_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- // atanh(0) -> 0
- if (x.is_zero())
- return _ex0();
- // atanh({+|-}1) -> throw
- if (x.is_equal(_ex1()) || x.is_equal(_ex_1()))
- throw (pole_error("atanh_eval(): logarithmic pole",0));
- // atanh(float) -> float
- if (!x.info(info_flags::crational))
- return atanh_evalf(x);
- }
-
- return atanh(x).hold();
+ if (x.info(info_flags::numeric)) {
+ // atanh(0) -> 0
+ if (x.is_zero())
+ return _ex0();
+ // atanh({+|-}1) -> throw
+ if (x.is_equal(_ex1()) || x.is_equal(_ex_1()))
+ throw (pole_error("atanh_eval(): logarithmic pole",0));
+ // atanh(float) -> float
+ if (!x.info(info_flags::crational))
+ return atanh_evalf(x);
+ }
+
+ return atanh(x).hold();
}
static ex atanh_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- // d/dx atanh(x) -> 1/(1-x^2)
- return power(_ex1()-power(x,_ex2()),_ex_1());
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx atanh(x) -> 1/(1-x^2)
+ return power(_ex1()-power(x,_ex2()),_ex_1());
}
REGISTER_FUNCTION(atanh, eval_func(atanh_eval).
- evalf_func(atanh_evalf).
- derivative_func(atanh_deriv));
+ evalf_func(atanh_evalf).
+ derivative_func(atanh_deriv));
#ifndef NO_NAMESPACE_GINAC
} // namespace GiNaC
static ex zeta1_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(zeta(x))
-
- return zeta(ex_to_numeric(x));
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(zeta(x))
+
+ return zeta(ex_to_numeric(x));
}
static ex zeta1_eval(const ex & x)
{
- if (x.info(info_flags::numeric)) {
- numeric y = ex_to_numeric(x);
- // trap integer arguments:
- if (y.is_integer()) {
- if (y.is_zero())
- return -_ex1_2();
- if (x.is_equal(_ex1()))
- throw(std::domain_error("zeta(1): infinity"));
- if (x.info(info_flags::posint)) {
- if (x.info(info_flags::odd))
- return zeta(x).hold();
- else
- return abs(bernoulli(y))*pow(Pi,x)*pow(_num2(),y-_num1())/factorial(y);
- } else {
- if (x.info(info_flags::odd))
- return -bernoulli(_num1()-y)/(_num1()-y);
- else
- return _num0();
- }
- }
- }
- return zeta(x).hold();
+ if (x.info(info_flags::numeric)) {
+ numeric y = ex_to_numeric(x);
+ // trap integer arguments:
+ if (y.is_integer()) {
+ if (y.is_zero())
+ return -_ex1_2();
+ if (x.is_equal(_ex1()))
+ throw(std::domain_error("zeta(1): infinity"));
+ if (x.info(info_flags::posint)) {
+ if (x.info(info_flags::odd))
+ return zeta(x).hold();
+ else
+ return abs(bernoulli(y))*pow(Pi,x)*pow(_num2(),y-_num1())/factorial(y);
+ } else {
+ if (x.info(info_flags::odd))
+ return -bernoulli(_num1()-y)/(_num1()-y);
+ else
+ return _num0();
+ }
+ }
+ }
+ return zeta(x).hold();
}
static ex zeta1_deriv(const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param==0);
-
- return zeta(_ex1(), x);
+ GINAC_ASSERT(deriv_param==0);
+
+ return zeta(_ex1(), x);
}
const unsigned function_index_zeta1 =
- function::register_new(function_options("zeta").
- eval_func(zeta1_eval).
- evalf_func(zeta1_evalf).
+ function::register_new(function_options("zeta").
+ eval_func(zeta1_eval).
+ evalf_func(zeta1_evalf).
derivative_func(zeta1_deriv).
overloaded(2));
static ex zeta2_eval(const ex & n, const ex & x)
{
- if (n.info(info_flags::numeric)) {
- // zeta(0,x) -> zeta(x)
- if (n.is_zero())
- return zeta(x);
- }
-
- return zeta(n, x).hold();
+ if (n.info(info_flags::numeric)) {
+ // zeta(0,x) -> zeta(x)
+ if (n.is_zero())
+ return zeta(x);
+ }
+
+ return zeta(n, x).hold();
}
static ex zeta2_deriv(const ex & n, const ex & x, unsigned deriv_param)
{
- GINAC_ASSERT(deriv_param<2);
-
- if (deriv_param==0) {
- // d/dn zeta(n,x)
- throw(std::logic_error("cannot diff zeta(n,x) with respect to n"));
- }
- // d/dx psi(n,x)
- return zeta(n+1,x);
+ GINAC_ASSERT(deriv_param<2);
+
+ if (deriv_param==0) {
+ // d/dn zeta(n,x)
+ throw(std::logic_error("cannot diff zeta(n,x) with respect to n"));
+ }
+ // d/dx psi(n,x)
+ return zeta(n+1,x);
}
const unsigned function_index_zeta2 =
- function::register_new(function_options("zeta").
- eval_func(zeta2_eval).
+ function::register_new(function_options("zeta").
+ eval_func(zeta2_eval).
derivative_func(zeta2_deriv).
overloaded(2));
extern "C" {
#include <stdio.h>
}
-
+
#include "config.h"
// yacc stack type
isospin::isospin()
{
- debugmsg("isospin default constructor",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- name=autoname_prefix()+ToString(serial);
- tinfo_key=TINFO_isospin;
+ debugmsg("isospin default constructor",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ name=autoname_prefix()+ToString(serial);
+ tinfo_key=TINFO_isospin;
}
isospin::~isospin()
{
- debugmsg("isospin destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("isospin destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
isospin::isospin(const isospin & other)
{
- debugmsg("isospin copy constructor",LOGLEVEL_CONSTRUCT);
- copy (other);
+ debugmsg("isospin copy constructor",LOGLEVEL_CONSTRUCT);
+ copy (other);
}
const isospin & isospin::operator=(const isospin & other)
{
- debugmsg("isospin operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("isospin operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void isospin::copy(const isospin & other)
{
- inherited::copy(other);
- name=other.name;
- serial=other.serial;
+ inherited::copy(other);
+ name=other.name;
+ serial=other.serial;
}
void isospin::destroy(bool call_parent)
{
- if (call_parent) {
- inherited::destroy(call_parent);
- }
+ if (call_parent) {
+ inherited::destroy(call_parent);
+ }
}
//////////
isospin::isospin(const std::string & initname)
{
- debugmsg("isospin constructor from string",LOGLEVEL_CONSTRUCT);
- name=initname;
- serial=next_serial++;
- tinfo_key=TINFO_isospin;
+ debugmsg("isospin constructor from string",LOGLEVEL_CONSTRUCT);
+ name=initname;
+ serial=next_serial++;
+ tinfo_key=TINFO_isospin;
}
//////////
/** Construct object from archive_node. */
isospin::isospin(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("isospin constructor from archive_node", LOGLEVEL_CONSTRUCT);
- serial = next_serial++;
- if (!(n.find_string("name", name)))
- name = autoname_prefix() + ToString(serial);
- tinfo_key = TINFO_isospin;
+ debugmsg("isospin constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ serial = next_serial++;
+ if (!(n.find_string("name", name)))
+ name = autoname_prefix() + ToString(serial);
+ tinfo_key = TINFO_isospin;
}
/** Unarchive the object. */
ex isospin::unarchive(const archive_node &n, const lst &sym_lst)
{
- ex s = (new isospin(n, sym_lst))->setflag(status_flags::dynallocated);
-
- // If isospin is in sym_lst, return the existing isospin
- for (unsigned i=0; i<sym_lst.nops(); i++) {
- if (is_ex_of_type(sym_lst.op(i), isospin) && (ex_to_isospin(sym_lst.op(i)).name == ex_to_isospin(s).name))
- return sym_lst.op(i);
- }
- return s;
+ ex s = (new isospin(n, sym_lst))->setflag(status_flags::dynallocated);
+
+ // If isospin is in sym_lst, return the existing isospin
+ for (unsigned i=0; i<sym_lst.nops(); i++) {
+ if (is_ex_of_type(sym_lst.op(i), isospin) && (ex_to_isospin(sym_lst.op(i)).name == ex_to_isospin(s).name))
+ return sym_lst.op(i);
+ }
+ return s;
}
/** Archive the object. */
void isospin::archive(archive_node &n) const
{
- inherited::archive(n);
- n.add_string("name", name);
+ inherited::archive(n);
+ n.add_string("name", name);
}
//////////
basic * isospin::duplicate() const
{
- debugmsg("isospin duplicate",LOGLEVEL_DUPLICATE);
- return new isospin(*this);
+ debugmsg("isospin duplicate",LOGLEVEL_DUPLICATE);
+ return new isospin(*this);
}
void isospin::printraw(std::ostream & os) const
{
- debugmsg("isospin printraw",LOGLEVEL_PRINT);
- os << "isospin(" << "name=" << name << ",serial=" << serial
- << ",indices=";
- printrawindices(os);
- os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+ debugmsg("isospin printraw",LOGLEVEL_PRINT);
+ os << "isospin(" << "name=" << name << ",serial=" << serial
+ << ",indices=";
+ printrawindices(os);
+ os << ",hash=" << hashvalue << ",flags=" << flags << ")";
}
void isospin::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("isospin printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << name << " (isospin): "
- << "serial=" << serial << ","
- << seq.size() << "indices=";
- printtreeindices(os,indent);
- os << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("isospin printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << name << " (isospin): "
+ << "serial=" << serial << ","
+ << seq.size() << "indices=";
+ printtreeindices(os,indent);
+ os << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void isospin::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("isospin print",LOGLEVEL_PRINT);
- os << name;
- printindices(os);
+ debugmsg("isospin print",LOGLEVEL_PRINT);
+ os << name;
+ printindices(os);
}
void isospin::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("isospin print csrc",LOGLEVEL_PRINT);
- print(os,upper_precedence);
+ debugmsg("isospin print csrc",LOGLEVEL_PRINT);
+ print(os,upper_precedence);
}
bool isospin::info(unsigned inf) const
{
- return inherited::info(inf);
+ return inherited::info(inf);
}
// protected
int isospin::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(other.tinfo() == TINFO_isospin);
- const isospin *o = static_cast<const isospin *>(&other);
- if (serial==o->serial) {
- return inherited::compare_same_type(other);
- }
- return serial < o->serial ? -1 : 1;
+ GINAC_ASSERT(other.tinfo() == TINFO_isospin);
+ const isospin *o = static_cast<const isospin *>(&other);
+ if (serial==o->serial) {
+ return inherited::compare_same_type(other);
+ }
+ return serial < o->serial ? -1 : 1;
}
ex isospin::simplify_ncmul(const exvector & v) const
{
- return simplified_ncmul(v);
+ return simplified_ncmul(v);
}
unsigned isospin::calchash(void) const
{
- hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555556U ^
- golden_ratio_hash(tinfo_key) ^
- serial));
- setflag(status_flags::hash_calculated);
- return hashvalue;
+ hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555556U ^
+ golden_ratio_hash(tinfo_key) ^
+ serial));
+ setflag(status_flags::hash_calculated);
+ return hashvalue;
}
//////////
void isospin::setname(const std::string & n)
{
- name = n;
+ name = n;
}
// private
std::string & isospin::autoname_prefix(void)
{
- static std::string * s = new std::string("isospin");
- return *s;
+ static std::string * s = new std::string("isospin");
+ return *s;
}
//////////
/** Base class for isospin object */
class isospin : public indexed
{
- GINAC_DECLARE_REGISTERED_CLASS(isospin, indexed)
+ GINAC_DECLARE_REGISTERED_CLASS(isospin, indexed)
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- isospin();
- ~isospin();
- isospin(const isospin & other);
- const isospin & operator=(const isospin & other);
+ isospin();
+ ~isospin();
+ isospin(const isospin & other);
+ const isospin & operator=(const isospin & other);
protected:
- void copy(const isospin & other);
- void destroy(bool call_parent);
+ void copy(const isospin & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- explicit isospin(const std::string & initname);
+ explicit isospin(const std::string & initname);
- // functions overriding virtual functions from base classes
+ // functions overriding virtual functions from base classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
protected:
- int compare_same_type(const basic & other) const;
- ex simplify_ncmul(const exvector & v) const;
- unsigned calchash(void) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ int compare_same_type(const basic & other) const;
+ ex simplify_ncmul(const exvector & v) const;
+ unsigned calchash(void) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
public:
- void setname(const std::string & n);
+ void setname(const std::string & n);
private:
- std::string & autoname_prefix(void);
+ std::string & autoname_prefix(void);
// member variables
protected:
- std::string name;
- unsigned serial; // unique serial number for comparision
+ std::string name;
+ unsigned serial; // unique serial number for comparision
private:
- static unsigned next_serial;
+ static unsigned next_serial;
};
// global constants
lorentzidx::lorentzidx() : orthogonal_only(false), dim_parallel_space(0)
{
- debugmsg("lorentzidx default constructor",LOGLEVEL_CONSTRUCT);
- // serial is incremented in idx::idx()
- name="mu"+ToString(serial);
- tinfo_key=TINFO_lorentzidx;
+ debugmsg("lorentzidx default constructor",LOGLEVEL_CONSTRUCT);
+ // serial is incremented in idx::idx()
+ name="mu"+ToString(serial);
+ tinfo_key=TINFO_lorentzidx;
}
lorentzidx::~lorentzidx()
{
- debugmsg("lorentzidx destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("lorentzidx destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
lorentzidx::lorentzidx(const lorentzidx & other)
{
- debugmsg("lorentzidx copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("lorentzidx copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const lorentzidx & lorentzidx::operator=(const lorentzidx & other)
{
- debugmsg("lorentzidx operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("lorentzidx operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void lorentzidx::copy(const lorentzidx & other)
{
- inherited::copy(other);
- orthogonal_only=other.orthogonal_only;
- dim_parallel_space=other.dim_parallel_space;
+ inherited::copy(other);
+ orthogonal_only=other.orthogonal_only;
+ dim_parallel_space=other.dim_parallel_space;
}
void lorentzidx::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
//////////
// public
lorentzidx::lorentzidx(bool cov, bool oonly, unsigned dimp) :
- idx(cov), orthogonal_only(oonly), dim_parallel_space(dimp)
+ idx(cov), orthogonal_only(oonly), dim_parallel_space(dimp)
{
- debugmsg("lorentzidx constructor from bool",LOGLEVEL_CONSTRUCT);
- // serial is incremented in idx::idx(bool)
- if (oonly) {
- name="muorth"+ToString(serial);
- } else {
- name="mu"+ToString(serial);
- }
- tinfo_key=TINFO_lorentzidx;
+ debugmsg("lorentzidx constructor from bool",LOGLEVEL_CONSTRUCT);
+ // serial is incremented in idx::idx(bool)
+ if (oonly) {
+ name="muorth"+ToString(serial);
+ } else {
+ name="mu"+ToString(serial);
+ }
+ tinfo_key=TINFO_lorentzidx;
}
lorentzidx::lorentzidx(const std::string & n, bool cov, bool oonly, unsigned dimp)
- : idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp)
+ : idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp)
{
- debugmsg("lorentzidx constructor from string,bool,bool,unsigned",
- LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_lorentzidx;
+ debugmsg("lorentzidx constructor from string,bool,bool,unsigned",
+ LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_lorentzidx;
}
lorentzidx::lorentzidx(const char * n, bool cov, bool oonly, unsigned dimp)
- : idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp)
+ : idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp)
{
- debugmsg("lorentzidx constructor from char*,bool,bool,unsigned",
- LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_lorentzidx;
+ debugmsg("lorentzidx constructor from char*,bool,bool,unsigned",
+ LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_lorentzidx;
}
lorentzidx::lorentzidx(unsigned v, bool cov) : idx(v,cov),
- orthogonal_only(false), dim_parallel_space(0)
+ orthogonal_only(false), dim_parallel_space(0)
{
- debugmsg("lorentzidx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_lorentzidx;
+ debugmsg("lorentzidx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_lorentzidx;
}
//////////
/** Construct object from archive_node. */
lorentzidx::lorentzidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("lorentzidx constructor from archive_node", LOGLEVEL_CONSTRUCT);
- n.find_bool("orthogonal_only", orthogonal_only);
+ debugmsg("lorentzidx constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ n.find_bool("orthogonal_only", orthogonal_only);
if (orthogonal_only)
n.find_unsigned("pdim", dim_parallel_space);
}
/** Unarchive the object. */
ex lorentzidx::unarchive(const archive_node &n, const lst &sym_lst)
{
- ex s = (new lorentzidx(n, sym_lst))->setflag(status_flags::dynallocated);
-
- if (ex_to_lorentzidx(s).symbolic) {
- // If lorentzidx is in sym_lst, return the existing lorentzidx
- for (unsigned i=0; i<sym_lst.nops(); i++) {
- if (is_ex_of_type(sym_lst.op(i), lorentzidx) && (ex_to_lorentzidx(sym_lst.op(i)).name == ex_to_lorentzidx(s).name))
- return sym_lst.op(i);
- }
- }
- return s;
+ ex s = (new lorentzidx(n, sym_lst))->setflag(status_flags::dynallocated);
+
+ if (ex_to_lorentzidx(s).symbolic) {
+ // If lorentzidx is in sym_lst, return the existing lorentzidx
+ for (unsigned i=0; i<sym_lst.nops(); i++) {
+ if (is_ex_of_type(sym_lst.op(i), lorentzidx) && (ex_to_lorentzidx(sym_lst.op(i)).name == ex_to_lorentzidx(s).name))
+ return sym_lst.op(i);
+ }
+ }
+ return s;
}
/** Archive the object. */
void lorentzidx::archive(archive_node &n) const
{
- inherited::archive(n);
+ inherited::archive(n);
n.add_bool("orthogonal_only", orthogonal_only);
if (orthogonal_only)
n.add_unsigned("pdim", dim_parallel_space);
basic * lorentzidx::duplicate() const
{
- debugmsg("lorentzidx duplicate",LOGLEVEL_DUPLICATE);
- return new lorentzidx(*this);
+ debugmsg("lorentzidx duplicate",LOGLEVEL_DUPLICATE);
+ return new lorentzidx(*this);
}
void lorentzidx::printraw(std::ostream & os) const
{
- debugmsg("lorentzidx printraw",LOGLEVEL_PRINT);
-
- os << "lorentzidx(";
-
- if (symbolic) {
- os << "symbolic,name=" << name;
- } else {
- os << "non symbolic,value=" << value;
- }
-
- if (covariant) {
- os << ",covariant";
- } else {
- os << ",contravariant";
- }
-
- if (orthogonal_only) {
- os << ",only orthogonal components at " << dim_parallel_space
- << " parallel dimensions";
- } else {
- os << ",parallel and orthogonal components";
- }
-
- os << ",serial=" << serial;
- os << ",hash=" << hashvalue << ",flags=" << flags;
- os << ")";
+ debugmsg("lorentzidx printraw",LOGLEVEL_PRINT);
+
+ os << "lorentzidx(";
+
+ if (symbolic) {
+ os << "symbolic,name=" << name;
+ } else {
+ os << "non symbolic,value=" << value;
+ }
+
+ if (covariant) {
+ os << ",covariant";
+ } else {
+ os << ",contravariant";
+ }
+
+ if (orthogonal_only) {
+ os << ",only orthogonal components at " << dim_parallel_space
+ << " parallel dimensions";
+ } else {
+ os << ",parallel and orthogonal components";
+ }
+
+ os << ",serial=" << serial;
+ os << ",hash=" << hashvalue << ",flags=" << flags;
+ os << ")";
}
void lorentzidx::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("lorentzidx printtree",LOGLEVEL_PRINT);
-
- os << std::string(indent,' ') << "lorentzidx: ";
-
- if (symbolic) {
- os << "symbolic,name=" << name;
- } else {
- os << "non symbolic,value=" << value;
- }
-
- if (covariant) {
- os << ",covariant";
- } else {
- os << ",contravariant";
- }
-
- if (orthogonal_only) {
- os << ",only orthogonal components at " << dim_parallel_space
- << " parallel dimensions";
- } else {
- os << ",parallel and orthogonal components";
- }
-
- os << ", serial=" << serial
- << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("lorentzidx printtree",LOGLEVEL_PRINT);
+
+ os << std::string(indent,' ') << "lorentzidx: ";
+
+ if (symbolic) {
+ os << "symbolic,name=" << name;
+ } else {
+ os << "non symbolic,value=" << value;
+ }
+
+ if (covariant) {
+ os << ",covariant";
+ } else {
+ os << ",contravariant";
+ }
+
+ if (orthogonal_only) {
+ os << ",only orthogonal components at " << dim_parallel_space
+ << " parallel dimensions";
+ } else {
+ os << ",parallel and orthogonal components";
+ }
+
+ os << ", serial=" << serial
+ << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void lorentzidx::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("lorentzidx print",LOGLEVEL_PRINT);
-
- if (covariant) {
- os << "_";
- } else {
- os << "~";
- }
- if (symbolic) {
- os << name;
- } else {
- os << value;
- }
+ debugmsg("lorentzidx print",LOGLEVEL_PRINT);
+
+ if (covariant) {
+ os << "_";
+ } else {
+ os << "~";
+ }
+ if (symbolic) {
+ os << name;
+ } else {
+ os << value;
+ }
}
bool lorentzidx::info(unsigned inf) const
{
- if (inf==info_flags::lorentzidx) return true;
- return inherited::info(inf);
+ if (inf==info_flags::lorentzidx) return true;
+ return inherited::info(inf);
}
//////////
lorentzidx lorentzidx::create_anonymous_representative(void) const
{
- GINAC_ASSERT(is_symbolic());
- lorentzidx i_copy(*this);
- i_copy.serial=0;
- i_copy.name="anonymous_representative";
- i_copy.covariant=false;
- i_copy.clearflag(status_flags::dynallocated|
- status_flags::hash_calculated);
- return i_copy;
+ GINAC_ASSERT(is_symbolic());
+ lorentzidx i_copy(*this);
+ i_copy.serial=0;
+ i_copy.name="anonymous_representative";
+ i_copy.covariant=false;
+ i_copy.clearflag(status_flags::dynallocated|
+ status_flags::hash_calculated);
+ return i_copy;
}
//////////
class lorentzidx : public idx
{
- GINAC_DECLARE_REGISTERED_CLASS(lorentzidx, idx)
+ GINAC_DECLARE_REGISTERED_CLASS(lorentzidx, idx)
- friend class simp_lor;
- friend class scalar_products;
+ friend class simp_lor;
+ friend class scalar_products;
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- lorentzidx();
- ~lorentzidx();
- lorentzidx (const lorentzidx & other);
- const lorentzidx & operator=(const lorentzidx & other);
+ lorentzidx();
+ ~lorentzidx();
+ lorentzidx (const lorentzidx & other);
+ const lorentzidx & operator=(const lorentzidx & other);
protected:
- void copy(const lorentzidx & other);
- void destroy(bool call_parent);
+ void copy(const lorentzidx & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- explicit lorentzidx(bool cov, bool oonly=false, unsigned dimp=0);
- explicit lorentzidx(const std::string & n, bool cov=false,
- bool oonly=false, unsigned dimp=0);
- explicit lorentzidx(const char * n, bool cov=false,
- bool oonly=false, unsigned dimp=0);
- explicit lorentzidx(unsigned v, bool cov=false);
-
- // functions overriding virtual functions from bases classes
+ explicit lorentzidx(bool cov, bool oonly=false, unsigned dimp=0);
+ explicit lorentzidx(const std::string & n, bool cov=false,
+ bool oonly=false, unsigned dimp=0);
+ explicit lorentzidx(const char * n, bool cov=false,
+ bool oonly=false, unsigned dimp=0);
+ explicit lorentzidx(unsigned v, bool cov=false);
+
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
- // new virtual functions which can be overridden by derived classes
- // none
+ // new virtual functions which can be overridden by derived classes
+ // none
- // non-virtual functions in this class
+ // non-virtual functions in this class
public:
- bool is_orthogonal_only(void) const { return orthogonal_only; }
- unsigned get_dim_parallel_space(void) const { return dim_parallel_space; }
- lorentzidx create_anonymous_representative(void) const;
+ bool is_orthogonal_only(void) const { return orthogonal_only; }
+ unsigned get_dim_parallel_space(void) const { return dim_parallel_space; }
+ lorentzidx create_anonymous_representative(void) const;
- // member variables
+ // member variables
protected:
- bool orthogonal_only;
- unsigned dim_parallel_space;
+ bool orthogonal_only;
+ unsigned dim_parallel_space;
};
// global constants
lortensor::lortensor()
{
- debugmsg("lortensor default constructor",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- name=autoname_prefix()+ToString(serial);
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor default constructor",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ name=autoname_prefix()+ToString(serial);
+ tinfo_key=TINFO_lortensor;
}
lortensor::~lortensor()
{
- debugmsg("lortensor destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("lortensor destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
lortensor::lortensor(const lortensor & other)
{
- debugmsg("lortensor copy constructor",LOGLEVEL_CONSTRUCT);
- copy (other);
+ debugmsg("lortensor copy constructor",LOGLEVEL_CONSTRUCT);
+ copy (other);
}
const lortensor & lortensor::operator=(const lortensor & other)
{
- debugmsg("lortensor operator=",LOGLEVEL_ASSIGNMENT);
- if (this != & other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("lortensor operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != & other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
//protected
void lortensor::copy(const lortensor & other)
{
- indexed::copy(other);
- type=other.type;
- name=other.name;
- serial=other.serial;
+ indexed::copy(other);
+ type=other.type;
+ name=other.name;
+ serial=other.serial;
}
void lortensor::destroy(bool call_parent)
{
- if (call_parent) {
- indexed::destroy(call_parent);
- }
+ if (call_parent) {
+ indexed::destroy(call_parent);
+ }
}
//////////
lortensor::lortensor(lortensor_types const lt, const std::string & n) : type(lt), name(n)
{
- debugmsg("lortensor constructor from lortensor_types,string",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor constructor from lortensor_types,string",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ tinfo_key=TINFO_lortensor;
}
lortensor::lortensor(lortensor_types const lt, const std::string & n, const ex & mu) : indexed(mu), type(lt), name(n)
{
- debugmsg("lortensor constructor from lortensor_types,string,ex",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- GINAC_ASSERT(all_of_type_lorentzidx());
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor constructor from lortensor_types,string,ex",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ GINAC_ASSERT(all_of_type_lorentzidx());
+ tinfo_key=TINFO_lortensor;
}
lortensor::lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu) : indexed(mu,nu), type(lt), name(n)
{
- debugmsg("lortensor constructor from lortensor_types,string,ex,ex",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- GINAC_ASSERT(all_of_type_lorentzidx());
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor constructor from lortensor_types,string,ex,ex",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ GINAC_ASSERT(all_of_type_lorentzidx());
+ tinfo_key=TINFO_lortensor;
}
lortensor::lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu, const ex & rho) : indexed(mu,nu,rho), type(lt), name(n)
{
- debugmsg("lortensor constructor from lortensor_types,string,ex,ex,ex",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- GINAC_ASSERT(all_of_type_lorentzidx());
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor constructor from lortensor_types,string,ex,ex,ex",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ GINAC_ASSERT(all_of_type_lorentzidx());
+ tinfo_key=TINFO_lortensor;
}
lortensor::lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu, const ex & rho, const ex & sigma) : indexed(mu,nu,rho,sigma), type(lt), name(n)
{
- debugmsg("lortensor constructor from lortensor_types,string,ex,ex,ex,ex",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- GINAC_ASSERT(all_of_type_lorentzidx());
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor constructor from lortensor_types,string,ex,ex,ex,ex",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ GINAC_ASSERT(all_of_type_lorentzidx());
+ tinfo_key=TINFO_lortensor;
}
lortensor::lortensor(lortensor_types const lt, const std::string & n, const exvector & iv) : indexed(iv), type(lt), name(n)
{
- debugmsg("lortensor constructor from lortensor_types,string,exvector",LOGLEVEL_CONSTRUCT);
- serial=next_serial++;
- GINAC_ASSERT(all_of_type_lorentzidx());
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor constructor from lortensor_types,string,exvector",LOGLEVEL_CONSTRUCT);
+ serial=next_serial++;
+ GINAC_ASSERT(all_of_type_lorentzidx());
+ tinfo_key=TINFO_lortensor;
}
lortensor::lortensor(lortensor_types const lt, const std::string & n, unsigned s, const exvector & iv) : indexed(iv), type(lt), name(n), serial(s)
{
- debugmsg("lortensor constructor from lortensor_types,string,unsigned,exvector",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(all_of_type_lorentzidx());
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor constructor from lortensor_types,string,unsigned,exvector",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(all_of_type_lorentzidx());
+ tinfo_key=TINFO_lortensor;
}
lortensor::lortensor(lortensor_types const lt, const std::string & n, unsigned s, exvector *ivp) : indexed(ivp), type(lt), name(n), serial(s)
{
- debugmsg("lortensor constructor from lortensor_types,string,unsigned,exvector",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(all_of_type_lorentzidx());
- tinfo_key=TINFO_lortensor;
+ debugmsg("lortensor constructor from lortensor_types,string,unsigned,exvector",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(all_of_type_lorentzidx());
+ tinfo_key=TINFO_lortensor;
}
//////////
basic * lortensor::duplicate() const
{
- debugmsg("lortensor duplicate",LOGLEVEL_DUPLICATE);
- return new lortensor(*this);
+ debugmsg("lortensor duplicate",LOGLEVEL_DUPLICATE);
+ return new lortensor(*this);
}
void lortensor::printraw(std::ostream & os) const
{
- debugmsg("lortensor printraw",LOGLEVEL_PRINT);
- os << "lortensor(type=" << (unsigned)type
- << ",indices=";
- printrawindices(os);
- os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+ debugmsg("lortensor printraw",LOGLEVEL_PRINT);
+ os << "lortensor(type=" << (unsigned)type
+ << ",indices=";
+ printrawindices(os);
+ os << ",hash=" << hashvalue << ",flags=" << flags << ")";
}
void lortensor::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("lortensor printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') <<"lortensor object: "
- << "type=" << (unsigned)type << ","
- << seq.size() << " indices" << std::endl;
- printtreeindices(os,indent);
- os << std::string(indent,' ') << "hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("lortensor printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') <<"lortensor object: "
+ << "type=" << (unsigned)type << ","
+ << seq.size() << " indices" << std::endl;
+ printtreeindices(os,indent);
+ os << std::string(indent,' ') << "hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void lortensor::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("lortensor print",LOGLEVEL_PRINT);
- switch (type) {
- case lortensor_g:
- os << "g";
- break;
- case lortensor_rankn:
- os << name;
- break;
- case lortensor_rank1:
- os << name;
- break;
- case lortensor_rank2:
- os << name;
- break;
- case lortensor_epsilon:
- os << "epsilon";
- break;
- case invalid:
- default:
- os << "INVALID_LORTENSOR_OBJECT";
- break;
- }
- printindices(os);
+ debugmsg("lortensor print",LOGLEVEL_PRINT);
+ switch (type) {
+ case lortensor_g:
+ os << "g";
+ break;
+ case lortensor_rankn:
+ os << name;
+ break;
+ case lortensor_rank1:
+ os << name;
+ break;
+ case lortensor_rank2:
+ os << name;
+ break;
+ case lortensor_epsilon:
+ os << "epsilon";
+ break;
+ case invalid:
+ default:
+ os << "INVALID_LORTENSOR_OBJECT";
+ break;
+ }
+ printindices(os);
}
void lortensor::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("lortensor print csrc",LOGLEVEL_PRINT);
- print(os,upper_precedence);
+ debugmsg("lortensor print csrc",LOGLEVEL_PRINT);
+ print(os,upper_precedence);
}
bool lortensor::info(unsigned inf) const
{
- return indexed::info(inf);
+ return indexed::info(inf);
}
ex lortensor::eval(int level) const
{
- if (type==lortensor_g) {
- // canonicalize indices
- exvector iv=seq;
- int sig=canonicalize_indices(iv,false); //symmetric
- if (sig!=INT_MAX) {
- //something has changed while sorting indices, more evaluations later
- return ex(sig) *lortensor(type,name,iv);
- }
- const lorentzidx & idx1=ex_to_lorentzidx(seq[0]);
- const lorentzidx & idx2=ex_to_lorentzidx(seq[1]);
- if ((!idx1.is_symbolic()) && (!idx2.is_symbolic())) {
- //both indices are numeric
- if ((idx1.get_value()==idx2.get_value())) {
- //both on diagonal
- if (idx1.get_value()==0){
- // (0,0)
- return _ex1();
- } else {
- if (idx1.is_covariant() != idx2.is_covariant()) {
- // (_i,~i) or (~i,_i), i = 1...3
- return _ex1();
- } else {
- // (_i,_i) or (~i,~i), i= 1...3
- return _ex_1();
- }
- }
- } else {
- // at least one off-diagonal
- return _ex0();
- }
- } else if (idx1.is_symbolic() && idx1.is_co_contra_pair(idx2)) {
- return Dim()-idx1.get_dim_parallel_space();
- }
- }
- return this -> hold();
+ if (type==lortensor_g) {
+ // canonicalize indices
+ exvector iv=seq;
+ int sig=canonicalize_indices(iv,false); //symmetric
+ if (sig!=INT_MAX) {
+ //something has changed while sorting indices, more evaluations later
+ return ex(sig) *lortensor(type,name,iv);
+ }
+ const lorentzidx & idx1=ex_to_lorentzidx(seq[0]);
+ const lorentzidx & idx2=ex_to_lorentzidx(seq[1]);
+ if ((!idx1.is_symbolic()) && (!idx2.is_symbolic())) {
+ //both indices are numeric
+ if ((idx1.get_value()==idx2.get_value())) {
+ //both on diagonal
+ if (idx1.get_value()==0){
+ // (0,0)
+ return _ex1();
+ } else {
+ if (idx1.is_covariant() != idx2.is_covariant()) {
+ // (_i,~i) or (~i,_i), i = 1...3
+ return _ex1();
+ } else {
+ // (_i,_i) or (~i,~i), i= 1...3
+ return _ex_1();
+ }
+ }
+ } else {
+ // at least one off-diagonal
+ return _ex0();
+ }
+ } else if (idx1.is_symbolic() && idx1.is_co_contra_pair(idx2)) {
+ return Dim()-idx1.get_dim_parallel_space();
+ }
+ }
+ return this -> hold();
}
//protected
int lortensor::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other,lortensor));
- const lortensor *o = static_cast <const lortensor *> (&other);
- if (type==o->type) {
- if (type==lortensor_rankn) {
- if (serial!=o->serial) {
- return serial < o->serial ? -1 : 1;
- }
- }
- return indexed::compare_same_type(other);
- }
- return type < o->type ? -1 : 1;
+ GINAC_ASSERT(is_of_type(other,lortensor));
+ const lortensor *o = static_cast <const lortensor *> (&other);
+ if (type==o->type) {
+ if (type==lortensor_rankn) {
+ if (serial!=o->serial) {
+ return serial < o->serial ? -1 : 1;
+ }
+ }
+ return indexed::compare_same_type(other);
+ }
+ return type < o->type ? -1 : 1;
}
bool lortensor::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other,lortensor));
- const lortensor *o=static_cast<const lortensor *> (&other);
- if (type!=o->type) return false;
- if (type==lortensor_rankn) {
- if (serial!=o->serial) return false;
- }
- return indexed::is_equal_same_type(other);
+ GINAC_ASSERT(is_of_type(other,lortensor));
+ const lortensor *o=static_cast<const lortensor *> (&other);
+ if (type!=o->type) return false;
+ if (type==lortensor_rankn) {
+ if (serial!=o->serial) return false;
+ }
+ return indexed::is_equal_same_type(other);
}
unsigned lortensor::return_type(void) const
{
- return return_types::commutative;
+ return return_types::commutative;
}
unsigned lortensor::return_type_tinfo(void) const
{
- return tinfo_key;
+ return tinfo_key;
}
ex lortensor::thisexprseq(const exvector & v) const
{
- return lortensor(type,name,serial,v);
+ return lortensor(type,name,serial,v);
}
ex lortensor::thisexprseq(exvector *vp) const
{
- return lortensor(type,name,serial,vp);
+ return lortensor(type,name,serial,vp);
}
-
+
//////////
// non-virtual functions in this class
//////////
void lortensor::setname(const std::string & n)
{
- name = n;
+ name = n;
}
bool lortensor::all_of_type_lorentzidx(void) const
{
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++ cit) {
- if (!is_ex_of_type(*cit,lorentzidx)) {
- return false;
- }
- }
- return true;
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++ cit) {
+ if (!is_ex_of_type(*cit,lorentzidx)) {
+ return false;
+ }
+ }
+ return true;
}
// private
std::string & lortensor::autoname_prefix(void)
{
- static std::string * s = new std::string("lortensor");
- return *s;
+ static std::string * s = new std::string("lortensor");
+ return *s;
}
//////////
lortensor lortensor_g(const ex & mu, const ex & nu)
{
- return lortensor(lortensor::lortensor_g,"",mu,nu);
+ return lortensor(lortensor::lortensor_g,"",mu,nu);
}
lortensor lortensor_epsilon(const ex & mu, const ex & nu, const ex & rho, const ex & sigma)
{
- return lortensor(lortensor::lortensor_epsilon,"",mu,nu,rho,sigma);
+ return lortensor(lortensor::lortensor_epsilon,"",mu,nu,rho,sigma);
}
lortensor lortensor_rank1(const std::string & n, const ex & mu)
{
- return lortensor(lortensor::lortensor_rank1,n,mu);
+ return lortensor(lortensor::lortensor_rank1,n,mu);
}
lortensor lortensor_rank2(const std::string & n, const ex & mu, const ex & nu)
{
- return lortensor(lortensor::lortensor_rank2,n,mu,nu);
+ return lortensor(lortensor::lortensor_rank2,n,mu,nu);
}
ex simplify_lortensor_mul(const ex & m)
{
- GINAC_ASSERT(is_ex_exactly_of_type(m,mul));
- exvector v_contracted;
-
- // collect factors in an exvector, store squares twice
- int n=m.nops();
- v_contracted.reserve(2*n);
- for (int i=0; i<n; ++i) {
- ex f=m.op(i);
- if (is_ex_exactly_of_type(f,power)&&f.op(1).is_equal(_ex2())) {
- v_contracted.push_back(f.op(0));
- v_contracted.push_back(f.op(0));
- } else {
- v_contracted.push_back(f);
- }
- }
-
- unsigned replacements;
- bool something_changed=false;
-
- exvector::iterator it=v_contracted.begin();
- while (it!=v_contracted.end()) {
- // process only lor_g objects
- if (is_ex_exactly_of_type(*it,lortensor) &&
- (ex_to_lortensor(*it).type==lortensor::lortensor_g)) {
- const lortensor & g=ex_to_lortensor(*it);
- GINAC_ASSERT(g.seq.size()==2);
- const idx & first_idx=ex_to_lorentzidx(g.seq[0]);
- const idx & second_idx=ex_to_lorentzidx(g.seq[1]);
- // g_{mu,mu} should have been contracted in lortensor::eval()
- GINAC_ASSERT(!first_idx.is_equal(second_idx));
- ex saved_g=*it; // save to restore it later
-
- // try to contract first index
- replacements=0;
- if (first_idx.is_symbolic()) {
- replacements = subs_index_in_exvector(v_contracted,
- first_idx.toggle_covariant(),second_idx);
- if (replacements==0) {
- // not contracted, restore g object
- *it=saved_g;
- } else {
- // a contracted index should occur exactly once
- GINAC_ASSERT(replacements==1);
- *it=_ex1();
- something_changed=true;
- }
- }
-
- // try second index only if first was not contracted
- if ((replacements==0)&&(second_idx.is_symbolic())) {
- // first index not contracted, *it is again the original g object
- replacements = subs_index_in_exvector(v_contracted,
- second_idx.toggle_covariant(),first_idx);
- if (replacements==0) {
- // not contracted except in itself, restore g object
- *it=saved_g;
- } else {
- // a contracted index should occur exactly once
- GINAC_ASSERT(replacements==1);
- *it=_ex1();
- something_changed=true;
- }
- }
- }
- ++it;
- }
- if (something_changed) {
- return mul(v_contracted);
- }
- return m;
+ GINAC_ASSERT(is_ex_exactly_of_type(m,mul));
+ exvector v_contracted;
+
+ // collect factors in an exvector, store squares twice
+ int n=m.nops();
+ v_contracted.reserve(2*n);
+ for (int i=0; i<n; ++i) {
+ ex f=m.op(i);
+ if (is_ex_exactly_of_type(f,power)&&f.op(1).is_equal(_ex2())) {
+ v_contracted.push_back(f.op(0));
+ v_contracted.push_back(f.op(0));
+ } else {
+ v_contracted.push_back(f);
+ }
+ }
+
+ unsigned replacements;
+ bool something_changed=false;
+
+ exvector::iterator it=v_contracted.begin();
+ while (it!=v_contracted.end()) {
+ // process only lor_g objects
+ if (is_ex_exactly_of_type(*it,lortensor) &&
+ (ex_to_lortensor(*it).type==lortensor::lortensor_g)) {
+ const lortensor & g=ex_to_lortensor(*it);
+ GINAC_ASSERT(g.seq.size()==2);
+ const idx & first_idx=ex_to_lorentzidx(g.seq[0]);
+ const idx & second_idx=ex_to_lorentzidx(g.seq[1]);
+ // g_{mu,mu} should have been contracted in lortensor::eval()
+ GINAC_ASSERT(!first_idx.is_equal(second_idx));
+ ex saved_g=*it; // save to restore it later
+
+ // try to contract first index
+ replacements=0;
+ if (first_idx.is_symbolic()) {
+ replacements = subs_index_in_exvector(v_contracted,
+ first_idx.toggle_covariant(),second_idx);
+ if (replacements==0) {
+ // not contracted, restore g object
+ *it=saved_g;
+ } else {
+ // a contracted index should occur exactly once
+ GINAC_ASSERT(replacements==1);
+ *it=_ex1();
+ something_changed=true;
+ }
+ }
+
+ // try second index only if first was not contracted
+ if ((replacements==0)&&(second_idx.is_symbolic())) {
+ // first index not contracted, *it is again the original g object
+ replacements = subs_index_in_exvector(v_contracted,
+ second_idx.toggle_covariant(),first_idx);
+ if (replacements==0) {
+ // not contracted except in itself, restore g object
+ *it=saved_g;
+ } else {
+ // a contracted index should occur exactly once
+ GINAC_ASSERT(replacements==1);
+ *it=_ex1();
+ something_changed=true;
+ }
+ }
+ }
+ ++it;
+ }
+ if (something_changed) {
+ return mul(v_contracted);
+ }
+ return m;
}
ex simplify_lortensor(const ex & e)
{
- // all simplification is done on expanded objects
- ex e_expanded=e.expand();
+ // all simplification is done on expanded objects
+ ex e_expanded=e.expand();
- // simplification of sum=sum of simplifications
- if (is_ex_exactly_of_type(e_expanded,add)) {
- ex sum=_ex0();
- for (unsigned i=0; i<e_expanded.nops(); ++i) {
- sum += simplify_lortensor(e_expanded.op(i));
- }
- return sum;
- }
+ // simplification of sum=sum of simplifications
+ if (is_ex_exactly_of_type(e_expanded,add)) {
+ ex sum=_ex0();
+ for (unsigned i=0; i<e_expanded.nops(); ++i) {
+ sum += simplify_lortensor(e_expanded.op(i));
+ }
+ return sum;
+ }
- // simplification of commutative product=commutative product of simplifications
- if (is_ex_exactly_of_type(e_expanded,mul)) {
- return simplify_lortensor_mul(e);
- }
+ // simplification of commutative product=commutative product of simplifications
+ if (is_ex_exactly_of_type(e_expanded,mul)) {
+ return simplify_lortensor_mul(e);
+ }
- // cannot do anything
- return e_expanded;
+ // cannot do anything
+ return e_expanded;
}
ex Dim(void)
{
- static symbol * d=new symbol("dim");
- return *d;
+ static symbol * d=new symbol("dim");
+ return *d;
}
//////////
/** Base class for lortensor object */
class lortensor : public indexed
{
- // friends
- friend lortensor lortensor_g(const ex & mu, const ex & nu);
- // friend lortensor lortensor_delta(const ex & mu, const ex & nu);
- friend lortensor lortensor_epsilon(const ex & mu, const ex & nu,
- const ex & rho, const ex & sigma);
- // friend lortensor lortensor_rankn(const string & n, const exvector & iv);
- friend lortensor lortensor_rank1(const std::string & n, const ex & mu);
- friend lortensor lortensor_rank2(const std::string & n, const ex & mu, const ex & nu);
- friend ex simplify_lortensor_mul(const ex & m);
- friend ex simplify_lortensor(const ex & e);
-
- // types
+ // friends
+ friend lortensor lortensor_g(const ex & mu, const ex & nu);
+ // friend lortensor lortensor_delta(const ex & mu, const ex & nu);
+ friend lortensor lortensor_epsilon(const ex & mu, const ex & nu,
+ const ex & rho, const ex & sigma);
+ // friend lortensor lortensor_rankn(const string & n, const exvector & iv);
+ friend lortensor lortensor_rank1(const std::string & n, const ex & mu);
+ friend lortensor lortensor_rank2(const std::string & n, const ex & mu, const ex & nu);
+ friend ex simplify_lortensor_mul(const ex & m);
+ friend ex simplify_lortensor(const ex & e);
+
+ // types
public:
- typedef enum { invalid,
- lortensor_g,
- lortensor_rankn,
- lortensor_rank1,
- lortensor_rank2,
- // lortensor_delta,
- lortensor_epsilon
- } lortensor_types;
-
- // member functions
-
- // default constructor, destructor, copy constructor assignment operator and helpers
+ typedef enum { invalid,
+ lortensor_g,
+ lortensor_rankn,
+ lortensor_rank1,
+ lortensor_rank2,
+ // lortensor_delta,
+ lortensor_epsilon
+ } lortensor_types;
+
+ // member functions
+
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- lortensor();
- ~lortensor();
- lortensor(const lortensor & other);
- const lortensor & operator=(const lortensor & other);
+ lortensor();
+ ~lortensor();
+ lortensor(const lortensor & other);
+ const lortensor & operator=(const lortensor & other);
protected:
- void copy(const lortensor & other);
- void destroy(bool call_parent);
+ void copy(const lortensor & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
protected:
- lortensor(lortensor_types const lt, const std::string & n);
- lortensor(lortensor_types const lt, const std::string & n, const ex & mu);
- lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu);
- lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu,
- const ex & rho);
- lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu, const ex & rho, const ex & sigma);
- lortensor(lortensor_types const lt, const std::string & n, const exvector & iv);
- lortensor(lortensor_types const lt, const std::string & n, unsigned s, const exvector & iv);
- lortensor(lortensor_types const lt, const std::string & n, unsigned s, exvector * ivp);
-
- //functions overriding virtual functions from base classes
+ lortensor(lortensor_types const lt, const std::string & n);
+ lortensor(lortensor_types const lt, const std::string & n, const ex & mu);
+ lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu);
+ lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu,
+ const ex & rho);
+ lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu, const ex & rho, const ex & sigma);
+ lortensor(lortensor_types const lt, const std::string & n, const exvector & iv);
+ lortensor(lortensor_types const lt, const std::string & n, unsigned s, const exvector & iv);
+ lortensor(lortensor_types const lt, const std::string & n, unsigned s, exvector * ivp);
+
+ //functions overriding virtual functions from base classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
- ex eval(int level=0) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
+ ex eval(int level=0) const;
protected:
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+ ex thisexprseq(const exvector & v) const;
+ ex thisexprseq(exvector * vp) const;
- // new virtual functions which can be overridden by derived classes
- // none
+ // new virtual functions which can be overridden by derived classes
+ // none
- //non virtual functions in this class
+ //non virtual functions in this class
public:
- void setname(const std::string & n);
- std::string getname(void) const {return name;}
+ void setname(const std::string & n);
+ std::string getname(void) const {return name;}
protected:
- bool all_of_type_lorentzidx(void) const;
+ bool all_of_type_lorentzidx(void) const;
private:
- std::string & autoname_prefix(void);
+ std::string & autoname_prefix(void);
- //member variables
+ //member variables
protected:
- lortensor_types type;
- std::string name;
- unsigned serial;
+ lortensor_types type;
+ std::string name;
+ unsigned serial;
private:
- static unsigned next_serial;
+ static unsigned next_serial;
};
// global constants
extern const type_info & typeid_lortensor;
// utility functions
-
+
inline const lortensor & ex_to_lortensor(const ex &e)
{
return static_cast<const lortensor &>(*e.bp);
bool lst::info(unsigned inf) const
{
- if (inf==info_flags::list) return 1;
- return basic::info(inf);
+ if (inf==info_flags::list) return 1;
+ return basic::info(inf);
}
#ifndef NO_NAMESPACE_GINAC
/** Default ctor. Initializes to 1 x 1-dimensional zero-matrix. */
matrix::matrix()
- : inherited(TINFO_matrix), row(1), col(1)
+ : inherited(TINFO_matrix), row(1), col(1)
{
- debugmsg("matrix default constructor",LOGLEVEL_CONSTRUCT);
- m.push_back(_ex0());
+ debugmsg("matrix default constructor",LOGLEVEL_CONSTRUCT);
+ m.push_back(_ex0());
}
matrix::~matrix()
{
- debugmsg("matrix destructor",LOGLEVEL_DESTRUCT);
+ debugmsg("matrix destructor",LOGLEVEL_DESTRUCT);
}
matrix::matrix(const matrix & other)
{
- debugmsg("matrix copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("matrix copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const matrix & matrix::operator=(const matrix & other)
{
- debugmsg("matrix operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("matrix operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void matrix::copy(const matrix & other)
{
- inherited::copy(other);
- row = other.row;
- col = other.col;
- m = other.m; // STL's vector copying invoked here
+ inherited::copy(other);
+ row = other.row;
+ col = other.col;
+ m = other.m; // STL's vector copying invoked here
}
void matrix::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
//////////
* @param r number of rows
* @param c number of cols */
matrix::matrix(unsigned r, unsigned c)
- : inherited(TINFO_matrix), row(r), col(c)
+ : inherited(TINFO_matrix), row(r), col(c)
{
- debugmsg("matrix constructor from unsigned,unsigned",LOGLEVEL_CONSTRUCT);
- m.resize(r*c, _ex0());
+ debugmsg("matrix constructor from unsigned,unsigned",LOGLEVEL_CONSTRUCT);
+ m.resize(r*c, _ex0());
}
// protected
/** Ctor from representation, for internal use only. */
matrix::matrix(unsigned r, unsigned c, const exvector & m2)
- : inherited(TINFO_matrix), row(r), col(c), m(m2)
+ : inherited(TINFO_matrix), row(r), col(c), m(m2)
{
- debugmsg("matrix constructor from unsigned,unsigned,exvector",LOGLEVEL_CONSTRUCT);
+ debugmsg("matrix constructor from unsigned,unsigned,exvector",LOGLEVEL_CONSTRUCT);
}
//////////
/** Construct object from archive_node. */
matrix::matrix(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("matrix constructor from archive_node", LOGLEVEL_CONSTRUCT);
- if (!(n.find_unsigned("row", row)) || !(n.find_unsigned("col", col)))
- throw (std::runtime_error("unknown matrix dimensions in archive"));
- m.reserve(row * col);
- for (unsigned int i=0; true; i++) {
- ex e;
- if (n.find_ex("m", e, sym_lst, i))
- m.push_back(e);
- else
- break;
- }
+ debugmsg("matrix constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ if (!(n.find_unsigned("row", row)) || !(n.find_unsigned("col", col)))
+ throw (std::runtime_error("unknown matrix dimensions in archive"));
+ m.reserve(row * col);
+ for (unsigned int i=0; true; i++) {
+ ex e;
+ if (n.find_ex("m", e, sym_lst, i))
+ m.push_back(e);
+ else
+ break;
+ }
}
/** Unarchive the object. */
ex matrix::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new matrix(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new matrix(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void matrix::archive(archive_node &n) const
{
- inherited::archive(n);
- n.add_unsigned("row", row);
- n.add_unsigned("col", col);
- exvector::const_iterator i = m.begin(), iend = m.end();
- while (i != iend) {
- n.add_ex("m", *i);
- ++i;
- }
+ inherited::archive(n);
+ n.add_unsigned("row", row);
+ n.add_unsigned("col", col);
+ exvector::const_iterator i = m.begin(), iend = m.end();
+ while (i != iend) {
+ n.add_ex("m", *i);
+ ++i;
+ }
}
//////////
basic * matrix::duplicate() const
{
- debugmsg("matrix duplicate",LOGLEVEL_DUPLICATE);
- return new matrix(*this);
+ debugmsg("matrix duplicate",LOGLEVEL_DUPLICATE);
+ return new matrix(*this);
}
void matrix::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("matrix print",LOGLEVEL_PRINT);
- os << "[[ ";
- for (unsigned r=0; r<row-1; ++r) {
- os << "[[";
- for (unsigned c=0; c<col-1; ++c)
- os << m[r*col+c] << ",";
- os << m[col*(r+1)-1] << "]], ";
- }
- os << "[[";
- for (unsigned c=0; c<col-1; ++c)
- os << m[(row-1)*col+c] << ",";
- os << m[row*col-1] << "]] ]]";
+ debugmsg("matrix print",LOGLEVEL_PRINT);
+ os << "[[ ";
+ for (unsigned r=0; r<row-1; ++r) {
+ os << "[[";
+ for (unsigned c=0; c<col-1; ++c)
+ os << m[r*col+c] << ",";
+ os << m[col*(r+1)-1] << "]], ";
+ }
+ os << "[[";
+ for (unsigned c=0; c<col-1; ++c)
+ os << m[(row-1)*col+c] << ",";
+ os << m[row*col-1] << "]] ]]";
}
void matrix::printraw(std::ostream & os) const
{
- debugmsg("matrix printraw",LOGLEVEL_PRINT);
- os << "matrix(" << row << "," << col <<",";
- for (unsigned r=0; r<row-1; ++r) {
- os << "(";
- for (unsigned c=0; c<col-1; ++c)
- os << m[r*col+c] << ",";
- os << m[col*(r-1)-1] << "),";
- }
- os << "(";
- for (unsigned c=0; c<col-1; ++c)
- os << m[(row-1)*col+c] << ",";
- os << m[row*col-1] << "))";
+ debugmsg("matrix printraw",LOGLEVEL_PRINT);
+ os << "matrix(" << row << "," << col <<",";
+ for (unsigned r=0; r<row-1; ++r) {
+ os << "(";
+ for (unsigned c=0; c<col-1; ++c)
+ os << m[r*col+c] << ",";
+ os << m[col*(r-1)-1] << "),";
+ }
+ os << "(";
+ for (unsigned c=0; c<col-1; ++c)
+ os << m[(row-1)*col+c] << ",";
+ os << m[row*col-1] << "))";
}
/** nops is defined to be rows x columns. */
unsigned matrix::nops() const
{
- return row*col;
+ return row*col;
}
/** returns matrix entry at position (i/col, i%col). */
ex matrix::op(int i) const
{
- return m[i];
+ return m[i];
}
/** returns matrix entry at position (i/col, i%col). */
ex & matrix::let_op(int i)
{
- GINAC_ASSERT(i>=0);
- GINAC_ASSERT(i<nops());
-
- return m[i];
+ GINAC_ASSERT(i>=0);
+ GINAC_ASSERT(i<nops());
+
+ return m[i];
}
/** expands the elements of a matrix entry by entry. */
ex matrix::expand(unsigned options) const
{
- exvector tmp(row*col);
- for (unsigned i=0; i<row*col; ++i)
- tmp[i] = m[i].expand(options);
-
- return matrix(row, col, tmp);
+ exvector tmp(row*col);
+ for (unsigned i=0; i<row*col; ++i)
+ tmp[i] = m[i].expand(options);
+
+ return matrix(row, col, tmp);
}
/** Search ocurrences. A matrix 'has' an expression if it is the expression
* itself or one of the elements 'has' it. */
bool matrix::has(const ex & other) const
{
- GINAC_ASSERT(other.bp!=0);
-
- // tautology: it is the expression itself
- if (is_equal(*other.bp)) return true;
-
- // search all the elements
- for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r)
- if ((*r).has(other)) return true;
-
- return false;
+ GINAC_ASSERT(other.bp!=0);
+
+ // tautology: it is the expression itself
+ if (is_equal(*other.bp)) return true;
+
+ // search all the elements
+ for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r)
+ if ((*r).has(other)) return true;
+
+ return false;
}
/** evaluate matrix entry by entry. */
ex matrix::eval(int level) const
{
- debugmsg("matrix eval",LOGLEVEL_MEMBER_FUNCTION);
-
- // check if we have to do anything at all
- if ((level==1)&&(flags & status_flags::evaluated))
- return *this;
-
- // emergency break
- if (level == -max_recursion_level)
- throw (std::runtime_error("matrix::eval(): recursion limit exceeded"));
-
- // eval() entry by entry
- exvector m2(row*col);
- --level;
- for (unsigned r=0; r<row; ++r)
- for (unsigned c=0; c<col; ++c)
- m2[r*col+c] = m[r*col+c].eval(level);
-
- return (new matrix(row, col, m2))->setflag(status_flags::dynallocated |
- status_flags::evaluated );
+ debugmsg("matrix eval",LOGLEVEL_MEMBER_FUNCTION);
+
+ // check if we have to do anything at all
+ if ((level==1)&&(flags & status_flags::evaluated))
+ return *this;
+
+ // emergency break
+ if (level == -max_recursion_level)
+ throw (std::runtime_error("matrix::eval(): recursion limit exceeded"));
+
+ // eval() entry by entry
+ exvector m2(row*col);
+ --level;
+ for (unsigned r=0; r<row; ++r)
+ for (unsigned c=0; c<col; ++c)
+ m2[r*col+c] = m[r*col+c].eval(level);
+
+ return (new matrix(row, col, m2))->setflag(status_flags::dynallocated |
+ status_flags::evaluated );
}
/** evaluate matrix numerically entry by entry. */
ex matrix::evalf(int level) const
{
- debugmsg("matrix evalf",LOGLEVEL_MEMBER_FUNCTION);
-
- // check if we have to do anything at all
- if (level==1)
- return *this;
-
- // emergency break
- if (level == -max_recursion_level) {
- throw (std::runtime_error("matrix::evalf(): recursion limit exceeded"));
- }
-
- // evalf() entry by entry
- exvector m2(row*col);
- --level;
- for (unsigned r=0; r<row; ++r)
- for (unsigned c=0; c<col; ++c)
- m2[r*col+c] = m[r*col+c].evalf(level);
-
- return matrix(row, col, m2);
+ debugmsg("matrix evalf",LOGLEVEL_MEMBER_FUNCTION);
+
+ // check if we have to do anything at all
+ if (level==1)
+ return *this;
+
+ // emergency break
+ if (level == -max_recursion_level) {
+ throw (std::runtime_error("matrix::evalf(): recursion limit exceeded"));
+ }
+
+ // evalf() entry by entry
+ exvector m2(row*col);
+ --level;
+ for (unsigned r=0; r<row; ++r)
+ for (unsigned c=0; c<col; ++c)
+ m2[r*col+c] = m[r*col+c].evalf(level);
+
+ return matrix(row, col, m2);
}
// protected
int matrix::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_exactly_of_type(other, matrix));
- const matrix & o = static_cast<matrix &>(const_cast<basic &>(other));
-
- // compare number of rows
- if (row != o.rows())
- return row < o.rows() ? -1 : 1;
-
- // compare number of columns
- if (col != o.cols())
- return col < o.cols() ? -1 : 1;
-
- // equal number of rows and columns, compare individual elements
- int cmpval;
- for (unsigned r=0; r<row; ++r) {
- for (unsigned c=0; c<col; ++c) {
- cmpval = ((*this)(r,c)).compare(o(r,c));
- if (cmpval!=0) return cmpval;
- }
- }
- // all elements are equal => matrices are equal;
- return 0;
+ GINAC_ASSERT(is_exactly_of_type(other, matrix));
+ const matrix & o = static_cast<matrix &>(const_cast<basic &>(other));
+
+ // compare number of rows
+ if (row != o.rows())
+ return row < o.rows() ? -1 : 1;
+
+ // compare number of columns
+ if (col != o.cols())
+ return col < o.cols() ? -1 : 1;
+
+ // equal number of rows and columns, compare individual elements
+ int cmpval;
+ for (unsigned r=0; r<row; ++r) {
+ for (unsigned c=0; c<col; ++c) {
+ cmpval = ((*this)(r,c)).compare(o(r,c));
+ if (cmpval!=0) return cmpval;
+ }
+ }
+ // all elements are equal => matrices are equal;
+ return 0;
}
//////////
* @exception logic_error (incompatible matrices) */
matrix matrix::add(const matrix & other) const
{
- if (col != other.col || row != other.row)
- throw (std::logic_error("matrix::add(): incompatible matrices"));
-
- exvector sum(this->m);
- exvector::iterator i;
- exvector::const_iterator ci;
- for (i=sum.begin(), ci=other.m.begin(); i!=sum.end(); ++i, ++ci)
- (*i) += (*ci);
-
- return matrix(row,col,sum);
+ if (col != other.col || row != other.row)
+ throw (std::logic_error("matrix::add(): incompatible matrices"));
+
+ exvector sum(this->m);
+ exvector::iterator i;
+ exvector::const_iterator ci;
+ for (i=sum.begin(), ci=other.m.begin(); i!=sum.end(); ++i, ++ci)
+ (*i) += (*ci);
+
+ return matrix(row,col,sum);
}
* @exception logic_error (incompatible matrices) */
matrix matrix::sub(const matrix & other) const
{
- if (col != other.col || row != other.row)
- throw (std::logic_error("matrix::sub(): incompatible matrices"));
-
- exvector dif(this->m);
- exvector::iterator i;
- exvector::const_iterator ci;
- for (i=dif.begin(), ci=other.m.begin(); i!=dif.end(); ++i, ++ci)
- (*i) -= (*ci);
-
- return matrix(row,col,dif);
+ if (col != other.col || row != other.row)
+ throw (std::logic_error("matrix::sub(): incompatible matrices"));
+
+ exvector dif(this->m);
+ exvector::iterator i;
+ exvector::const_iterator ci;
+ for (i=dif.begin(), ci=other.m.begin(); i!=dif.end(); ++i, ++ci)
+ (*i) -= (*ci);
+
+ return matrix(row,col,dif);
}
* @exception logic_error (incompatible matrices) */
matrix matrix::mul(const matrix & other) const
{
- if (this->cols() != other.rows())
- throw (std::logic_error("matrix::mul(): incompatible matrices"));
-
- exvector prod(this->rows()*other.cols());
-
- for (unsigned r1=0; r1<this->rows(); ++r1) {
- for (unsigned c=0; c<this->cols(); ++c) {
- if (m[r1*col+c].is_zero())
- continue;
- for (unsigned r2=0; r2<other.cols(); ++r2)
- prod[r1*other.col+r2] += (m[r1*col+c] * other.m[c*other.col+r2]).expand();
- }
- }
- return matrix(row, other.col, prod);
+ if (this->cols() != other.rows())
+ throw (std::logic_error("matrix::mul(): incompatible matrices"));
+
+ exvector prod(this->rows()*other.cols());
+
+ for (unsigned r1=0; r1<this->rows(); ++r1) {
+ for (unsigned c=0; c<this->cols(); ++c) {
+ if (m[r1*col+c].is_zero())
+ continue;
+ for (unsigned r2=0; r2<other.cols(); ++r2)
+ prod[r1*other.col+r2] += (m[r1*col+c] * other.m[c*other.col+r2]).expand();
+ }
+ }
+ return matrix(row, other.col, prod);
}
* @exception range_error (index out of range) */
const ex & matrix::operator() (unsigned ro, unsigned co) const
{
- if (ro<0 || ro>=row || co<0 || co>=col)
- throw (std::range_error("matrix::operator(): index out of range"));
+ if (ro<0 || ro>=row || co<0 || co>=col)
+ throw (std::range_error("matrix::operator(): index out of range"));
- return m[ro*col+co];
+ return m[ro*col+co];
}
* @exception range_error (index out of range) */
matrix & matrix::set(unsigned ro, unsigned co, ex value)
{
- if (ro<0 || ro>=row || co<0 || co>=col)
- throw (std::range_error("matrix::set(): index out of range"));
-
- ensure_if_modifiable();
- m[ro*col+co] = value;
- return *this;
+ if (ro<0 || ro>=row || co<0 || co>=col)
+ throw (std::range_error("matrix::set(): index out of range"));
+
+ ensure_if_modifiable();
+ m[ro*col+co] = value;
+ return *this;
}
* represents the transposed. */
matrix matrix::transpose(void) const
{
- exvector trans(this->cols()*this->rows());
-
- for (unsigned r=0; r<this->cols(); ++r)
- for (unsigned c=0; c<this->rows(); ++c)
- trans[r*this->rows()+c] = m[c*this->cols()+r];
-
- return matrix(this->cols(),this->rows(),trans);
+ exvector trans(this->cols()*this->rows());
+
+ for (unsigned r=0; r<this->cols(); ++r)
+ for (unsigned c=0; c<this->rows(); ++c)
+ trans[r*this->rows()+c] = m[c*this->cols()+r];
+
+ return matrix(this->cols(),this->rows(),trans);
}
* @see determinant_algo */
ex matrix::determinant(unsigned algo) const
{
- if (row!=col)
- throw (std::logic_error("matrix::determinant(): matrix not square"));
- GINAC_ASSERT(row*col==m.capacity());
-
- // Gather some statistical information about this matrix:
- bool numeric_flag = true;
- bool normal_flag = false;
- unsigned sparse_count = 0; // counts non-zero elements
- for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) {
- lst srl; // symbol replacement list
- ex rtest = (*r).to_rational(srl);
- if (!rtest.is_zero())
- ++sparse_count;
- if (!rtest.info(info_flags::numeric))
- numeric_flag = false;
- if (!rtest.info(info_flags::crational_polynomial) &&
- rtest.info(info_flags::rational_function))
- normal_flag = true;
- }
-
- // Here is the heuristics in case this routine has to decide:
- if (algo == determinant_algo::automatic) {
- // Minor expansion is generally a good guess:
- algo = determinant_algo::laplace;
- // Does anybody know when a matrix is really sparse?
- // Maybe <~row/2.236 nonzero elements average in a row?
- if (row>3 && 5*sparse_count<=row*col)
- algo = determinant_algo::bareiss;
- // Purely numeric matrix can be handled by Gauss elimination.
- // This overrides any prior decisions.
- if (numeric_flag)
- algo = determinant_algo::gauss;
- }
-
- // Trap the trivial case here, since some algorithms don't like it
- if (this->row==1) {
- // for consistency with non-trivial determinants...
- if (normal_flag)
- return m[0].normal();
- else
- return m[0].expand();
- }
-
- // Compute the determinant
- switch(algo) {
- case determinant_algo::gauss: {
- ex det = 1;
- matrix tmp(*this);
- int sign = tmp.gauss_elimination(true);
- for (unsigned d=0; d<row; ++d)
- det *= tmp.m[d*col+d];
- if (normal_flag)
- return (sign*det).normal();
- else
- return (sign*det).normal().expand();
- }
- case determinant_algo::bareiss: {
- matrix tmp(*this);
- int sign;
- sign = tmp.fraction_free_elimination(true);
- if (normal_flag)
- return (sign*tmp.m[row*col-1]).normal();
- else
- return (sign*tmp.m[row*col-1]).expand();
- }
- case determinant_algo::divfree: {
- matrix tmp(*this);
- int sign;
- sign = tmp.division_free_elimination(true);
- if (sign==0)
- return _ex0();
- ex det = tmp.m[row*col-1];
- // factor out accumulated bogus slag
- for (unsigned d=0; d<row-2; ++d)
- for (unsigned j=0; j<row-d-2; ++j)
- det = (det/tmp.m[d*col+d]).normal();
- return (sign*det);
- }
- case determinant_algo::laplace:
- default: {
- // This is the minor expansion scheme. We always develop such
- // that the smallest minors (i.e, the trivial 1x1 ones) are on the
- // rightmost column. For this to be efficient it turns out that
- // the emptiest columns (i.e. the ones with most zeros) should be
- // the ones on the right hand side. Therefore we presort the
- // columns of the matrix:
- typedef std::pair<unsigned,unsigned> uintpair;
- std::vector<uintpair> c_zeros; // number of zeros in column
- for (unsigned c=0; c<col; ++c) {
- unsigned acc = 0;
- for (unsigned r=0; r<row; ++r)
- if (m[r*col+c].is_zero())
- ++acc;
- c_zeros.push_back(uintpair(acc,c));
- }
- sort(c_zeros.begin(),c_zeros.end());
- std::vector<unsigned> pre_sort;
- for (std::vector<uintpair>::iterator i=c_zeros.begin(); i!=c_zeros.end(); ++i)
- pre_sort.push_back(i->second);
- int sign = permutation_sign(pre_sort);
- exvector result(row*col); // represents sorted matrix
- unsigned c = 0;
- for (std::vector<unsigned>::iterator i=pre_sort.begin();
- i!=pre_sort.end();
- ++i,++c) {
- for (unsigned r=0; r<row; ++r)
- result[r*col+c] = m[r*col+(*i)];
- }
-
- if (normal_flag)
- return (sign*matrix(row,col,result).determinant_minor()).normal();
- else
- return sign*matrix(row,col,result).determinant_minor();
- }
- }
+ if (row!=col)
+ throw (std::logic_error("matrix::determinant(): matrix not square"));
+ GINAC_ASSERT(row*col==m.capacity());
+
+ // Gather some statistical information about this matrix:
+ bool numeric_flag = true;
+ bool normal_flag = false;
+ unsigned sparse_count = 0; // counts non-zero elements
+ for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) {
+ lst srl; // symbol replacement list
+ ex rtest = (*r).to_rational(srl);
+ if (!rtest.is_zero())
+ ++sparse_count;
+ if (!rtest.info(info_flags::numeric))
+ numeric_flag = false;
+ if (!rtest.info(info_flags::crational_polynomial) &&
+ rtest.info(info_flags::rational_function))
+ normal_flag = true;
+ }
+
+ // Here is the heuristics in case this routine has to decide:
+ if (algo == determinant_algo::automatic) {
+ // Minor expansion is generally a good guess:
+ algo = determinant_algo::laplace;
+ // Does anybody know when a matrix is really sparse?
+ // Maybe <~row/2.236 nonzero elements average in a row?
+ if (row>3 && 5*sparse_count<=row*col)
+ algo = determinant_algo::bareiss;
+ // Purely numeric matrix can be handled by Gauss elimination.
+ // This overrides any prior decisions.
+ if (numeric_flag)
+ algo = determinant_algo::gauss;
+ }
+
+ // Trap the trivial case here, since some algorithms don't like it
+ if (this->row==1) {
+ // for consistency with non-trivial determinants...
+ if (normal_flag)
+ return m[0].normal();
+ else
+ return m[0].expand();
+ }
+
+ // Compute the determinant
+ switch(algo) {
+ case determinant_algo::gauss: {
+ ex det = 1;
+ matrix tmp(*this);
+ int sign = tmp.gauss_elimination(true);
+ for (unsigned d=0; d<row; ++d)
+ det *= tmp.m[d*col+d];
+ if (normal_flag)
+ return (sign*det).normal();
+ else
+ return (sign*det).normal().expand();
+ }
+ case determinant_algo::bareiss: {
+ matrix tmp(*this);
+ int sign;
+ sign = tmp.fraction_free_elimination(true);
+ if (normal_flag)
+ return (sign*tmp.m[row*col-1]).normal();
+ else
+ return (sign*tmp.m[row*col-1]).expand();
+ }
+ case determinant_algo::divfree: {
+ matrix tmp(*this);
+ int sign;
+ sign = tmp.division_free_elimination(true);
+ if (sign==0)
+ return _ex0();
+ ex det = tmp.m[row*col-1];
+ // factor out accumulated bogus slag
+ for (unsigned d=0; d<row-2; ++d)
+ for (unsigned j=0; j<row-d-2; ++j)
+ det = (det/tmp.m[d*col+d]).normal();
+ return (sign*det);
+ }
+ case determinant_algo::laplace:
+ default: {
+ // This is the minor expansion scheme. We always develop such
+ // that the smallest minors (i.e, the trivial 1x1 ones) are on the
+ // rightmost column. For this to be efficient it turns out that
+ // the emptiest columns (i.e. the ones with most zeros) should be
+ // the ones on the right hand side. Therefore we presort the
+ // columns of the matrix:
+ typedef std::pair<unsigned,unsigned> uintpair;
+ std::vector<uintpair> c_zeros; // number of zeros in column
+ for (unsigned c=0; c<col; ++c) {
+ unsigned acc = 0;
+ for (unsigned r=0; r<row; ++r)
+ if (m[r*col+c].is_zero())
+ ++acc;
+ c_zeros.push_back(uintpair(acc,c));
+ }
+ sort(c_zeros.begin(),c_zeros.end());
+ std::vector<unsigned> pre_sort;
+ for (std::vector<uintpair>::iterator i=c_zeros.begin(); i!=c_zeros.end(); ++i)
+ pre_sort.push_back(i->second);
+ int sign = permutation_sign(pre_sort);
+ exvector result(row*col); // represents sorted matrix
+ unsigned c = 0;
+ for (std::vector<unsigned>::iterator i=pre_sort.begin();
+ i!=pre_sort.end();
+ ++i,++c) {
+ for (unsigned r=0; r<row; ++r)
+ result[r*col+c] = m[r*col+(*i)];
+ }
+
+ if (normal_flag)
+ return (sign*matrix(row,col,result).determinant_minor()).normal();
+ else
+ return sign*matrix(row,col,result).determinant_minor();
+ }
+ }
}
* @exception logic_error (matrix not square) */
ex matrix::trace(void) const
{
- if (row != col)
- throw (std::logic_error("matrix::trace(): matrix not square"));
-
- ex tr;
- for (unsigned r=0; r<col; ++r)
- tr += m[r*col+r];
-
- if (tr.info(info_flags::rational_function) &&
- !tr.info(info_flags::crational_polynomial))
- return tr.normal();
- else
- return tr.expand();
+ if (row != col)
+ throw (std::logic_error("matrix::trace(): matrix not square"));
+
+ ex tr;
+ for (unsigned r=0; r<col; ++r)
+ tr += m[r*col+r];
+
+ if (tr.info(info_flags::rational_function) &&
+ !tr.info(info_flags::crational_polynomial))
+ return tr.normal();
+ else
+ return tr.expand();
}
* @see matrix::determinant() */
ex matrix::charpoly(const symbol & lambda) const
{
- if (row != col)
- throw (std::logic_error("matrix::charpoly(): matrix not square"));
-
- bool numeric_flag = true;
- for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) {
- if (!(*r).info(info_flags::numeric)) {
- numeric_flag = false;
- }
- }
-
- // The pure numeric case is traditionally rather common. Hence, it is
- // trapped and we use Leverrier's algorithm which goes as row^3 for
- // every coefficient. The expensive part is the matrix multiplication.
- if (numeric_flag) {
- matrix B(*this);
- ex c = B.trace();
- ex poly = power(lambda,row)-c*power(lambda,row-1);
- for (unsigned i=1; i<row; ++i) {
- for (unsigned j=0; j<row; ++j)
- B.m[j*col+j] -= c;
- B = this->mul(B);
- c = B.trace()/ex(i+1);
- poly -= c*power(lambda,row-i-1);
- }
- if (row%2)
- return -poly;
- else
- return poly;
- }
-
- matrix M(*this);
- for (unsigned r=0; r<col; ++r)
- M.m[r*col+r] -= lambda;
-
- return M.determinant().collect(lambda);
+ if (row != col)
+ throw (std::logic_error("matrix::charpoly(): matrix not square"));
+
+ bool numeric_flag = true;
+ for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) {
+ if (!(*r).info(info_flags::numeric)) {
+ numeric_flag = false;
+ }
+ }
+
+ // The pure numeric case is traditionally rather common. Hence, it is
+ // trapped and we use Leverrier's algorithm which goes as row^3 for
+ // every coefficient. The expensive part is the matrix multiplication.
+ if (numeric_flag) {
+ matrix B(*this);
+ ex c = B.trace();
+ ex poly = power(lambda,row)-c*power(lambda,row-1);
+ for (unsigned i=1; i<row; ++i) {
+ for (unsigned j=0; j<row; ++j)
+ B.m[j*col+j] -= c;
+ B = this->mul(B);
+ c = B.trace()/ex(i+1);
+ poly -= c*power(lambda,row-i-1);
+ }
+ if (row%2)
+ return -poly;
+ else
+ return poly;
+ }
+
+ matrix M(*this);
+ for (unsigned r=0; r<col; ++r)
+ M.m[r*col+r] -= lambda;
+
+ return M.determinant().collect(lambda);
}
* @exception runtime_error (singular matrix) */
matrix matrix::inverse(void) const
{
- if (row != col)
- throw (std::logic_error("matrix::inverse(): matrix not square"));
-
- // NOTE: the Gauss-Jordan elimination used here can in principle be
- // replaced this by two clever calls to gauss_elimination() and some to
- // transpose(). Wouldn't be more efficient (maybe less?), just more
- // orthogonal.
- matrix tmp(row,col);
- // set tmp to the unit matrix
- for (unsigned i=0; i<col; ++i)
- tmp.m[i*col+i] = _ex1();
-
- // create a copy of this matrix
- matrix cpy(*this);
- for (unsigned r1=0; r1<row; ++r1) {
- int indx = cpy.pivot(r1, r1);
- if (indx == -1) {
- throw (std::runtime_error("matrix::inverse(): singular matrix"));
- }
- if (indx != 0) { // swap rows r and indx of matrix tmp
- for (unsigned i=0; i<col; ++i)
- tmp.m[r1*col+i].swap(tmp.m[indx*col+i]);
- }
- ex a1 = cpy.m[r1*col+r1];
- for (unsigned c=0; c<col; ++c) {
- cpy.m[r1*col+c] /= a1;
- tmp.m[r1*col+c] /= a1;
- }
- for (unsigned r2=0; r2<row; ++r2) {
- if (r2 != r1) {
- ex a2 = cpy.m[r2*col+r1];
- for (unsigned c=0; c<col; ++c) {
- cpy.m[r2*col+c] -= a2 * cpy.m[r1*col+c];
- if (!cpy.m[r2*col+c].info(info_flags::numeric))
- cpy.m[r2*col+c] = cpy.m[r2*col+c].normal();
- tmp.m[r2*col+c] -= a2 * tmp.m[r1*col+c];
- if (!tmp.m[r2*col+c].info(info_flags::numeric))
- tmp.m[r2*col+c] = tmp.m[r2*col+c].normal();
- }
- }
- }
- }
-
- return tmp;
+ if (row != col)
+ throw (std::logic_error("matrix::inverse(): matrix not square"));
+
+ // NOTE: the Gauss-Jordan elimination used here can in principle be
+ // replaced this by two clever calls to gauss_elimination() and some to
+ // transpose(). Wouldn't be more efficient (maybe less?), just more
+ // orthogonal.
+ matrix tmp(row,col);
+ // set tmp to the unit matrix
+ for (unsigned i=0; i<col; ++i)
+ tmp.m[i*col+i] = _ex1();
+
+ // create a copy of this matrix
+ matrix cpy(*this);
+ for (unsigned r1=0; r1<row; ++r1) {
+ int indx = cpy.pivot(r1, r1);
+ if (indx == -1) {
+ throw (std::runtime_error("matrix::inverse(): singular matrix"));
+ }
+ if (indx != 0) { // swap rows r and indx of matrix tmp
+ for (unsigned i=0; i<col; ++i)
+ tmp.m[r1*col+i].swap(tmp.m[indx*col+i]);
+ }
+ ex a1 = cpy.m[r1*col+r1];
+ for (unsigned c=0; c<col; ++c) {
+ cpy.m[r1*col+c] /= a1;
+ tmp.m[r1*col+c] /= a1;
+ }
+ for (unsigned r2=0; r2<row; ++r2) {
+ if (r2 != r1) {
+ ex a2 = cpy.m[r2*col+r1];
+ for (unsigned c=0; c<col; ++c) {
+ cpy.m[r2*col+c] -= a2 * cpy.m[r1*col+c];
+ if (!cpy.m[r2*col+c].info(info_flags::numeric))
+ cpy.m[r2*col+c] = cpy.m[r2*col+c].normal();
+ tmp.m[r2*col+c] -= a2 * tmp.m[r1*col+c];
+ if (!tmp.m[r2*col+c].info(info_flags::numeric))
+ tmp.m[r2*col+c] = tmp.m[r2*col+c].normal();
+ }
+ }
+ }
+ }
+
+ return tmp;
}
* @exception runtime_error (inconsistent linear system)
* @see solve_algo */
matrix matrix::solve(const matrix & vars,
- const matrix & rhs,
- unsigned algo) const
+ const matrix & rhs,
+ unsigned algo) const
{
- const unsigned m = this->rows();
- const unsigned n = this->cols();
- const unsigned p = rhs.cols();
-
- // syntax checks
- if ((rhs.rows() != m) || (vars.rows() != n) || (vars.col != p))
- throw (std::logic_error("matrix::solve(): incompatible matrices"));
- for (unsigned ro=0; ro<n; ++ro)
- for (unsigned co=0; co<p; ++co)
- if (!vars(ro,co).info(info_flags::symbol))
- throw (std::invalid_argument("matrix::solve(): 1st argument must be matrix of symbols"));
-
- // build the augmented matrix of *this with rhs attached to the right
- matrix aug(m,n+p);
- for (unsigned r=0; r<m; ++r) {
- for (unsigned c=0; c<n; ++c)
- aug.m[r*(n+p)+c] = this->m[r*n+c];
- for (unsigned c=0; c<p; ++c)
- aug.m[r*(n+p)+c+n] = rhs.m[r*p+c];
- }
-
- // Gather some statistical information about the augmented matrix:
- bool numeric_flag = true;
- for (exvector::const_iterator r=aug.m.begin(); r!=aug.m.end(); ++r) {
- if (!(*r).info(info_flags::numeric))
- numeric_flag = false;
- }
-
- // Here is the heuristics in case this routine has to decide:
- if (algo == solve_algo::automatic) {
- // Bareiss (fraction-free) elimination is generally a good guess:
- algo = solve_algo::bareiss;
- // For m<3, Bareiss elimination is equivalent to division free
- // elimination but has more logistic overhead
- if (m<3)
- algo = solve_algo::divfree;
- // This overrides any prior decisions.
- if (numeric_flag)
- algo = solve_algo::gauss;
- }
-
- // Eliminate the augmented matrix:
- switch(algo) {
- case solve_algo::gauss:
- aug.gauss_elimination();
- case solve_algo::divfree:
- aug.division_free_elimination();
- case solve_algo::bareiss:
- default:
- aug.fraction_free_elimination();
- }
-
- // assemble the solution matrix:
- matrix sol(n,p);
- for (unsigned co=0; co<p; ++co) {
- unsigned last_assigned_sol = n+1;
- for (int r=m-1; r>=0; --r) {
- unsigned fnz = 1; // first non-zero in row
- while ((fnz<=n) && (aug.m[r*(n+p)+(fnz-1)].is_zero()))
- ++fnz;
- if (fnz>n) {
- // row consists only of zeros, corresponding rhs must be 0, too
- if (!aug.m[r*(n+p)+n+co].is_zero()) {
- throw (std::runtime_error("matrix::solve(): inconsistent linear system"));
- }
- } else {
- // assign solutions for vars between fnz+1 and
- // last_assigned_sol-1: free parameters
- for (unsigned c=fnz; c<last_assigned_sol-1; ++c)
- sol.set(c,co,vars.m[c*p+co]);
- ex e = aug.m[r*(n+p)+n+co];
- for (unsigned c=fnz; c<n; ++c)
- e -= aug.m[r*(n+p)+c]*sol.m[c*p+co];
- sol.set(fnz-1,co,
- (e/(aug.m[r*(n+p)+(fnz-1)])).normal());
- last_assigned_sol = fnz;
- }
- }
- // assign solutions for vars between 1 and
- // last_assigned_sol-1: free parameters
- for (unsigned ro=0; ro<last_assigned_sol-1; ++ro)
- sol.set(ro,co,vars(ro,co));
- }
-
- return sol;
+ const unsigned m = this->rows();
+ const unsigned n = this->cols();
+ const unsigned p = rhs.cols();
+
+ // syntax checks
+ if ((rhs.rows() != m) || (vars.rows() != n) || (vars.col != p))
+ throw (std::logic_error("matrix::solve(): incompatible matrices"));
+ for (unsigned ro=0; ro<n; ++ro)
+ for (unsigned co=0; co<p; ++co)
+ if (!vars(ro,co).info(info_flags::symbol))
+ throw (std::invalid_argument("matrix::solve(): 1st argument must be matrix of symbols"));
+
+ // build the augmented matrix of *this with rhs attached to the right
+ matrix aug(m,n+p);
+ for (unsigned r=0; r<m; ++r) {
+ for (unsigned c=0; c<n; ++c)
+ aug.m[r*(n+p)+c] = this->m[r*n+c];
+ for (unsigned c=0; c<p; ++c)
+ aug.m[r*(n+p)+c+n] = rhs.m[r*p+c];
+ }
+
+ // Gather some statistical information about the augmented matrix:
+ bool numeric_flag = true;
+ for (exvector::const_iterator r=aug.m.begin(); r!=aug.m.end(); ++r) {
+ if (!(*r).info(info_flags::numeric))
+ numeric_flag = false;
+ }
+
+ // Here is the heuristics in case this routine has to decide:
+ if (algo == solve_algo::automatic) {
+ // Bareiss (fraction-free) elimination is generally a good guess:
+ algo = solve_algo::bareiss;
+ // For m<3, Bareiss elimination is equivalent to division free
+ // elimination but has more logistic overhead
+ if (m<3)
+ algo = solve_algo::divfree;
+ // This overrides any prior decisions.
+ if (numeric_flag)
+ algo = solve_algo::gauss;
+ }
+
+ // Eliminate the augmented matrix:
+ switch(algo) {
+ case solve_algo::gauss:
+ aug.gauss_elimination();
+ case solve_algo::divfree:
+ aug.division_free_elimination();
+ case solve_algo::bareiss:
+ default:
+ aug.fraction_free_elimination();
+ }
+
+ // assemble the solution matrix:
+ matrix sol(n,p);
+ for (unsigned co=0; co<p; ++co) {
+ unsigned last_assigned_sol = n+1;
+ for (int r=m-1; r>=0; --r) {
+ unsigned fnz = 1; // first non-zero in row
+ while ((fnz<=n) && (aug.m[r*(n+p)+(fnz-1)].is_zero()))
+ ++fnz;
+ if (fnz>n) {
+ // row consists only of zeros, corresponding rhs must be 0, too
+ if (!aug.m[r*(n+p)+n+co].is_zero()) {
+ throw (std::runtime_error("matrix::solve(): inconsistent linear system"));
+ }
+ } else {
+ // assign solutions for vars between fnz+1 and
+ // last_assigned_sol-1: free parameters
+ for (unsigned c=fnz; c<last_assigned_sol-1; ++c)
+ sol.set(c,co,vars.m[c*p+co]);
+ ex e = aug.m[r*(n+p)+n+co];
+ for (unsigned c=fnz; c<n; ++c)
+ e -= aug.m[r*(n+p)+c]*sol.m[c*p+co];
+ sol.set(fnz-1,co,
+ (e/(aug.m[r*(n+p)+(fnz-1)])).normal());
+ last_assigned_sol = fnz;
+ }
+ }
+ // assign solutions for vars between 1 and
+ // last_assigned_sol-1: free parameters
+ for (unsigned ro=0; ro<last_assigned_sol-1; ++ro)
+ sol.set(ro,co,vars(ro,co));
+ }
+
+ return sol;
}
* @see matrix::determinant() */
ex matrix::determinant_minor(void) const
{
- // for small matrices the algorithm does not make any sense:
- const unsigned n = this->cols();
- if (n==1)
- return m[0].expand();
- if (n==2)
- return (m[0]*m[3]-m[2]*m[1]).expand();
- if (n==3)
- return (m[0]*m[4]*m[8]-m[0]*m[5]*m[7]-
- m[1]*m[3]*m[8]+m[2]*m[3]*m[7]+
- m[1]*m[5]*m[6]-m[2]*m[4]*m[6]).expand();
-
- // This algorithm can best be understood by looking at a naive
- // implementation of Laplace-expansion, like this one:
- // ex det;
- // matrix minorM(this->rows()-1,this->cols()-1);
- // for (unsigned r1=0; r1<this->rows(); ++r1) {
- // // shortcut if element(r1,0) vanishes
- // if (m[r1*col].is_zero())
- // continue;
- // // assemble the minor matrix
- // for (unsigned r=0; r<minorM.rows(); ++r) {
- // for (unsigned c=0; c<minorM.cols(); ++c) {
- // if (r<r1)
- // minorM.set(r,c,m[r*col+c+1]);
- // else
- // minorM.set(r,c,m[(r+1)*col+c+1]);
- // }
- // }
- // // recurse down and care for sign:
- // if (r1%2)
- // det -= m[r1*col] * minorM.determinant_minor();
- // else
- // det += m[r1*col] * minorM.determinant_minor();
- // }
- // return det.expand();
- // What happens is that while proceeding down many of the minors are
- // computed more than once. In particular, there are binomial(n,k)
- // kxk minors and each one is computed factorial(n-k) times. Therefore
- // it is reasonable to store the results of the minors. We proceed from
- // right to left. At each column c we only need to retrieve the minors
- // calculated in step c-1. We therefore only have to store at most
- // 2*binomial(n,n/2) minors.
-
- // Unique flipper counter for partitioning into minors
- std::vector<unsigned> Pkey;
- Pkey.reserve(n);
- // key for minor determinant (a subpartition of Pkey)
- std::vector<unsigned> Mkey;
- Mkey.reserve(n-1);
- // we store our subminors in maps, keys being the rows they arise from
- typedef std::map<std::vector<unsigned>,class ex> Rmap;
- typedef std::map<std::vector<unsigned>,class ex>::value_type Rmap_value;
- Rmap A;
- Rmap B;
- ex det;
- // initialize A with last column:
- for (unsigned r=0; r<n; ++r) {
- Pkey.erase(Pkey.begin(),Pkey.end());
- Pkey.push_back(r);
- A.insert(Rmap_value(Pkey,m[n*(r+1)-1]));
- }
- // proceed from right to left through matrix
- for (int c=n-2; c>=0; --c) {
- Pkey.erase(Pkey.begin(),Pkey.end()); // don't change capacity
- Mkey.erase(Mkey.begin(),Mkey.end());
- for (unsigned i=0; i<n-c; ++i)
- Pkey.push_back(i);
- unsigned fc = 0; // controls logic for our strange flipper counter
- do {
- det = _ex0();
- for (unsigned r=0; r<n-c; ++r) {
- // maybe there is nothing to do?
- if (m[Pkey[r]*n+c].is_zero())
- continue;
- // create the sorted key for all possible minors
- Mkey.erase(Mkey.begin(),Mkey.end());
- for (unsigned i=0; i<n-c; ++i)
- if (i!=r)
- Mkey.push_back(Pkey[i]);
- // Fetch the minors and compute the new determinant
- if (r%2)
- det -= m[Pkey[r]*n+c]*A[Mkey];
- else
- det += m[Pkey[r]*n+c]*A[Mkey];
- }
- // prevent build-up of deep nesting of expressions saves time:
- det = det.expand();
- // store the new determinant at its place in B:
- if (!det.is_zero())
- B.insert(Rmap_value(Pkey,det));
- // increment our strange flipper counter
- for (fc=n-c; fc>0; --fc) {
- ++Pkey[fc-1];
- if (Pkey[fc-1]<fc+c)
- break;
- }
- if (fc<n-c)
- for (unsigned j=fc; j<n-c; ++j)
- Pkey[j] = Pkey[j-1]+1;
- } while(fc);
- // next column, so change the role of A and B:
- A = B;
- B.clear();
- }
-
- return det;
+ // for small matrices the algorithm does not make any sense:
+ const unsigned n = this->cols();
+ if (n==1)
+ return m[0].expand();
+ if (n==2)
+ return (m[0]*m[3]-m[2]*m[1]).expand();
+ if (n==3)
+ return (m[0]*m[4]*m[8]-m[0]*m[5]*m[7]-
+ m[1]*m[3]*m[8]+m[2]*m[3]*m[7]+
+ m[1]*m[5]*m[6]-m[2]*m[4]*m[6]).expand();
+
+ // This algorithm can best be understood by looking at a naive
+ // implementation of Laplace-expansion, like this one:
+ // ex det;
+ // matrix minorM(this->rows()-1,this->cols()-1);
+ // for (unsigned r1=0; r1<this->rows(); ++r1) {
+ // // shortcut if element(r1,0) vanishes
+ // if (m[r1*col].is_zero())
+ // continue;
+ // // assemble the minor matrix
+ // for (unsigned r=0; r<minorM.rows(); ++r) {
+ // for (unsigned c=0; c<minorM.cols(); ++c) {
+ // if (r<r1)
+ // minorM.set(r,c,m[r*col+c+1]);
+ // else
+ // minorM.set(r,c,m[(r+1)*col+c+1]);
+ // }
+ // }
+ // // recurse down and care for sign:
+ // if (r1%2)
+ // det -= m[r1*col] * minorM.determinant_minor();
+ // else
+ // det += m[r1*col] * minorM.determinant_minor();
+ // }
+ // return det.expand();
+ // What happens is that while proceeding down many of the minors are
+ // computed more than once. In particular, there are binomial(n,k)
+ // kxk minors and each one is computed factorial(n-k) times. Therefore
+ // it is reasonable to store the results of the minors. We proceed from
+ // right to left. At each column c we only need to retrieve the minors
+ // calculated in step c-1. We therefore only have to store at most
+ // 2*binomial(n,n/2) minors.
+
+ // Unique flipper counter for partitioning into minors
+ std::vector<unsigned> Pkey;
+ Pkey.reserve(n);
+ // key for minor determinant (a subpartition of Pkey)
+ std::vector<unsigned> Mkey;
+ Mkey.reserve(n-1);
+ // we store our subminors in maps, keys being the rows they arise from
+ typedef std::map<std::vector<unsigned>,class ex> Rmap;
+ typedef std::map<std::vector<unsigned>,class ex>::value_type Rmap_value;
+ Rmap A;
+ Rmap B;
+ ex det;
+ // initialize A with last column:
+ for (unsigned r=0; r<n; ++r) {
+ Pkey.erase(Pkey.begin(),Pkey.end());
+ Pkey.push_back(r);
+ A.insert(Rmap_value(Pkey,m[n*(r+1)-1]));
+ }
+ // proceed from right to left through matrix
+ for (int c=n-2; c>=0; --c) {
+ Pkey.erase(Pkey.begin(),Pkey.end()); // don't change capacity
+ Mkey.erase(Mkey.begin(),Mkey.end());
+ for (unsigned i=0; i<n-c; ++i)
+ Pkey.push_back(i);
+ unsigned fc = 0; // controls logic for our strange flipper counter
+ do {
+ det = _ex0();
+ for (unsigned r=0; r<n-c; ++r) {
+ // maybe there is nothing to do?
+ if (m[Pkey[r]*n+c].is_zero())
+ continue;
+ // create the sorted key for all possible minors
+ Mkey.erase(Mkey.begin(),Mkey.end());
+ for (unsigned i=0; i<n-c; ++i)
+ if (i!=r)
+ Mkey.push_back(Pkey[i]);
+ // Fetch the minors and compute the new determinant
+ if (r%2)
+ det -= m[Pkey[r]*n+c]*A[Mkey];
+ else
+ det += m[Pkey[r]*n+c]*A[Mkey];
+ }
+ // prevent build-up of deep nesting of expressions saves time:
+ det = det.expand();
+ // store the new determinant at its place in B:
+ if (!det.is_zero())
+ B.insert(Rmap_value(Pkey,det));
+ // increment our strange flipper counter
+ for (fc=n-c; fc>0; --fc) {
+ ++Pkey[fc-1];
+ if (Pkey[fc-1]<fc+c)
+ break;
+ }
+ if (fc<n-c)
+ for (unsigned j=fc; j<n-c; ++j)
+ Pkey[j] = Pkey[j-1]+1;
+ } while(fc);
+ // next column, so change the role of A and B:
+ A = B;
+ B.clear();
+ }
+
+ return det;
}
* number of rows was swapped and 0 if the matrix is singular. */
int matrix::gauss_elimination(const bool det)
{
- ensure_if_modifiable();
- const unsigned m = this->rows();
- const unsigned n = this->cols();
- GINAC_ASSERT(!det || n==m);
- int sign = 1;
-
- unsigned r0 = 0;
- for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
- int indx = pivot(r0, r1, true);
- if (indx == -1) {
- sign = 0;
- if (det)
- return 0; // leaves *this in a messy state
- }
- if (indx>=0) {
- if (indx > 0)
- sign = -sign;
- for (unsigned r2=r0+1; r2<m; ++r2) {
- ex piv = this->m[r2*n+r1] / this->m[r0*n+r1];
- for (unsigned c=r1+1; c<n; ++c) {
- this->m[r2*n+c] -= piv * this->m[r0*n+c];
- if (!this->m[r2*n+c].info(info_flags::numeric))
- this->m[r2*n+c] = this->m[r2*n+c].normal();
- }
- // fill up left hand side with zeros
- for (unsigned c=0; c<=r1; ++c)
- this->m[r2*n+c] = _ex0();
- }
- if (det) {
- // save space by deleting no longer needed elements
- for (unsigned c=r0+1; c<n; ++c)
- this->m[r0*n+c] = _ex0();
- }
- ++r0;
- }
- }
-
- return sign;
+ ensure_if_modifiable();
+ const unsigned m = this->rows();
+ const unsigned n = this->cols();
+ GINAC_ASSERT(!det || n==m);
+ int sign = 1;
+
+ unsigned r0 = 0;
+ for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
+ int indx = pivot(r0, r1, true);
+ if (indx == -1) {
+ sign = 0;
+ if (det)
+ return 0; // leaves *this in a messy state
+ }
+ if (indx>=0) {
+ if (indx > 0)
+ sign = -sign;
+ for (unsigned r2=r0+1; r2<m; ++r2) {
+ ex piv = this->m[r2*n+r1] / this->m[r0*n+r1];
+ for (unsigned c=r1+1; c<n; ++c) {
+ this->m[r2*n+c] -= piv * this->m[r0*n+c];
+ if (!this->m[r2*n+c].info(info_flags::numeric))
+ this->m[r2*n+c] = this->m[r2*n+c].normal();
+ }
+ // fill up left hand side with zeros
+ for (unsigned c=0; c<=r1; ++c)
+ this->m[r2*n+c] = _ex0();
+ }
+ if (det) {
+ // save space by deleting no longer needed elements
+ for (unsigned c=r0+1; c<n; ++c)
+ this->m[r0*n+c] = _ex0();
+ }
+ ++r0;
+ }
+ }
+
+ return sign;
}
* number of rows was swapped and 0 if the matrix is singular. */
int matrix::division_free_elimination(const bool det)
{
- ensure_if_modifiable();
- const unsigned m = this->rows();
- const unsigned n = this->cols();
- GINAC_ASSERT(!det || n==m);
- int sign = 1;
-
- unsigned r0 = 0;
- for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
- int indx = pivot(r0, r1, true);
- if (indx==-1) {
- sign = 0;
- if (det)
- return 0; // leaves *this in a messy state
- }
- if (indx>=0) {
- if (indx>0)
- sign = -sign;
- for (unsigned r2=r0+1; r2<m; ++r2) {
- for (unsigned c=r1+1; c<n; ++c)
- this->m[r2*n+c] = (this->m[r0*n+r1]*this->m[r2*n+c] - this->m[r2*n+r1]*this->m[r0*n+c]).expand();
- // fill up left hand side with zeros
- for (unsigned c=0; c<=r1; ++c)
- this->m[r2*n+c] = _ex0();
- }
- if (det) {
- // save space by deleting no longer needed elements
- for (unsigned c=r0+1; c<n; ++c)
- this->m[r0*n+c] = _ex0();
- }
- ++r0;
- }
- }
-
- return sign;
+ ensure_if_modifiable();
+ const unsigned m = this->rows();
+ const unsigned n = this->cols();
+ GINAC_ASSERT(!det || n==m);
+ int sign = 1;
+
+ unsigned r0 = 0;
+ for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
+ int indx = pivot(r0, r1, true);
+ if (indx==-1) {
+ sign = 0;
+ if (det)
+ return 0; // leaves *this in a messy state
+ }
+ if (indx>=0) {
+ if (indx>0)
+ sign = -sign;
+ for (unsigned r2=r0+1; r2<m; ++r2) {
+ for (unsigned c=r1+1; c<n; ++c)
+ this->m[r2*n+c] = (this->m[r0*n+r1]*this->m[r2*n+c] - this->m[r2*n+r1]*this->m[r0*n+c]).expand();
+ // fill up left hand side with zeros
+ for (unsigned c=0; c<=r1; ++c)
+ this->m[r2*n+c] = _ex0();
+ }
+ if (det) {
+ // save space by deleting no longer needed elements
+ for (unsigned c=r0+1; c<n; ++c)
+ this->m[r0*n+c] = _ex0();
+ }
+ ++r0;
+ }
+ }
+
+ return sign;
}
* number of rows was swapped and 0 if the matrix is singular. */
int matrix::fraction_free_elimination(const bool det)
{
- // Method:
- // (single-step fraction free elimination scheme, already known to Jordan)
- //
- // Usual division-free elimination sets m[0](r,c) = m(r,c) and then sets
- // m[k+1](r,c) = m[k](k,k) * m[k](r,c) - m[k](r,k) * m[k](k,c).
- //
- // Bareiss (fraction-free) elimination in addition divides that element
- // by m[k-1](k-1,k-1) for k>1, where it can be shown by means of the
- // Sylvester determinant that this really divides m[k+1](r,c).
- //
- // We also allow rational functions where the original prove still holds.
- // However, we must care for numerator and denominator separately and
- // "manually" work in the integral domains because of subtle cancellations
- // (see below). This blows up the bookkeeping a bit and the formula has
- // to be modified to expand like this (N{x} stands for numerator of x,
- // D{x} for denominator of x):
- // N{m[k+1](r,c)} = N{m[k](k,k)}*N{m[k](r,c)}*D{m[k](r,k)}*D{m[k](k,c)}
- // -N{m[k](r,k)}*N{m[k](k,c)}*D{m[k](k,k)}*D{m[k](r,c)}
- // D{m[k+1](r,c)} = D{m[k](k,k)}*D{m[k](r,c)}*D{m[k](r,k)}*D{m[k](k,c)}
- // where for k>1 we now divide N{m[k+1](r,c)} by
- // N{m[k-1](k-1,k-1)}
- // and D{m[k+1](r,c)} by
- // D{m[k-1](k-1,k-1)}.
-
- ensure_if_modifiable();
- const unsigned m = this->rows();
- const unsigned n = this->cols();
- GINAC_ASSERT(!det || n==m);
- int sign = 1;
- if (m==1)
- return 1;
- ex divisor_n = 1;
- ex divisor_d = 1;
- ex dividend_n;
- ex dividend_d;
-
- // We populate temporary matrices to subsequently operate on. There is
- // one holding numerators and another holding denominators of entries.
- // This is a must since the evaluator (or even earlier mul's constructor)
- // might cancel some trivial element which causes divide() to fail. The
- // elements are normalized first (yes, even though this algorithm doesn't
- // need GCDs) since the elements of *this might be unnormalized, which
- // makes things more complicated than they need to be.
- matrix tmp_n(*this);
- matrix tmp_d(m,n); // for denominators, if needed
- lst srl; // symbol replacement list
- exvector::iterator it = this->m.begin();
- exvector::iterator tmp_n_it = tmp_n.m.begin();
- exvector::iterator tmp_d_it = tmp_d.m.begin();
- for (; it!= this->m.end(); ++it, ++tmp_n_it, ++tmp_d_it) {
- (*tmp_n_it) = (*it).normal().to_rational(srl);
- (*tmp_d_it) = (*tmp_n_it).denom();
- (*tmp_n_it) = (*tmp_n_it).numer();
- }
-
- unsigned r0 = 0;
- for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
- int indx = tmp_n.pivot(r0, r1, true);
- if (indx==-1) {
- sign = 0;
- if (det)
- return 0;
- }
- if (indx>=0) {
- if (indx>0) {
- sign = -sign;
- // tmp_n's rows r0 and indx were swapped, do the same in tmp_d:
- for (unsigned c=r1; c<n; ++c)
- tmp_d.m[n*indx+c].swap(tmp_d.m[n*r0+c]);
- }
- for (unsigned r2=r0+1; r2<m; ++r2) {
- for (unsigned c=r1+1; c<n; ++c) {
- dividend_n = (tmp_n.m[r0*n+r1]*tmp_n.m[r2*n+c]*
- tmp_d.m[r2*n+r1]*tmp_d.m[r0*n+c]
- -tmp_n.m[r2*n+r1]*tmp_n.m[r0*n+c]*
- tmp_d.m[r0*n+r1]*tmp_d.m[r2*n+c]).expand();
- dividend_d = (tmp_d.m[r2*n+r1]*tmp_d.m[r0*n+c]*
- tmp_d.m[r0*n+r1]*tmp_d.m[r2*n+c]).expand();
- bool check = divide(dividend_n, divisor_n,
- tmp_n.m[r2*n+c], true);
- check &= divide(dividend_d, divisor_d,
- tmp_d.m[r2*n+c], true);
- GINAC_ASSERT(check);
- }
- // fill up left hand side with zeros
- for (unsigned c=0; c<=r1; ++c)
- tmp_n.m[r2*n+c] = _ex0();
- }
- if ((r1<n-1)&&(r0<m-1)) {
- // compute next iteration's divisor
- divisor_n = tmp_n.m[r0*n+r1].expand();
- divisor_d = tmp_d.m[r0*n+r1].expand();
- if (det) {
- // save space by deleting no longer needed elements
- for (unsigned c=0; c<n; ++c) {
- tmp_n.m[r0*n+c] = _ex0();
- tmp_d.m[r0*n+c] = _ex1();
- }
- }
- }
- ++r0;
- }
- }
- // repopulate *this matrix:
- it = this->m.begin();
- tmp_n_it = tmp_n.m.begin();
- tmp_d_it = tmp_d.m.begin();
- for (; it!= this->m.end(); ++it, ++tmp_n_it, ++tmp_d_it)
- (*it) = ((*tmp_n_it)/(*tmp_d_it)).subs(srl);
-
- return sign;
+ // Method:
+ // (single-step fraction free elimination scheme, already known to Jordan)
+ //
+ // Usual division-free elimination sets m[0](r,c) = m(r,c) and then sets
+ // m[k+1](r,c) = m[k](k,k) * m[k](r,c) - m[k](r,k) * m[k](k,c).
+ //
+ // Bareiss (fraction-free) elimination in addition divides that element
+ // by m[k-1](k-1,k-1) for k>1, where it can be shown by means of the
+ // Sylvester determinant that this really divides m[k+1](r,c).
+ //
+ // We also allow rational functions where the original prove still holds.
+ // However, we must care for numerator and denominator separately and
+ // "manually" work in the integral domains because of subtle cancellations
+ // (see below). This blows up the bookkeeping a bit and the formula has
+ // to be modified to expand like this (N{x} stands for numerator of x,
+ // D{x} for denominator of x):
+ // N{m[k+1](r,c)} = N{m[k](k,k)}*N{m[k](r,c)}*D{m[k](r,k)}*D{m[k](k,c)}
+ // -N{m[k](r,k)}*N{m[k](k,c)}*D{m[k](k,k)}*D{m[k](r,c)}
+ // D{m[k+1](r,c)} = D{m[k](k,k)}*D{m[k](r,c)}*D{m[k](r,k)}*D{m[k](k,c)}
+ // where for k>1 we now divide N{m[k+1](r,c)} by
+ // N{m[k-1](k-1,k-1)}
+ // and D{m[k+1](r,c)} by
+ // D{m[k-1](k-1,k-1)}.
+
+ ensure_if_modifiable();
+ const unsigned m = this->rows();
+ const unsigned n = this->cols();
+ GINAC_ASSERT(!det || n==m);
+ int sign = 1;
+ if (m==1)
+ return 1;
+ ex divisor_n = 1;
+ ex divisor_d = 1;
+ ex dividend_n;
+ ex dividend_d;
+
+ // We populate temporary matrices to subsequently operate on. There is
+ // one holding numerators and another holding denominators of entries.
+ // This is a must since the evaluator (or even earlier mul's constructor)
+ // might cancel some trivial element which causes divide() to fail. The
+ // elements are normalized first (yes, even though this algorithm doesn't
+ // need GCDs) since the elements of *this might be unnormalized, which
+ // makes things more complicated than they need to be.
+ matrix tmp_n(*this);
+ matrix tmp_d(m,n); // for denominators, if needed
+ lst srl; // symbol replacement list
+ exvector::iterator it = this->m.begin();
+ exvector::iterator tmp_n_it = tmp_n.m.begin();
+ exvector::iterator tmp_d_it = tmp_d.m.begin();
+ for (; it!= this->m.end(); ++it, ++tmp_n_it, ++tmp_d_it) {
+ (*tmp_n_it) = (*it).normal().to_rational(srl);
+ (*tmp_d_it) = (*tmp_n_it).denom();
+ (*tmp_n_it) = (*tmp_n_it).numer();
+ }
+
+ unsigned r0 = 0;
+ for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
+ int indx = tmp_n.pivot(r0, r1, true);
+ if (indx==-1) {
+ sign = 0;
+ if (det)
+ return 0;
+ }
+ if (indx>=0) {
+ if (indx>0) {
+ sign = -sign;
+ // tmp_n's rows r0 and indx were swapped, do the same in tmp_d:
+ for (unsigned c=r1; c<n; ++c)
+ tmp_d.m[n*indx+c].swap(tmp_d.m[n*r0+c]);
+ }
+ for (unsigned r2=r0+1; r2<m; ++r2) {
+ for (unsigned c=r1+1; c<n; ++c) {
+ dividend_n = (tmp_n.m[r0*n+r1]*tmp_n.m[r2*n+c]*
+ tmp_d.m[r2*n+r1]*tmp_d.m[r0*n+c]
+ -tmp_n.m[r2*n+r1]*tmp_n.m[r0*n+c]*
+ tmp_d.m[r0*n+r1]*tmp_d.m[r2*n+c]).expand();
+ dividend_d = (tmp_d.m[r2*n+r1]*tmp_d.m[r0*n+c]*
+ tmp_d.m[r0*n+r1]*tmp_d.m[r2*n+c]).expand();
+ bool check = divide(dividend_n, divisor_n,
+ tmp_n.m[r2*n+c], true);
+ check &= divide(dividend_d, divisor_d,
+ tmp_d.m[r2*n+c], true);
+ GINAC_ASSERT(check);
+ }
+ // fill up left hand side with zeros
+ for (unsigned c=0; c<=r1; ++c)
+ tmp_n.m[r2*n+c] = _ex0();
+ }
+ if ((r1<n-1)&&(r0<m-1)) {
+ // compute next iteration's divisor
+ divisor_n = tmp_n.m[r0*n+r1].expand();
+ divisor_d = tmp_d.m[r0*n+r1].expand();
+ if (det) {
+ // save space by deleting no longer needed elements
+ for (unsigned c=0; c<n; ++c) {
+ tmp_n.m[r0*n+c] = _ex0();
+ tmp_d.m[r0*n+c] = _ex1();
+ }
+ }
+ }
+ ++r0;
+ }
+ }
+ // repopulate *this matrix:
+ it = this->m.begin();
+ tmp_n_it = tmp_n.m.begin();
+ tmp_d_it = tmp_d.m.begin();
+ for (; it!= this->m.end(); ++it, ++tmp_n_it, ++tmp_d_it)
+ (*it) = ((*tmp_n_it)/(*tmp_d_it)).subs(srl);
+
+ return sign;
}
*/
int matrix::pivot(unsigned ro, unsigned co, bool symbolic)
{
- unsigned k = ro;
- if (symbolic) {
- // search first non-zero element in column co beginning at row ro
- while ((k<row) && (this->m[k*col+co].expand().is_zero()))
- ++k;
- } else {
- // search largest element in column co beginning at row ro
- GINAC_ASSERT(is_ex_of_type(this->m[k*col+co],numeric));
- unsigned kmax = k+1;
- numeric mmax = abs(ex_to_numeric(m[kmax*col+co]));
- while (kmax<row) {
- GINAC_ASSERT(is_ex_of_type(this->m[kmax*col+co],numeric));
- numeric tmp = ex_to_numeric(this->m[kmax*col+co]);
- if (abs(tmp) > mmax) {
- mmax = tmp;
- k = kmax;
- }
- ++kmax;
- }
- if (!mmax.is_zero())
- k = kmax;
- }
- if (k==row)
- // all elements in column co below row ro vanish
- return -1;
- if (k==ro)
- // matrix needs no pivoting
- return 0;
- // matrix needs pivoting, so swap rows k and ro
- ensure_if_modifiable();
- for (unsigned c=0; c<col; ++c)
- m[k*col+c].swap(m[ro*col+c]);
-
- return k;
+ unsigned k = ro;
+ if (symbolic) {
+ // search first non-zero element in column co beginning at row ro
+ while ((k<row) && (this->m[k*col+co].expand().is_zero()))
+ ++k;
+ } else {
+ // search largest element in column co beginning at row ro
+ GINAC_ASSERT(is_ex_of_type(this->m[k*col+co],numeric));
+ unsigned kmax = k+1;
+ numeric mmax = abs(ex_to_numeric(m[kmax*col+co]));
+ while (kmax<row) {
+ GINAC_ASSERT(is_ex_of_type(this->m[kmax*col+co],numeric));
+ numeric tmp = ex_to_numeric(this->m[kmax*col+co]);
+ if (abs(tmp) > mmax) {
+ mmax = tmp;
+ k = kmax;
+ }
+ ++kmax;
+ }
+ if (!mmax.is_zero())
+ k = kmax;
+ }
+ if (k==row)
+ // all elements in column co below row ro vanish
+ return -1;
+ if (k==ro)
+ // matrix needs no pivoting
+ return 0;
+ // matrix needs pivoting, so swap rows k and ro
+ ensure_if_modifiable();
+ for (unsigned c=0; c<col; ++c)
+ m[k*col+c].swap(m[ro*col+c]);
+
+ return k;
}
/** Convert list of lists to matrix. */
ex lst_to_matrix(const ex &l)
{
- if (!is_ex_of_type(l, lst))
- throw(std::invalid_argument("argument to lst_to_matrix() must be a lst"));
-
- // Find number of rows and columns
- unsigned rows = l.nops(), cols = 0, i, j;
- for (i=0; i<rows; i++)
- if (l.op(i).nops() > cols)
- cols = l.op(i).nops();
-
- // Allocate and fill matrix
- matrix &m = *new matrix(rows, cols);
- for (i=0; i<rows; i++)
- for (j=0; j<cols; j++)
- if (l.op(i).nops() > j)
- m.set(i, j, l.op(i).op(j));
- else
- m.set(i, j, ex(0));
- return m;
+ if (!is_ex_of_type(l, lst))
+ throw(std::invalid_argument("argument to lst_to_matrix() must be a lst"));
+
+ // Find number of rows and columns
+ unsigned rows = l.nops(), cols = 0, i, j;
+ for (i=0; i<rows; i++)
+ if (l.op(i).nops() > cols)
+ cols = l.op(i).nops();
+
+ // Allocate and fill matrix
+ matrix &m = *new matrix(rows, cols);
+ for (i=0; i<rows; i++)
+ for (j=0; j<cols; j++)
+ if (l.op(i).nops() > j)
+ m.set(i, j, l.op(i).op(j));
+ else
+ m.set(i, j, ex(0));
+ return m;
}
//////////
/** Symbolic matrices. */
class matrix : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(matrix, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(matrix, basic)
// friends
// (none)
// member functions
- // default constructor, destructor, copy constructor, assignment operator
- // and helpers:
+ // default constructor, destructor, copy constructor, assignment operator
+ // and helpers:
public:
- matrix();
- ~matrix();
- matrix(const matrix & other);
- const matrix & operator=(const matrix & other);
+ matrix();
+ ~matrix();
+ matrix(const matrix & other);
+ const matrix & operator=(const matrix & other);
protected:
- void copy(const matrix & other);
- void destroy(bool call_parent);
+ void copy(const matrix & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- matrix(unsigned r, unsigned c);
- matrix(unsigned r, unsigned c, const exvector & m2);
+ matrix(unsigned r, unsigned c);
+ matrix(unsigned r, unsigned c, const exvector & m2);
- // functions overriding virtual functions from bases classes
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printraw(std::ostream & os) const;
- unsigned nops() const;
- ex op(int i) const;
- ex & let_op(int i);
- ex expand(unsigned options=0) const;
- bool has(const ex & other) const;
- ex eval(int level=0) const;
- ex evalf(int level=0) const;
- // ex subs(const lst & ls, const lst & lr) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printraw(std::ostream & os) const;
+ unsigned nops() const;
+ ex op(int i) const;
+ ex & let_op(int i);
+ ex expand(unsigned options=0) const;
+ bool has(const ex & other) const;
+ ex eval(int level=0) const;
+ ex evalf(int level=0) const;
+ // ex subs(const lst & ls, const lst & lr) const;
protected:
- int compare_same_type(const basic & other) const;
- unsigned return_type(void) const { return return_types::noncommutative; };
- // new virtual functions which can be overridden by derived classes
- // (none)
-
- // non-virtual functions in this class
+ int compare_same_type(const basic & other) const;
+ unsigned return_type(void) const { return return_types::noncommutative; };
+ // new virtual functions which can be overridden by derived classes
+ // (none)
+
+ // non-virtual functions in this class
public:
- unsigned rows(void) const //! Get number of rows.
- { return row; }
- unsigned cols(void) const //! Get number of columns.
- { return col; }
- matrix add(const matrix & other) const;
- matrix sub(const matrix & other) const;
- matrix mul(const matrix & other) const;
- const ex & operator() (unsigned ro, unsigned co) const;
- matrix & set(unsigned ro, unsigned co, ex value);
- matrix transpose(void) const;
- ex determinant(unsigned algo = determinant_algo::automatic) const;
- ex trace(void) const;
- ex charpoly(const symbol & lambda) const;
- matrix inverse(void) const;
- matrix solve(const matrix & vars, const matrix & rhs,
- unsigned algo = solve_algo::automatic) const;
+ unsigned rows(void) const //! Get number of rows.
+ { return row; }
+ unsigned cols(void) const //! Get number of columns.
+ { return col; }
+ matrix add(const matrix & other) const;
+ matrix sub(const matrix & other) const;
+ matrix mul(const matrix & other) const;
+ const ex & operator() (unsigned ro, unsigned co) const;
+ matrix & set(unsigned ro, unsigned co, ex value);
+ matrix transpose(void) const;
+ ex determinant(unsigned algo = determinant_algo::automatic) const;
+ ex trace(void) const;
+ ex charpoly(const symbol & lambda) const;
+ matrix inverse(void) const;
+ matrix solve(const matrix & vars, const matrix & rhs,
+ unsigned algo = solve_algo::automatic) const;
protected:
- ex determinant_minor(void) const;
- int gauss_elimination(const bool det = false);
- int division_free_elimination(const bool det = false);
- int fraction_free_elimination(const bool det = false);
- int pivot(unsigned ro, unsigned co, bool symbolic = true);
-
+ ex determinant_minor(void) const;
+ int gauss_elimination(const bool det = false);
+ int division_free_elimination(const bool det = false);
+ int fraction_free_elimination(const bool det = false);
+ int pivot(unsigned ro, unsigned co, bool symbolic = true);
+
// member variables
protected:
- unsigned row; /**< number of rows */
- unsigned col; /**< number of columns */
- exvector m; /**< representation (cols indexed first) */
- static unsigned precedence;
+ unsigned row; /**< number of rows */
+ unsigned col; /**< number of columns */
+ exvector m; /**< representation (cols indexed first) */
+ static unsigned precedence;
};
mul::mul()
{
- debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_mul;
+ debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_mul;
}
mul::~mul()
{
- debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
+ destroy(false);
}
mul::mul(const mul & other)
{
- debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const mul & mul::operator=(const mul & other)
{
- debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(true);
+ copy(other);
+ }
+ return *this;
}
// protected
void mul::copy(const mul & other)
{
- inherited::copy(other);
+ inherited::copy(other);
}
void mul::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
//////////
mul::mul(const ex & lh, const ex & rh)
{
- debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_mul;
- overall_coeff = _ex1();
- construct_from_2_ex(lh,rh);
- GINAC_ASSERT(is_canonical());
+ debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_mul;
+ overall_coeff = _ex1();
+ construct_from_2_ex(lh,rh);
+ GINAC_ASSERT(is_canonical());
}
mul::mul(const exvector & v)
{
- debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_mul;
- overall_coeff = _ex1();
- construct_from_exvector(v);
- GINAC_ASSERT(is_canonical());
+ debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_mul;
+ overall_coeff = _ex1();
+ construct_from_exvector(v);
+ GINAC_ASSERT(is_canonical());
}
mul::mul(const epvector & v)
{
- debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_mul;
- overall_coeff = _ex1();
- construct_from_epvector(v);
- GINAC_ASSERT(is_canonical());
+ debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_mul;
+ overall_coeff = _ex1();
+ construct_from_epvector(v);
+ GINAC_ASSERT(is_canonical());
}
mul::mul(const epvector & v, const ex & oc)
{
- debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_mul;
- overall_coeff = oc;
- construct_from_epvector(v);
- GINAC_ASSERT(is_canonical());
+ debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_mul;
+ overall_coeff = oc;
+ construct_from_epvector(v);
+ GINAC_ASSERT(is_canonical());
}
mul::mul(epvector * vp, const ex & oc)
{
- debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_mul;
- GINAC_ASSERT(vp!=0);
- overall_coeff = oc;
- construct_from_epvector(*vp);
- delete vp;
- GINAC_ASSERT(is_canonical());
+ debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_mul;
+ GINAC_ASSERT(vp!=0);
+ overall_coeff = oc;
+ construct_from_epvector(*vp);
+ delete vp;
+ GINAC_ASSERT(is_canonical());
}
mul::mul(const ex & lh, const ex & mh, const ex & rh)
{
- debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_mul;
- exvector factors;
- factors.reserve(3);
- factors.push_back(lh);
- factors.push_back(mh);
- factors.push_back(rh);
- overall_coeff = _ex1();
- construct_from_exvector(factors);
- GINAC_ASSERT(is_canonical());
+ debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_mul;
+ exvector factors;
+ factors.reserve(3);
+ factors.push_back(lh);
+ factors.push_back(mh);
+ factors.push_back(rh);
+ overall_coeff = _ex1();
+ construct_from_exvector(factors);
+ GINAC_ASSERT(is_canonical());
}
//////////
/** Construct object from archive_node. */
mul::mul(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("mul constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ debugmsg("mul constructor from archive_node", LOGLEVEL_CONSTRUCT);
}
/** Unarchive the object. */
ex mul::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new mul(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new mul(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void mul::archive(archive_node &n) const
{
- inherited::archive(n);
+ inherited::archive(n);
}
//////////
basic * mul::duplicate() const
{
- debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
- return new mul(*this);
+ debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
+ return new mul(*this);
}
void mul::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("mul print",LOGLEVEL_PRINT);
- if (precedence<=upper_precedence) os << "(";
- bool first=true;
- // first print the overall numeric coefficient:
- numeric coeff = ex_to_numeric(overall_coeff);
- if (coeff.csgn()==-1) os << '-';
- if (!coeff.is_equal(_num1()) &&
- !coeff.is_equal(_num_1())) {
- if (coeff.is_rational()) {
- if (coeff.is_negative())
- os << -coeff;
- else
- os << coeff;
- } else {
- if (coeff.csgn()==-1)
- (-coeff).print(os, precedence);
- else
- coeff.print(os, precedence);
- }
- os << '*';
- }
- // then proceed with the remaining factors:
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- if (!first) {
- os << '*';
- } else {
- first=false;
- }
- recombine_pair_to_ex(*cit).print(os,precedence);
- }
- if (precedence<=upper_precedence) os << ")";
+ debugmsg("mul print",LOGLEVEL_PRINT);
+ if (precedence<=upper_precedence) os << "(";
+ bool first=true;
+ // first print the overall numeric coefficient:
+ numeric coeff = ex_to_numeric(overall_coeff);
+ if (coeff.csgn()==-1) os << '-';
+ if (!coeff.is_equal(_num1()) &&
+ !coeff.is_equal(_num_1())) {
+ if (coeff.is_rational()) {
+ if (coeff.is_negative())
+ os << -coeff;
+ else
+ os << coeff;
+ } else {
+ if (coeff.csgn()==-1)
+ (-coeff).print(os, precedence);
+ else
+ coeff.print(os, precedence);
+ }
+ os << '*';
+ }
+ // then proceed with the remaining factors:
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ if (!first) {
+ os << '*';
+ } else {
+ first=false;
+ }
+ recombine_pair_to_ex(*cit).print(os,precedence);
+ }
+ if (precedence<=upper_precedence) os << ")";
}
void mul::printraw(std::ostream & os) const
{
- debugmsg("mul printraw",LOGLEVEL_PRINT);
+ debugmsg("mul printraw",LOGLEVEL_PRINT);
- os << "*(";
- for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- os << "(";
- (*it).rest.bp->printraw(os);
- os << ",";
- (*it).coeff.bp->printraw(os);
- os << "),";
- }
- os << ",hash=" << hashvalue << ",flags=" << flags;
- os << ")";
+ os << "*(";
+ for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ os << "(";
+ (*it).rest.bp->printraw(os);
+ os << ",";
+ (*it).coeff.bp->printraw(os);
+ os << "),";
+ }
+ os << ",hash=" << hashvalue << ",flags=" << flags;
+ os << ")";
}
void mul::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("mul print csrc", LOGLEVEL_PRINT);
- if (precedence <= upper_precedence)
- os << "(";
-
- if (!overall_coeff.is_equal(_ex1())) {
- overall_coeff.bp->printcsrc(os,type,precedence);
- os << "*";
- }
-
- // Print arguments, separated by "*" or "/"
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- while (it != itend) {
-
- // If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
- if (it == seq.begin() && ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(_num0()) < 0) {
- if (type == csrc_types::ctype_cl_N)
- os << "recip(";
- else
- os << "1.0/";
- }
-
- // If the exponent is 1 or -1, it is left out
- if (it->coeff.compare(_ex1()) == 0 || it->coeff.compare(_num_1()) == 0)
- it->rest.bp->printcsrc(os, type, precedence);
- else
- // outer parens around ex needed for broken gcc-2.95 parser:
- (ex(power(it->rest, abs(ex_to_numeric(it->coeff))))).bp->printcsrc(os, type, upper_precedence);
-
- // Separator is "/" for negative integer powers, "*" otherwise
- ++it;
- if (it != itend) {
- if (ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(_num0()) < 0)
- os << "/";
- else
- os << "*";
- }
- }
- if (precedence <= upper_precedence)
- os << ")";
+ debugmsg("mul print csrc", LOGLEVEL_PRINT);
+ if (precedence <= upper_precedence)
+ os << "(";
+
+ if (!overall_coeff.is_equal(_ex1())) {
+ overall_coeff.bp->printcsrc(os,type,precedence);
+ os << "*";
+ }
+
+ // Print arguments, separated by "*" or "/"
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ while (it != itend) {
+
+ // If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
+ if (it == seq.begin() && ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(_num0()) < 0) {
+ if (type == csrc_types::ctype_cl_N)
+ os << "recip(";
+ else
+ os << "1.0/";
+ }
+
+ // If the exponent is 1 or -1, it is left out
+ if (it->coeff.compare(_ex1()) == 0 || it->coeff.compare(_num_1()) == 0)
+ it->rest.bp->printcsrc(os, type, precedence);
+ else
+ // outer parens around ex needed for broken gcc-2.95 parser:
+ (ex(power(it->rest, abs(ex_to_numeric(it->coeff))))).bp->printcsrc(os, type, upper_precedence);
+
+ // Separator is "/" for negative integer powers, "*" otherwise
+ ++it;
+ if (it != itend) {
+ if (ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(_num0()) < 0)
+ os << "/";
+ else
+ os << "*";
+ }
+ }
+ if (precedence <= upper_precedence)
+ os << ")";
}
bool mul::info(unsigned inf) const
{
- switch (inf) {
- case info_flags::polynomial:
- case info_flags::integer_polynomial:
- case info_flags::cinteger_polynomial:
- case info_flags::rational_polynomial:
- case info_flags::crational_polynomial:
- case info_flags::rational_function: {
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
- if (!(recombine_pair_to_ex(*i).info(inf)))
- return false;
- }
- return overall_coeff.info(inf);
- }
- case info_flags::algebraic: {
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
- if ((recombine_pair_to_ex(*i).info(inf)))
- return true;
- }
- return false;
- }
- }
- return inherited::info(inf);
+ switch (inf) {
+ case info_flags::polynomial:
+ case info_flags::integer_polynomial:
+ case info_flags::cinteger_polynomial:
+ case info_flags::rational_polynomial:
+ case info_flags::crational_polynomial:
+ case info_flags::rational_function: {
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+ if (!(recombine_pair_to_ex(*i).info(inf)))
+ return false;
+ }
+ return overall_coeff.info(inf);
+ }
+ case info_flags::algebraic: {
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+ if ((recombine_pair_to_ex(*i).info(inf)))
+ return true;
+ }
+ return false;
+ }
+ }
+ return inherited::info(inf);
}
typedef std::vector<int> intvector;
int mul::degree(const symbol & s) const
{
- int deg_sum = 0;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
- }
- return deg_sum;
+ int deg_sum = 0;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
+ }
+ return deg_sum;
}
int mul::ldegree(const symbol & s) const
{
- int deg_sum = 0;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
- }
- return deg_sum;
+ int deg_sum = 0;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
+ }
+ return deg_sum;
}
ex mul::coeff(const symbol & s, int n) const
{
- exvector coeffseq;
- coeffseq.reserve(seq.size()+1);
-
- if (n==0) {
- // product of individual coeffs
- // if a non-zero power of s is found, the resulting product will be 0
- epvector::const_iterator it=seq.begin();
- while (it!=seq.end()) {
- coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
- ++it;
- }
- coeffseq.push_back(overall_coeff);
- return (new mul(coeffseq))->setflag(status_flags::dynallocated);
- }
-
- epvector::const_iterator it=seq.begin();
- bool coeff_found=0;
- while (it!=seq.end()) {
- ex t=recombine_pair_to_ex(*it);
- ex c=t.coeff(s,n);
- if (!c.is_zero()) {
- coeffseq.push_back(c);
- coeff_found=1;
- } else {
- coeffseq.push_back(t);
- }
- ++it;
- }
- if (coeff_found) {
- coeffseq.push_back(overall_coeff);
- return (new mul(coeffseq))->setflag(status_flags::dynallocated);
- }
-
- return _ex0();
+ exvector coeffseq;
+ coeffseq.reserve(seq.size()+1);
+
+ if (n==0) {
+ // product of individual coeffs
+ // if a non-zero power of s is found, the resulting product will be 0
+ epvector::const_iterator it=seq.begin();
+ while (it!=seq.end()) {
+ coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
+ ++it;
+ }
+ coeffseq.push_back(overall_coeff);
+ return (new mul(coeffseq))->setflag(status_flags::dynallocated);
+ }
+
+ epvector::const_iterator it=seq.begin();
+ bool coeff_found=0;
+ while (it!=seq.end()) {
+ ex t=recombine_pair_to_ex(*it);
+ ex c=t.coeff(s,n);
+ if (!c.is_zero()) {
+ coeffseq.push_back(c);
+ coeff_found=1;
+ } else {
+ coeffseq.push_back(t);
+ }
+ ++it;
+ }
+ if (coeff_found) {
+ coeffseq.push_back(overall_coeff);
+ return (new mul(coeffseq))->setflag(status_flags::dynallocated);
+ }
+
+ return _ex0();
}
ex mul::eval(int level) const
{
- // simplifications *(...,x;0) -> 0
- // *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
- // *(x;1) -> x
- // *(;c) -> c
+ // simplifications *(...,x;0) -> 0
+ // *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
+ // *(x;1) -> x
+ // *(;c) -> c
- debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
+ debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
- epvector * evaled_seqp=evalchildren(level);
- if (evaled_seqp!=0) {
- // do more evaluation later
- return (new mul(evaled_seqp,overall_coeff))->
- setflag(status_flags::dynallocated);
- }
+ epvector * evaled_seqp=evalchildren(level);
+ if (evaled_seqp!=0) {
+ // do more evaluation later
+ return (new mul(evaled_seqp,overall_coeff))->
+ setflag(status_flags::dynallocated);
+ }
#ifdef DO_GINAC_ASSERT
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- GINAC_ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
- (!(ex_to_numeric((*cit).coeff).is_integer())));
- GINAC_ASSERT(!((*cit).is_numeric_with_coeff_1()));
- if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
- printtree(cerr,0);
- }
- GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
- /* for paranoia */
- expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
- GINAC_ASSERT(p.rest.is_equal((*cit).rest));
- GINAC_ASSERT(p.coeff.is_equal((*cit).coeff));
- /* end paranoia */
- }
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ GINAC_ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
+ (!(ex_to_numeric((*cit).coeff).is_integer())));
+ GINAC_ASSERT(!((*cit).is_numeric_with_coeff_1()));
+ if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
+ printtree(cerr,0);
+ }
+ GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
+ /* for paranoia */
+ expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
+ GINAC_ASSERT(p.rest.is_equal((*cit).rest));
+ GINAC_ASSERT(p.coeff.is_equal((*cit).coeff));
+ /* end paranoia */
+ }
#endif // def DO_GINAC_ASSERT
- if (flags & status_flags::evaluated) {
- GINAC_ASSERT(seq.size()>0);
- GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(_ex1()));
- return *this;
- }
-
- int seq_size=seq.size();
- if (overall_coeff.is_equal(_ex0())) {
- // *(...,x;0) -> 0
- return _ex0();
- } else if (seq_size==0) {
- // *(;c) -> c
- return overall_coeff;
- } else if ((seq_size==1)&&overall_coeff.is_equal(_ex1())) {
- // *(x;1) -> x
- return recombine_pair_to_ex(*(seq.begin()));
- } else if ((seq_size==1) &&
- is_ex_exactly_of_type((*seq.begin()).rest,add) &&
- ex_to_numeric((*seq.begin()).coeff).is_equal(_num1())) {
- // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
- const add & addref=ex_to_add((*seq.begin()).rest);
- epvector distrseq;
- distrseq.reserve(addref.seq.size());
- for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
- distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
- overall_coeff));
- }
- return (new add(distrseq,
- ex_to_numeric(addref.overall_coeff).
- mul_dyn(ex_to_numeric(overall_coeff))))
- ->setflag(status_flags::dynallocated |
- status_flags::evaluated);
- }
- return this->hold();
+ if (flags & status_flags::evaluated) {
+ GINAC_ASSERT(seq.size()>0);
+ GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(_ex1()));
+ return *this;
+ }
+
+ int seq_size=seq.size();
+ if (overall_coeff.is_equal(_ex0())) {
+ // *(...,x;0) -> 0
+ return _ex0();
+ } else if (seq_size==0) {
+ // *(;c) -> c
+ return overall_coeff;
+ } else if ((seq_size==1)&&overall_coeff.is_equal(_ex1())) {
+ // *(x;1) -> x
+ return recombine_pair_to_ex(*(seq.begin()));
+ } else if ((seq_size==1) &&
+ is_ex_exactly_of_type((*seq.begin()).rest,add) &&
+ ex_to_numeric((*seq.begin()).coeff).is_equal(_num1())) {
+ // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
+ const add & addref=ex_to_add((*seq.begin()).rest);
+ epvector distrseq;
+ distrseq.reserve(addref.seq.size());
+ for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
+ distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
+ overall_coeff));
+ }
+ return (new add(distrseq,
+ ex_to_numeric(addref.overall_coeff).
+ mul_dyn(ex_to_numeric(overall_coeff))))
+ ->setflag(status_flags::dynallocated |
+ status_flags::evaluated);
+ }
+ return this->hold();
}
ex mul::evalf(int level) const
{
- if (level==1)
- return mul(seq,overall_coeff);
-
- if (level==-max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
-
- epvector s;
- s.reserve(seq.size());
-
- --level;
- for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- s.push_back(combine_ex_with_coeff_to_pair((*it).rest.evalf(level),
- (*it).coeff));
- }
- return mul(s,overall_coeff.evalf(level));
+ if (level==1)
+ return mul(seq,overall_coeff);
+
+ if (level==-max_recursion_level)
+ throw(std::runtime_error("max recursion level reached"));
+
+ epvector s;
+ s.reserve(seq.size());
+
+ --level;
+ for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ s.push_back(combine_ex_with_coeff_to_pair((*it).rest.evalf(level),
+ (*it).coeff));
+ }
+ return mul(s,overall_coeff.evalf(level));
}
exvector mul::get_indices(void) const
{
- // return union of indices of factors
- exvector iv;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- exvector subiv=(*cit).rest.get_indices();
- iv.reserve(iv.size()+subiv.size());
- for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
- iv.push_back(*cit2);
- }
- }
- return iv;
+ // return union of indices of factors
+ exvector iv;
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ exvector subiv=(*cit).rest.get_indices();
+ iv.reserve(iv.size()+subiv.size());
+ for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
+ iv.push_back(*cit2);
+ }
+ }
+ return iv;
}
ex mul::simplify_ncmul(const exvector & v) const
{
- throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
+ throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
}
// protected
* @see ex::diff */
ex mul::derivative(const symbol & s) const
{
- exvector addseq;
- addseq.reserve(seq.size());
-
- // D(a*b*c) = D(a)*b*c + a*D(b)*c + a*b*D(c)
- for (unsigned i=0; i!=seq.size(); ++i) {
- epvector mulseq = seq;
- mulseq[i] = split_ex_to_pair(power(seq[i].rest,seq[i].coeff - _ex1())*
- seq[i].rest.diff(s));
- addseq.push_back((new mul(mulseq,overall_coeff*seq[i].coeff))->setflag(status_flags::dynallocated));
- }
- return (new add(addseq))->setflag(status_flags::dynallocated);
+ exvector addseq;
+ addseq.reserve(seq.size());
+
+ // D(a*b*c) = D(a)*b*c + a*D(b)*c + a*b*D(c)
+ for (unsigned i=0; i!=seq.size(); ++i) {
+ epvector mulseq = seq;
+ mulseq[i] = split_ex_to_pair(power(seq[i].rest,seq[i].coeff - _ex1())*
+ seq[i].rest.diff(s));
+ addseq.push_back((new mul(mulseq,overall_coeff*seq[i].coeff))->setflag(status_flags::dynallocated));
+ }
+ return (new add(addseq))->setflag(status_flags::dynallocated);
}
int mul::compare_same_type(const basic & other) const
{
- return inherited::compare_same_type(other);
+ return inherited::compare_same_type(other);
}
bool mul::is_equal_same_type(const basic & other) const
{
- return inherited::is_equal_same_type(other);
+ return inherited::is_equal_same_type(other);
}
unsigned mul::return_type(void) const
{
- if (seq.size()==0) {
- // mul without factors: should not happen, but commutes
- return return_types::commutative;
- }
-
- bool all_commutative = 1;
- unsigned rt;
- epvector::const_iterator cit_noncommutative_element; // point to first found nc element
-
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- rt=(*cit).rest.return_type();
- if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
- if ((rt==return_types::noncommutative)&&(all_commutative)) {
- // first nc element found, remember position
- cit_noncommutative_element = cit;
- all_commutative = 0;
- }
- if ((rt==return_types::noncommutative)&&(!all_commutative)) {
- // another nc element found, compare type_infos
- if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
- // diffent types -> mul is ncc
- return return_types::noncommutative_composite;
- }
- }
- }
- // all factors checked
- return all_commutative ? return_types::commutative : return_types::noncommutative;
+ if (seq.size()==0) {
+ // mul without factors: should not happen, but commutes
+ return return_types::commutative;
+ }
+
+ bool all_commutative = 1;
+ unsigned rt;
+ epvector::const_iterator cit_noncommutative_element; // point to first found nc element
+
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ rt=(*cit).rest.return_type();
+ if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
+ if ((rt==return_types::noncommutative)&&(all_commutative)) {
+ // first nc element found, remember position
+ cit_noncommutative_element = cit;
+ all_commutative = 0;
+ }
+ if ((rt==return_types::noncommutative)&&(!all_commutative)) {
+ // another nc element found, compare type_infos
+ if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
+ // diffent types -> mul is ncc
+ return return_types::noncommutative_composite;
+ }
+ }
+ }
+ // all factors checked
+ return all_commutative ? return_types::commutative : return_types::noncommutative;
}
unsigned mul::return_type_tinfo(void) const
{
- if (seq.size()==0) {
- // mul without factors: should not happen
- return tinfo_key;
- }
- // return type_info of first noncommutative element
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- if ((*cit).rest.return_type()==return_types::noncommutative) {
- return (*cit).rest.return_type_tinfo();
- }
- }
- // no noncommutative element found, should not happen
- return tinfo_key;
+ if (seq.size()==0) {
+ // mul without factors: should not happen
+ return tinfo_key;
+ }
+ // return type_info of first noncommutative element
+ for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ if ((*cit).rest.return_type()==return_types::noncommutative) {
+ return (*cit).rest.return_type_tinfo();
+ }
+ }
+ // no noncommutative element found, should not happen
+ return tinfo_key;
}
ex mul::thisexpairseq(const epvector & v, const ex & oc) const
{
- return (new mul(v,oc))->setflag(status_flags::dynallocated);
+ return (new mul(v,oc))->setflag(status_flags::dynallocated);
}
ex mul::thisexpairseq(epvector * vp, const ex & oc) const
{
- return (new mul(vp,oc))->setflag(status_flags::dynallocated);
+ return (new mul(vp,oc))->setflag(status_flags::dynallocated);
}
expair mul::split_ex_to_pair(const ex & e) const
{
- if (is_ex_exactly_of_type(e,power)) {
- const power & powerref=ex_to_power(e);
- if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
- return expair(powerref.basis,powerref.exponent);
- }
- }
- return expair(e,_ex1());
+ if (is_ex_exactly_of_type(e,power)) {
+ const power & powerref=ex_to_power(e);
+ if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
+ return expair(powerref.basis,powerref.exponent);
+ }
+ }
+ return expair(e,_ex1());
}
-
+
expair mul::combine_ex_with_coeff_to_pair(const ex & e,
- const ex & c) const
-{
- // to avoid duplication of power simplification rules,
- // we create a temporary power object
- // otherwise it would be hard to correctly simplify
- // expression like (4^(1/3))^(3/2)
- if (are_ex_trivially_equal(c,_ex1()))
- return split_ex_to_pair(e);
-
- return split_ex_to_pair(power(e,c));
-}
-
+ const ex & c) const
+{
+ // to avoid duplication of power simplification rules,
+ // we create a temporary power object
+ // otherwise it would be hard to correctly simplify
+ // expression like (4^(1/3))^(3/2)
+ if (are_ex_trivially_equal(c,_ex1()))
+ return split_ex_to_pair(e);
+
+ return split_ex_to_pair(power(e,c));
+}
+
expair mul::combine_pair_with_coeff_to_pair(const expair & p,
- const ex & c) const
-{
- // to avoid duplication of power simplification rules,
- // we create a temporary power object
- // otherwise it would be hard to correctly simplify
- // expression like (4^(1/3))^(3/2)
- if (are_ex_trivially_equal(c,_ex1()))
- return p;
-
- return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
-}
-
+ const ex & c) const
+{
+ // to avoid duplication of power simplification rules,
+ // we create a temporary power object
+ // otherwise it would be hard to correctly simplify
+ // expression like (4^(1/3))^(3/2)
+ if (are_ex_trivially_equal(c,_ex1()))
+ return p;
+
+ return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
+}
+
ex mul::recombine_pair_to_ex(const expair & p) const
{
- // if (p.coeff.compare(_ex1())==0) {
- // if (are_ex_trivially_equal(p.coeff,_ex1())) {
- if (ex_to_numeric(p.coeff).is_equal(_num1()))
- return p.rest;
- else
- return power(p.rest,p.coeff);
+ if (ex_to_numeric(p.coeff).is_equal(_num1()))
+ return p.rest;
+ else
+ return power(p.rest,p.coeff);
}
bool mul::expair_needs_further_processing(epp it)
{
- if (is_ex_exactly_of_type((*it).rest,mul) &&
- ex_to_numeric((*it).coeff).is_integer()) {
- // combined pair is product with integer power -> expand it
- *it=split_ex_to_pair(recombine_pair_to_ex(*it));
- return true;
- }
- if (is_ex_exactly_of_type((*it).rest,numeric)) {
- expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
- if (!ep.is_equal(*it)) {
- // combined pair is a numeric power which can be simplified
- *it=ep;
- return true;
- }
- if (ex_to_numeric((*it).coeff).is_equal(_num1())) {
- // combined pair has coeff 1 and must be moved to the end
- return true;
- }
- }
- return false;
+ if (is_ex_exactly_of_type((*it).rest,mul) &&
+ ex_to_numeric((*it).coeff).is_integer()) {
+ // combined pair is product with integer power -> expand it
+ *it=split_ex_to_pair(recombine_pair_to_ex(*it));
+ return true;
+ }
+ if (is_ex_exactly_of_type((*it).rest,numeric)) {
+ expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
+ if (!ep.is_equal(*it)) {
+ // combined pair is a numeric power which can be simplified
+ *it=ep;
+ return true;
+ }
+ if (ex_to_numeric((*it).coeff).is_equal(_num1())) {
+ // combined pair has coeff 1 and must be moved to the end
+ return true;
+ }
+ }
+ return false;
}
ex mul::default_overall_coeff(void) const
{
- return _ex1();
+ return _ex1();
}
void mul::combine_overall_coeff(const ex & c)
{
- 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).mul_dyn(ex_to_numeric(c));
+ 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).mul_dyn(ex_to_numeric(c));
}
void mul::combine_overall_coeff(const ex & c1, const ex & c2)
{
- 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).
- mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
+ 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).
+ mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
}
bool mul::can_make_flat(const expair & p) const
{
- GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
- // this assertion will probably fail somewhere
- // it would require a more careful make_flat, obeying the power laws
- // probably should return true only if p.coeff is integer
- return ex_to_numeric(p.coeff).is_equal(_num1());
+ GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
+ // this assertion will probably fail somewhere
+ // it would require a more careful make_flat, obeying the power laws
+ // probably should return true only if p.coeff is integer
+ return ex_to_numeric(p.coeff).is_equal(_num1());
}
ex mul::expand(unsigned options) const
{
- if (flags & status_flags::expanded)
- return *this;
-
- exvector sub_expanded_seq;
- intvector positions_of_adds;
- intvector number_of_add_operands;
-
- epvector * expanded_seqp = expandchildren(options);
-
- const epvector & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
-
- positions_of_adds.resize(expanded_seq.size());
- number_of_add_operands.resize(expanded_seq.size());
-
- int number_of_adds = 0;
- int number_of_expanded_terms = 1;
-
- unsigned current_position = 0;
- epvector::const_iterator last = expanded_seq.end();
- for (epvector::const_iterator cit = expanded_seq.begin(); cit!=last; ++cit) {
- if (is_ex_exactly_of_type((*cit).rest,add) &&
- ((*cit).coeff.is_equal(_ex1()))) {
- positions_of_adds[number_of_adds] = current_position;
- const add & expanded_addref = ex_to_add((*cit).rest);
- unsigned addref_nops = expanded_addref.nops();
- number_of_add_operands[number_of_adds] = addref_nops;
- number_of_expanded_terms *= addref_nops;
- ++number_of_adds;
- }
- ++current_position;
- }
-
- if (number_of_adds==0) {
- if (expanded_seqp==0)
- return this->setflag(status_flags::expanded);
- else
- return ((new mul(expanded_seqp,overall_coeff))->
- setflag(status_flags::dynallocated |
- status_flags::expanded));
- }
-
- exvector distrseq;
- distrseq.reserve(number_of_expanded_terms);
-
- intvector k;
- k.resize(number_of_adds, 0);
-
- while (1) {
- epvector term;
- term = expanded_seq;
- for (int l=0; l<number_of_adds; ++l) {
- const add & addref = ex_to_add(expanded_seq[positions_of_adds[l]].rest);
- GINAC_ASSERT(term[positions_of_adds[l]].coeff.compare(_ex1())==0);
- term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
- }
- distrseq.push_back((new mul(term,overall_coeff))->
- setflag(status_flags::dynallocated |
- status_flags::expanded));
-
- // increment k[]
- int l = number_of_adds-1;
- while ((l>=0) && ((++k[l])>=number_of_add_operands[l])) {
- k[l] = 0;
- --l;
- }
- if (l<0) break;
- }
-
- if (expanded_seqp!=0)
- delete expanded_seqp;
-
- return (new add(distrseq))->setflag(status_flags::dynallocated |
- status_flags::expanded);
+ if (flags & status_flags::expanded)
+ return *this;
+
+ exvector sub_expanded_seq;
+ intvector positions_of_adds;
+ intvector number_of_add_operands;
+
+ epvector * expanded_seqp = expandchildren(options);
+
+ const epvector & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
+
+ positions_of_adds.resize(expanded_seq.size());
+ number_of_add_operands.resize(expanded_seq.size());
+
+ int number_of_adds = 0;
+ int number_of_expanded_terms = 1;
+
+ unsigned current_position = 0;
+ epvector::const_iterator last = expanded_seq.end();
+ for (epvector::const_iterator cit = expanded_seq.begin(); cit!=last; ++cit) {
+ if (is_ex_exactly_of_type((*cit).rest,add) &&
+ ((*cit).coeff.is_equal(_ex1()))) {
+ positions_of_adds[number_of_adds] = current_position;
+ const add & expanded_addref = ex_to_add((*cit).rest);
+ unsigned addref_nops = expanded_addref.nops();
+ number_of_add_operands[number_of_adds] = addref_nops;
+ number_of_expanded_terms *= addref_nops;
+ ++number_of_adds;
+ }
+ ++current_position;
+ }
+
+ if (number_of_adds==0) {
+ if (expanded_seqp==0)
+ return this->setflag(status_flags::expanded);
+ else
+ return ((new mul(expanded_seqp,overall_coeff))->
+ setflag(status_flags::dynallocated |
+ status_flags::expanded));
+ }
+
+ exvector distrseq;
+ distrseq.reserve(number_of_expanded_terms);
+
+ intvector k;
+ k.resize(number_of_adds, 0);
+
+ for (;;) {
+ epvector term;
+ term = expanded_seq;
+ for (int l=0; l<number_of_adds; ++l) {
+ const add & addref = ex_to_add(expanded_seq[positions_of_adds[l]].rest);
+ GINAC_ASSERT(term[positions_of_adds[l]].coeff.compare(_ex1())==0);
+ term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
+ }
+ distrseq.push_back((new mul(term,overall_coeff))->
+ setflag(status_flags::dynallocated |
+ status_flags::expanded));
+
+ // increment k[]
+ int l = number_of_adds-1;
+ while ((l>=0) && ((++k[l])>=number_of_add_operands[l])) {
+ k[l] = 0;
+ --l;
+ }
+ if (l < 0) break;
+ }
+
+ if (expanded_seqp!=0)
+ delete expanded_seqp;
+
+ return (new add(distrseq))->setflag(status_flags::dynallocated |
+ status_flags::expanded);
}
//////////
epvector * mul::expandchildren(unsigned options) const
{
- epvector::const_iterator last = seq.end();
- epvector::const_iterator cit = seq.begin();
- while (cit!=last) {
- const ex & factor = recombine_pair_to_ex(*cit);
- const ex & expanded_factor = factor.expand(options);
- if (!are_ex_trivially_equal(factor,expanded_factor)) {
-
- // something changed, copy seq, eval 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(*cit2);
- ++cit2;
- }
- // copy first changed element
- s->push_back(split_ex_to_pair(expanded_factor));
- ++cit2;
- // copy rest
- while (cit2!=last) {
- s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
- ++cit2;
- }
- return s;
- }
- ++cit;
- }
-
- return 0; // nothing has changed
+ epvector::const_iterator last = seq.end();
+ epvector::const_iterator cit = seq.begin();
+ while (cit!=last) {
+ const ex & factor = recombine_pair_to_ex(*cit);
+ const ex & expanded_factor = factor.expand(options);
+ if (!are_ex_trivially_equal(factor,expanded_factor)) {
+
+ // something changed, copy seq, eval 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(*cit2);
+ ++cit2;
+ }
+ // copy first changed element
+ s->push_back(split_ex_to_pair(expanded_factor));
+ ++cit2;
+ // copy rest
+ while (cit2!=last) {
+ s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
+ ++cit2;
+ }
+ return s;
+ }
+ ++cit;
+ }
+
+ return 0; // nothing has changed
}
//////////
/** Product of expressions. */
class mul : public expairseq
{
- GINAC_DECLARE_REGISTERED_CLASS(mul, expairseq)
+ GINAC_DECLARE_REGISTERED_CLASS(mul, expairseq)
- friend class add;
- friend class ncmul;
- friend class power;
+ friend class add;
+ friend class ncmul;
+ friend class power;
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- mul();
- ~mul();
- mul(const mul & other);
- const mul & operator=(const mul & other);
+ mul();
+ ~mul();
+ mul(const mul & other);
+ const mul & operator=(const mul & other);
protected:
- void copy(const mul & other);
- void destroy(bool call_parent);
+ void copy(const mul & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- mul(const ex & lh, const ex & rh);
- mul(const exvector & v);
- mul(const epvector & v);
- mul(const epvector & v, const ex & oc);
- mul(epvector * vp, const ex & oc);
- mul(const ex & lh, const ex & mh, const ex & rh);
-
- // functions overriding virtual functions from bases classes
+ mul(const ex & lh, const ex & rh);
+ mul(const exvector & v);
+ mul(const epvector & v);
+ mul(const epvector & v, const ex & oc);
+ mul(epvector * vp, const ex & oc);
+ mul(const ex & lh, const ex & mh, const ex & rh);
+
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence) const;
- void printraw(std::ostream & os) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const;
- bool info(unsigned inf) const;
- int degree(const symbol & s) const;
- int ldegree(const symbol & s) const;
- ex coeff(const symbol & s, int n = 1) const;
- ex eval(int level=0) const;
- ex evalf(int level=0) const;
- ex series(const relational & s, int order, unsigned options = 0) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
- numeric integer_content(void) const;
- ex smod(const numeric &xi) const;
- numeric max_coefficient(void) const;
- exvector get_indices(void) const;
- ex simplify_ncmul(const exvector & v) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence) const;
+ void printraw(std::ostream & os) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const;
+ bool info(unsigned inf) const;
+ int degree(const symbol & s) const;
+ int ldegree(const symbol & s) const;
+ ex coeff(const symbol & s, int n = 1) const;
+ ex eval(int level=0) const;
+ ex evalf(int level=0) const;
+ ex series(const relational & s, int order, unsigned options = 0) const;
+ ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
+ numeric integer_content(void) const;
+ ex smod(const numeric &xi) const;
+ numeric max_coefficient(void) const;
+ exvector get_indices(void) const;
+ ex simplify_ncmul(const exvector & v) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- ex thisexpairseq(const epvector & v, const ex & oc) const;
- ex thisexpairseq(epvector * vp, const ex & oc) const;
- expair split_ex_to_pair(const ex & e) const;
- expair combine_ex_with_coeff_to_pair(const ex & e,
- const ex & c) const;
- expair combine_pair_with_coeff_to_pair(const expair & p,
- const ex & c) const;
- ex recombine_pair_to_ex(const expair & p) const;
- bool expair_needs_further_processing(epp it);
- ex default_overall_coeff(void) const;
- void combine_overall_coeff(const ex & c);
- void combine_overall_coeff(const ex & c1, const ex & c2);
- bool can_make_flat(const expair & p) const;
- ex expand(unsigned options=0) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+ ex thisexpairseq(const epvector & v, const ex & oc) const;
+ ex thisexpairseq(epvector * vp, const ex & oc) const;
+ expair split_ex_to_pair(const ex & e) const;
+ expair combine_ex_with_coeff_to_pair(const ex & e,
+ const ex & c) const;
+ expair combine_pair_with_coeff_to_pair(const expair & p,
+ const ex & c) const;
+ ex recombine_pair_to_ex(const expair & p) const;
+ bool expair_needs_further_processing(epp it);
+ ex default_overall_coeff(void) const;
+ void combine_overall_coeff(const ex & c);
+ void combine_overall_coeff(const ex & c1, const ex & c2);
+ bool can_make_flat(const expair & p) const;
+ ex expand(unsigned options=0) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
protected:
- epvector * expandchildren(unsigned options) const;
+ epvector * expandchildren(unsigned options) const;
// member variables
protected:
- static unsigned precedence;
+ static unsigned precedence;
};
// global constants
ncmul::ncmul()
{
- debugmsg("ncmul default constructor",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_ncmul;
+ debugmsg("ncmul default constructor",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_ncmul;
}
ncmul::~ncmul()
{
- debugmsg("ncmul destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("ncmul destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
ncmul::ncmul(const ncmul & other)
{
- debugmsg("ncmul copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("ncmul copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const ncmul & ncmul::operator=(const ncmul & other)
{
- debugmsg("ncmul operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("ncmul operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void ncmul::copy(const ncmul & other)
{
- inherited::copy(other);
+ inherited::copy(other);
}
void ncmul::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
//////////
// public
ncmul::ncmul(const ex & lh, const ex & rh) :
- inherited(lh,rh)
+ inherited(lh,rh)
{
- debugmsg("ncmul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_ncmul;
+ debugmsg("ncmul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_ncmul;
}
ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3) :
- inherited(f1,f2,f3)
+ inherited(f1,f2,f3)
{
- debugmsg("ncmul constructor from 3 ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_ncmul;
+ debugmsg("ncmul constructor from 3 ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_ncmul;
}
ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
- const ex & f4) : inherited(f1,f2,f3,f4)
+ const ex & f4) : inherited(f1,f2,f3,f4)
{
- debugmsg("ncmul constructor from 4 ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_ncmul;
+ debugmsg("ncmul constructor from 4 ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_ncmul;
}
ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
- const ex & f4, const ex & f5) : inherited(f1,f2,f3,f4,f5)
+ const ex & f4, const ex & f5) : inherited(f1,f2,f3,f4,f5)
{
- debugmsg("ncmul constructor from 5 ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_ncmul;
+ debugmsg("ncmul constructor from 5 ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_ncmul;
}
ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
- const ex & f4, const ex & f5, const ex & f6) :
- inherited(f1,f2,f3,f4,f5,f6)
+ const ex & f4, const ex & f5, const ex & f6) :
+ inherited(f1,f2,f3,f4,f5,f6)
{
- debugmsg("ncmul constructor from 6 ex",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_ncmul;
+ debugmsg("ncmul constructor from 6 ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_ncmul;
}
ncmul::ncmul(const exvector & v, bool discardable) : inherited(v,discardable)
{
- debugmsg("ncmul constructor from exvector,bool",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_ncmul;
+ debugmsg("ncmul constructor from exvector,bool",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_ncmul;
}
ncmul::ncmul(exvector * vp) : inherited(vp)
{
- debugmsg("ncmul constructor from exvector *",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_ncmul;
+ debugmsg("ncmul constructor from exvector *",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_ncmul;
}
//////////
/** Construct object from archive_node. */
ncmul::ncmul(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("ncmul constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ debugmsg("ncmul constructor from archive_node", LOGLEVEL_CONSTRUCT);
}
/** Unarchive the object. */
ex ncmul::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new ncmul(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new ncmul(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void ncmul::archive(archive_node &n) const
{
- inherited::archive(n);
+ inherited::archive(n);
}
-
+
//////////
// functions overriding virtual functions from bases classes
//////////
basic * ncmul::duplicate() const
{
- debugmsg("ncmul duplicate",LOGLEVEL_ASSIGNMENT);
- return new ncmul(*this);
+ debugmsg("ncmul duplicate",LOGLEVEL_ASSIGNMENT);
+ return new ncmul(*this);
}
void ncmul::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("ncmul print",LOGLEVEL_PRINT);
- printseq(os,'(','%',')',precedence,upper_precedence);
+ debugmsg("ncmul print",LOGLEVEL_PRINT);
+ printseq(os,'(','%',')',precedence,upper_precedence);
}
void ncmul::printraw(std::ostream & os) const
{
- debugmsg("ncmul printraw",LOGLEVEL_PRINT);
+ debugmsg("ncmul printraw",LOGLEVEL_PRINT);
- os << "%(";
- for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- (*it).bp->printraw(os);
- os << ",";
- }
- os << ",hash=" << hashvalue << ",flags=" << flags;
- os << ")";
+ os << "%(";
+ for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ (*it).bp->printraw(os);
+ os << ",";
+ }
+ os << ",hash=" << hashvalue << ",flags=" << flags;
+ os << ")";
}
void ncmul::printcsrc(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("ncmul print csrc",LOGLEVEL_PRINT);
- exvector::const_iterator it;
- exvector::const_iterator itend = seq.end()-1;
- os << "ncmul(";
- for (it=seq.begin(); it!=itend; ++it) {
- (*it).bp->printcsrc(os,precedence);
- os << ",";
- }
- (*it).bp->printcsrc(os,precedence);
- os << ")";
+ debugmsg("ncmul print csrc",LOGLEVEL_PRINT);
+ exvector::const_iterator it;
+ exvector::const_iterator itend = seq.end()-1;
+ os << "ncmul(";
+ for (it=seq.begin(); it!=itend; ++it) {
+ (*it).bp->printcsrc(os,precedence);
+ os << ",";
+ }
+ (*it).bp->printcsrc(os,precedence);
+ os << ")";
}
bool ncmul::info(unsigned inf) const
{
- throw(std::logic_error("which flags have to be implemented in ncmul::info()?"));
+ throw(std::logic_error("which flags have to be implemented in ncmul::info()?"));
}
typedef std::vector<int> intvector;
ex ncmul::expand(unsigned options) const
{
- exvector sub_expanded_seq;
- intvector positions_of_adds;
- intvector number_of_add_operands;
-
- exvector expanded_seq=expandchildren(options);
-
- positions_of_adds.resize(expanded_seq.size());
- number_of_add_operands.resize(expanded_seq.size());
-
- int number_of_adds=0;
- int number_of_expanded_terms=1;
-
- unsigned current_position=0;
- exvector::const_iterator last=expanded_seq.end();
- for (exvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
- if (is_ex_exactly_of_type((*cit),add)) {
- positions_of_adds[number_of_adds]=current_position;
- const add & expanded_addref=ex_to_add(*cit);
- number_of_add_operands[number_of_adds]=expanded_addref.seq.size();
- number_of_expanded_terms *= expanded_addref.seq.size();
- number_of_adds++;
- }
- current_position++;
- }
-
- if (number_of_adds==0) {
- return (new ncmul(expanded_seq,1))->setflag(status_flags::dynallocated ||
- status_flags::expanded);
- }
-
- exvector distrseq;
- distrseq.reserve(number_of_expanded_terms);
-
- intvector k;
- k.resize(number_of_adds);
-
- int l;
- for (l=0; l<number_of_adds; l++) {
- k[l]=0;
- }
-
- while (1) {
- exvector term;
- term=expanded_seq;
- for (l=0; l<number_of_adds; l++) {
- GINAC_ASSERT(is_ex_exactly_of_type(expanded_seq[positions_of_adds[l]],add));
- const add & addref=ex_to_add(expanded_seq[positions_of_adds[l]]);
- term[positions_of_adds[l]]=addref.recombine_pair_to_ex(addref.seq[k[l]]);
- }
- distrseq.push_back((new ncmul(term,1))->setflag(status_flags::dynallocated |
- status_flags::expanded));
-
- // increment k[]
- l=number_of_adds-1;
- while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
- k[l]=0;
- l--;
- }
- if (l<0) break;
- }
-
- return (new add(distrseq))->setflag(status_flags::dynallocated |
- status_flags::expanded);
+ exvector sub_expanded_seq;
+ intvector positions_of_adds;
+ intvector number_of_add_operands;
+
+ exvector expanded_seq=expandchildren(options);
+
+ positions_of_adds.resize(expanded_seq.size());
+ number_of_add_operands.resize(expanded_seq.size());
+
+ int number_of_adds=0;
+ int number_of_expanded_terms=1;
+
+ unsigned current_position=0;
+ exvector::const_iterator last=expanded_seq.end();
+ for (exvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
+ if (is_ex_exactly_of_type((*cit),add)) {
+ positions_of_adds[number_of_adds]=current_position;
+ const add & expanded_addref=ex_to_add(*cit);
+ number_of_add_operands[number_of_adds]=expanded_addref.seq.size();
+ number_of_expanded_terms *= expanded_addref.seq.size();
+ number_of_adds++;
+ }
+ current_position++;
+ }
+
+ if (number_of_adds==0) {
+ return (new ncmul(expanded_seq,1))->setflag(status_flags::dynallocated ||
+ status_flags::expanded);
+ }
+
+ exvector distrseq;
+ distrseq.reserve(number_of_expanded_terms);
+
+ intvector k;
+ k.resize(number_of_adds);
+
+ int l;
+ for (l=0; l<number_of_adds; l++) {
+ k[l]=0;
+ }
+
+ while (1) {
+ exvector term;
+ term=expanded_seq;
+ for (l=0; l<number_of_adds; l++) {
+ GINAC_ASSERT(is_ex_exactly_of_type(expanded_seq[positions_of_adds[l]],add));
+ const add & addref=ex_to_add(expanded_seq[positions_of_adds[l]]);
+ term[positions_of_adds[l]]=addref.recombine_pair_to_ex(addref.seq[k[l]]);
+ }
+ distrseq.push_back((new ncmul(term,1))->setflag(status_flags::dynallocated |
+ status_flags::expanded));
+
+ // increment k[]
+ l=number_of_adds-1;
+ while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
+ k[l]=0;
+ l--;
+ }
+ if (l<0) break;
+ }
+
+ return (new add(distrseq))->setflag(status_flags::dynallocated |
+ status_flags::expanded);
}
int ncmul::degree(const symbol & s) const
{
- int deg_sum=0;
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- deg_sum+=(*cit).degree(s);
- }
- return deg_sum;
+ int deg_sum=0;
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ deg_sum+=(*cit).degree(s);
+ }
+ return deg_sum;
}
int ncmul::ldegree(const symbol & s) const
{
- int deg_sum=0;
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- deg_sum+=(*cit).ldegree(s);
- }
- return deg_sum;
+ int deg_sum=0;
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ deg_sum+=(*cit).ldegree(s);
+ }
+ return deg_sum;
}
ex ncmul::coeff(const symbol & s, int n) const
{
- exvector coeffseq;
- coeffseq.reserve(seq.size());
-
- if (n==0) {
- // product of individual coeffs
- // if a non-zero power of s is found, the resulting product will be 0
- exvector::const_iterator it=seq.begin();
- while (it!=seq.end()) {
- coeffseq.push_back((*it).coeff(s,n));
- ++it;
- }
- return (new ncmul(coeffseq,1))->setflag(status_flags::dynallocated);
- }
-
- exvector::const_iterator it=seq.begin();
- bool coeff_found=0;
- while (it!=seq.end()) {
- ex c=(*it).coeff(s,n);
- if (!c.is_zero()) {
- coeffseq.push_back(c);
- coeff_found=1;
- } else {
- coeffseq.push_back(*it);
- }
- ++it;
- }
-
- if (coeff_found) return (new ncmul(coeffseq,1))->setflag(status_flags::dynallocated);
-
- return _ex0();
+ exvector coeffseq;
+ coeffseq.reserve(seq.size());
+
+ if (n==0) {
+ // product of individual coeffs
+ // if a non-zero power of s is found, the resulting product will be 0
+ exvector::const_iterator it=seq.begin();
+ while (it!=seq.end()) {
+ coeffseq.push_back((*it).coeff(s,n));
+ ++it;
+ }
+ return (new ncmul(coeffseq,1))->setflag(status_flags::dynallocated);
+ }
+
+ exvector::const_iterator it=seq.begin();
+ bool coeff_found=0;
+ while (it!=seq.end()) {
+ ex c=(*it).coeff(s,n);
+ if (!c.is_zero()) {
+ coeffseq.push_back(c);
+ coeff_found=1;
+ } else {
+ coeffseq.push_back(*it);
+ }
+ ++it;
+ }
+
+ if (coeff_found) return (new ncmul(coeffseq,1))->setflag(status_flags::dynallocated);
+
+ return _ex0();
}
unsigned ncmul::count_factors(const ex & e) const
{
- if ((is_ex_exactly_of_type(e,mul)&&(e.return_type()!=return_types::commutative))||
- (is_ex_exactly_of_type(e,ncmul))) {
- unsigned factors=0;
- for (unsigned i=0; i<e.nops(); i++)
- factors += count_factors(e.op(i));
-
- return factors;
- }
- return 1;
-}
-
+ if ((is_ex_exactly_of_type(e,mul)&&(e.return_type()!=return_types::commutative))||
+ (is_ex_exactly_of_type(e,ncmul))) {
+ unsigned factors=0;
+ for (unsigned i=0; i<e.nops(); i++)
+ factors += count_factors(e.op(i));
+
+ return factors;
+ }
+ return 1;
+}
+
void ncmul::append_factors(exvector & v, const ex & e) const
{
- if ((is_ex_exactly_of_type(e,mul)&&(e.return_type()!=return_types::commutative))||
- (is_ex_exactly_of_type(e,ncmul))) {
- for (unsigned i=0; i<e.nops(); i++)
- append_factors(v,e.op(i));
-
- return;
- }
- v.push_back(e);
+ if ((is_ex_exactly_of_type(e,mul)&&(e.return_type()!=return_types::commutative))||
+ (is_ex_exactly_of_type(e,ncmul))) {
+ for (unsigned i=0; i<e.nops(); i++)
+ append_factors(v,e.op(i));
+
+ return;
+ }
+ v.push_back(e);
}
typedef std::vector<unsigned> unsignedvector;
ex ncmul::eval(int level) const
{
- // simplifications: ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
- // ncmul(...,x1,x2,...,x3,x4,...) (associativity)
- // ncmul(x) -> x
- // ncmul() -> 1
- // ncmul(...,c1,...,c2,...) ->
- // *(c1,c2,ncmul(...)) (pull out commutative elements)
- // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
- // (collect elements of same type)
- // ncmul(x1,x2,x3,...) -> x::eval_ncmul(x1,x2,x3,...)
- // the following rule would be nice, but produces a recursion,
- // which must be trapped by introducing a flag that the sub-ncmuls()
- // are already evaluated (maybe later...)
- // ncmul(x1,x2,...,X,y1,y2,...) ->
- // ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
- // (X noncommutative_composite)
-
- if ((level==1)&&(flags & status_flags::evaluated)) {
- return *this;
- }
-
- exvector evaledseq=evalchildren(level);
-
- // ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
- // ncmul(...,x1,x2,...,x3,x4,...) (associativity)
- unsigned factors=0;
- for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
- factors += count_factors(*cit);
- }
-
- exvector assocseq;
- assocseq.reserve(factors);
- for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
- append_factors(assocseq,*cit);
- }
-
- // ncmul(x) -> x
- if (assocseq.size()==1) return *(seq.begin());
-
- // ncmul() -> 1
- if (assocseq.size()==0) return _ex1();
-
- // determine return types
- unsignedvector rettypes;
- rettypes.reserve(assocseq.size());
- unsigned i=0;
- unsigned count_commutative=0;
- unsigned count_noncommutative=0;
- unsigned count_noncommutative_composite=0;
- for (exvector::const_iterator cit=assocseq.begin(); cit!=assocseq.end(); ++cit) {
- switch (rettypes[i]=(*cit).return_type()) {
- case return_types::commutative:
- count_commutative++;
- break;
- case return_types::noncommutative:
- count_noncommutative++;
- break;
- case return_types::noncommutative_composite:
- count_noncommutative_composite++;
- break;
- default:
- throw(std::logic_error("ncmul::eval(): invalid return type"));
- }
- ++i;
- }
- GINAC_ASSERT(count_commutative+count_noncommutative+count_noncommutative_composite==assocseq.size());
-
- // ncmul(...,c1,...,c2,...) ->
- // *(c1,c2,ncmul(...)) (pull out commutative elements)
- if (count_commutative!=0) {
- exvector commutativeseq;
- commutativeseq.reserve(count_commutative+1);
- exvector noncommutativeseq;
- noncommutativeseq.reserve(assocseq.size()-count_commutative);
- for (i=0; i<assocseq.size(); ++i) {
- if (rettypes[i]==return_types::commutative) {
- commutativeseq.push_back(assocseq[i]);
- } else {
- noncommutativeseq.push_back(assocseq[i]);
- }
- }
- commutativeseq.push_back((new ncmul(noncommutativeseq,1))->
- setflag(status_flags::dynallocated));
- return (new mul(commutativeseq))->setflag(status_flags::dynallocated);
- }
-
- // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
- // (collect elements of same type)
-
- if (count_noncommutative_composite==0) {
- // there are neither commutative nor noncommutative_composite
- // elements in assocseq
- GINAC_ASSERT(count_commutative==0);
-
- exvectorvector evv;
- unsignedvector rttinfos;
- evv.reserve(assocseq.size());
- rttinfos.reserve(assocseq.size());
-
- for (exvector::const_iterator cit=assocseq.begin(); cit!=assocseq.end(); ++cit) {
- unsigned ti=(*cit).return_type_tinfo();
- // search type in vector of known types
- for (i=0; i<rttinfos.size(); ++i) {
- if (ti==rttinfos[i]) {
- evv[i].push_back(*cit);
- break;
- }
- }
- if (i>=rttinfos.size()) {
- // new type
- rttinfos.push_back(ti);
- evv.push_back(exvector());
- (*(evv.end()-1)).reserve(assocseq.size());
- (*(evv.end()-1)).push_back(*cit);
- }
- }
+ // simplifications: ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
+ // ncmul(...,x1,x2,...,x3,x4,...) (associativity)
+ // ncmul(x) -> x
+ // ncmul() -> 1
+ // ncmul(...,c1,...,c2,...) ->
+ // *(c1,c2,ncmul(...)) (pull out commutative elements)
+ // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
+ // (collect elements of same type)
+ // ncmul(x1,x2,x3,...) -> x::eval_ncmul(x1,x2,x3,...)
+ // the following rule would be nice, but produces a recursion,
+ // which must be trapped by introducing a flag that the sub-ncmuls()
+ // are already evaluated (maybe later...)
+ // ncmul(x1,x2,...,X,y1,y2,...) ->
+ // ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
+ // (X noncommutative_composite)
+
+ if ((level==1)&&(flags & status_flags::evaluated)) {
+ return *this;
+ }
+
+ exvector evaledseq=evalchildren(level);
+
+ // ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
+ // ncmul(...,x1,x2,...,x3,x4,...) (associativity)
+ unsigned factors=0;
+ for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
+ factors += count_factors(*cit);
+ }
+
+ exvector assocseq;
+ assocseq.reserve(factors);
+ for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
+ append_factors(assocseq,*cit);
+ }
+
+ // ncmul(x) -> x
+ if (assocseq.size()==1) return *(seq.begin());
+
+ // ncmul() -> 1
+ if (assocseq.size()==0) return _ex1();
+
+ // determine return types
+ unsignedvector rettypes;
+ rettypes.reserve(assocseq.size());
+ unsigned i=0;
+ unsigned count_commutative=0;
+ unsigned count_noncommutative=0;
+ unsigned count_noncommutative_composite=0;
+ for (exvector::const_iterator cit=assocseq.begin(); cit!=assocseq.end(); ++cit) {
+ switch (rettypes[i]=(*cit).return_type()) {
+ case return_types::commutative:
+ count_commutative++;
+ break;
+ case return_types::noncommutative:
+ count_noncommutative++;
+ break;
+ case return_types::noncommutative_composite:
+ count_noncommutative_composite++;
+ break;
+ default:
+ throw(std::logic_error("ncmul::eval(): invalid return type"));
+ }
+ ++i;
+ }
+ GINAC_ASSERT(count_commutative+count_noncommutative+count_noncommutative_composite==assocseq.size());
+
+ // ncmul(...,c1,...,c2,...) ->
+ // *(c1,c2,ncmul(...)) (pull out commutative elements)
+ if (count_commutative!=0) {
+ exvector commutativeseq;
+ commutativeseq.reserve(count_commutative+1);
+ exvector noncommutativeseq;
+ noncommutativeseq.reserve(assocseq.size()-count_commutative);
+ for (i=0; i<assocseq.size(); ++i) {
+ if (rettypes[i]==return_types::commutative) {
+ commutativeseq.push_back(assocseq[i]);
+ } else {
+ noncommutativeseq.push_back(assocseq[i]);
+ }
+ }
+ commutativeseq.push_back((new ncmul(noncommutativeseq,1))->
+ setflag(status_flags::dynallocated));
+ return (new mul(commutativeseq))->setflag(status_flags::dynallocated);
+ }
+
+ // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
+ // (collect elements of same type)
+
+ if (count_noncommutative_composite==0) {
+ // there are neither commutative nor noncommutative_composite
+ // elements in assocseq
+ GINAC_ASSERT(count_commutative==0);
+
+ exvectorvector evv;
+ unsignedvector rttinfos;
+ evv.reserve(assocseq.size());
+ rttinfos.reserve(assocseq.size());
+
+ for (exvector::const_iterator cit=assocseq.begin(); cit!=assocseq.end(); ++cit) {
+ unsigned ti=(*cit).return_type_tinfo();
+ // search type in vector of known types
+ for (i=0; i<rttinfos.size(); ++i) {
+ if (ti==rttinfos[i]) {
+ evv[i].push_back(*cit);
+ break;
+ }
+ }
+ if (i>=rttinfos.size()) {
+ // new type
+ rttinfos.push_back(ti);
+ evv.push_back(exvector());
+ (*(evv.end()-1)).reserve(assocseq.size());
+ (*(evv.end()-1)).push_back(*cit);
+ }
+ }
#ifdef DO_GINAC_ASSERT
- GINAC_ASSERT(evv.size()==rttinfos.size());
- GINAC_ASSERT(evv.size()>0);
- unsigned s=0;
- for (i=0; i<evv.size(); ++i) {
- s += evv[i].size();
- }
- GINAC_ASSERT(s==assocseq.size());
+ GINAC_ASSERT(evv.size()==rttinfos.size());
+ GINAC_ASSERT(evv.size()>0);
+ unsigned s=0;
+ for (i=0; i<evv.size(); ++i) {
+ s += evv[i].size();
+ }
+ GINAC_ASSERT(s==assocseq.size());
#endif // def DO_GINAC_ASSERT
-
- // if all elements are of same type, simplify the string
- if (evv.size()==1) {
- return evv[0][0].simplify_ncmul(evv[0]);
- }
-
- exvector splitseq;
- splitseq.reserve(evv.size());
- for (i=0; i<evv.size(); ++i) {
- splitseq.push_back((new ncmul(evv[i]))->
- setflag(status_flags::dynallocated));
- }
-
- return (new mul(splitseq))->setflag(status_flags::dynallocated);
- }
-
- return (new ncmul(assocseq))->setflag(status_flags::dynallocated |
- status_flags::evaluated);
+
+ // if all elements are of same type, simplify the string
+ if (evv.size()==1) {
+ return evv[0][0].simplify_ncmul(evv[0]);
+ }
+
+ exvector splitseq;
+ splitseq.reserve(evv.size());
+ for (i=0; i<evv.size(); ++i) {
+ splitseq.push_back((new ncmul(evv[i]))->
+ setflag(status_flags::dynallocated));
+ }
+
+ return (new mul(splitseq))->setflag(status_flags::dynallocated);
+ }
+
+ return (new ncmul(assocseq))->setflag(status_flags::dynallocated |
+ status_flags::evaluated);
}
exvector ncmul::get_indices(void) const
{
- // return union of indices of factors
- exvector iv;
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- exvector subiv=(*cit).get_indices();
- iv.reserve(iv.size()+subiv.size());
- for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
- iv.push_back(*cit2);
- }
- }
- return iv;
+ // return union of indices of factors
+ exvector iv;
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ exvector subiv=(*cit).get_indices();
+ iv.reserve(iv.size()+subiv.size());
+ for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
+ iv.push_back(*cit2);
+ }
+ }
+ return iv;
}
ex ncmul::subs(const lst & ls, const lst & lr) const
{
- return ncmul(subschildren(ls, lr));
+ return ncmul(subschildren(ls, lr));
}
ex ncmul::thisexprseq(const exvector & v) const
{
- return (new ncmul(v))->setflag(status_flags::dynallocated);
+ return (new ncmul(v))->setflag(status_flags::dynallocated);
}
ex ncmul::thisexprseq(exvector * vp) const
{
- return (new ncmul(vp))->setflag(status_flags::dynallocated);
+ return (new ncmul(vp))->setflag(status_flags::dynallocated);
}
// protected
* @see ex::diff */
ex ncmul::derivative(const symbol & s) const
{
- return _ex0();
+ return _ex0();
}
int ncmul::compare_same_type(const basic & other) const
{
- return inherited::compare_same_type(other);
+ return inherited::compare_same_type(other);
}
unsigned ncmul::return_type(void) const
{
- if (seq.size()==0) {
- // ncmul without factors: should not happen, but commutes
- return return_types::commutative;
- }
-
- bool all_commutative=1;
- unsigned rt;
- exvector::const_iterator cit_noncommutative_element; // point to first found nc element
-
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- rt=(*cit).return_type();
- if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
- if ((rt==return_types::noncommutative)&&(all_commutative)) {
- // first nc element found, remember position
- cit_noncommutative_element=cit;
- all_commutative=0;
- }
- if ((rt==return_types::noncommutative)&&(!all_commutative)) {
- // another nc element found, compare type_infos
- if ((*cit_noncommutative_element).return_type_tinfo()!=(*cit).return_type_tinfo()) {
- // diffent types -> mul is ncc
- return return_types::noncommutative_composite;
- }
- }
- }
- // all factors checked
- GINAC_ASSERT(!all_commutative); // not all factors should commute, because this is a ncmul();
- return all_commutative ? return_types::commutative : return_types::noncommutative;
+ if (seq.size()==0) {
+ // ncmul without factors: should not happen, but commutes
+ return return_types::commutative;
+ }
+
+ bool all_commutative=1;
+ unsigned rt;
+ exvector::const_iterator cit_noncommutative_element; // point to first found nc element
+
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ rt=(*cit).return_type();
+ if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
+ if ((rt==return_types::noncommutative)&&(all_commutative)) {
+ // first nc element found, remember position
+ cit_noncommutative_element=cit;
+ all_commutative=0;
+ }
+ if ((rt==return_types::noncommutative)&&(!all_commutative)) {
+ // another nc element found, compare type_infos
+ if ((*cit_noncommutative_element).return_type_tinfo()!=(*cit).return_type_tinfo()) {
+ // diffent types -> mul is ncc
+ return return_types::noncommutative_composite;
+ }
+ }
+ }
+ // all factors checked
+ GINAC_ASSERT(!all_commutative); // not all factors should commute, because this is a ncmul();
+ return all_commutative ? return_types::commutative : return_types::noncommutative;
}
unsigned ncmul::return_type_tinfo(void) const
{
- if (seq.size()==0) {
- // mul without factors: should not happen
- return tinfo_key;
- }
- // return type_info of first noncommutative element
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- if ((*cit).return_type()==return_types::noncommutative) {
- return (*cit).return_type_tinfo();
- }
- }
- // no noncommutative element found, should not happen
- return tinfo_key;
+ if (seq.size()==0) {
+ // mul without factors: should not happen
+ return tinfo_key;
+ }
+ // return type_info of first noncommutative element
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ if ((*cit).return_type()==return_types::noncommutative) {
+ return (*cit).return_type_tinfo();
+ }
+ }
+ // no noncommutative element found, should not happen
+ return tinfo_key;
}
//////////
exvector ncmul::expandchildren(unsigned options) const
{
- exvector s;
- s.reserve(seq.size());
+ exvector s;
+ s.reserve(seq.size());
- for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- s.push_back((*it).expand(options));
- }
- return s;
+ for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ s.push_back((*it).expand(options));
+ }
+ return s;
}
const exvector & ncmul::get_factors(void) const
{
- return seq;
+ return seq;
}
//////////
ex nonsimplified_ncmul(const exvector & v)
{
- return (new ncmul(v))->setflag(status_flags::dynallocated);
+ return (new ncmul(v))->setflag(status_flags::dynallocated);
}
ex simplified_ncmul(const exvector & v)
{
- if (v.size()==0) {
- return _ex1();
- } else if (v.size()==1) {
- return v[0];
- }
- return (new ncmul(v))->setflag(status_flags::dynallocated |
- status_flags::evaluated);
+ if (v.size()==0) {
+ return _ex1();
+ } else if (v.size()==1) {
+ return v[0];
+ }
+ return (new ncmul(v))->setflag(status_flags::dynallocated |
+ status_flags::evaluated);
}
#ifndef NO_NAMESPACE_GINAC
/** Non-commutative product of expressions. */
class ncmul : public exprseq
{
- GINAC_DECLARE_REGISTERED_CLASS(ncmul, exprseq)
+ GINAC_DECLARE_REGISTERED_CLASS(ncmul, exprseq)
- friend class power;
- friend ex nonsimplified_ncmul(const exvector & v);
- friend ex simplified_ncmul(const exvector & v);
+ friend class power;
+ friend ex nonsimplified_ncmul(const exvector & v);
+ friend ex simplified_ncmul(const exvector & v);
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- ncmul();
- ~ncmul();
- ncmul(const ncmul & other);
- const ncmul & operator=(const ncmul & other);
+ ncmul();
+ ~ncmul();
+ ncmul(const ncmul & other);
+ const ncmul & operator=(const ncmul & other);
protected:
- void copy(const ncmul & other);
- void destroy(bool call_parent);
+ void copy(const ncmul & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- ncmul(const ex & lh, const ex & rh);
- ncmul(const ex & f1, const ex & f2, const ex & f3);
- ncmul(const ex & f1, const ex & f2, const ex & f3,
- const ex & f4);
- ncmul(const ex & f1, const ex & f2, const ex & f3,
- const ex & f4, const ex & f5);
- ncmul(const ex & f1, const ex & f2, const ex & f3,
- const ex & f4, const ex & f5, const ex & f6);
- ncmul(const exvector & v, bool discardable=false);
- ncmul(exvector * vp); // vp will be deleted
-
- // functions overriding virtual functions from bases classes
+ ncmul(const ex & lh, const ex & rh);
+ ncmul(const ex & f1, const ex & f2, const ex & f3);
+ ncmul(const ex & f1, const ex & f2, const ex & f3,
+ const ex & f4);
+ ncmul(const ex & f1, const ex & f2, const ex & f3,
+ const ex & f4, const ex & f5);
+ ncmul(const ex & f1, const ex & f2, const ex & f3,
+ const ex & f4, const ex & f5, const ex & f6);
+ ncmul(const exvector & v, bool discardable=false);
+ ncmul(exvector * vp); // vp will be deleted
+
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence) const;
- void printraw(std::ostream & os) const;
- void printcsrc(std::ostream & os, unsigned upper_precedence) const;
- bool info(unsigned inf) const;
- int degree(const symbol & s) const;
- int ldegree(const symbol & s) const;
- ex expand(unsigned options=0) const;
- ex coeff(const symbol & s, int n=1) const;
- ex eval(int level=0) const;
- ex subs(const lst & ls, const lst & lr) const;
- exvector get_indices(void) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence) const;
+ void printraw(std::ostream & os) const;
+ void printcsrc(std::ostream & os, unsigned upper_precedence) const;
+ bool info(unsigned inf) const;
+ int degree(const symbol & s) const;
+ int ldegree(const symbol & s) const;
+ ex expand(unsigned options=0) const;
+ ex coeff(const symbol & s, int n=1) const;
+ ex eval(int level=0) const;
+ ex subs(const lst & ls, const lst & lr) const;
+ exvector get_indices(void) const;
+ ex thisexprseq(const exvector & v) const;
+ ex thisexprseq(exvector * vp) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
protected:
- unsigned count_factors(const ex & e) const;
- void append_factors(exvector & v, const ex & e) const;
- exvector expandchildren(unsigned options) const;
+ unsigned count_factors(const ex & e) const;
+ void append_factors(exvector & v, const ex & e) const;
+ exvector expandchildren(unsigned options) const;
public:
- const exvector & get_factors(void) const;
+ const exvector & get_factors(void) const;
// member variables
protected:
- static unsigned precedence;
+ static unsigned precedence;
};
// global constants
* @return "false" if no symbol was found, "true" otherwise */
static bool get_first_symbol(const ex &e, const symbol *&x)
{
- if (is_ex_exactly_of_type(e, symbol)) {
- x = static_cast<symbol *>(e.bp);
- return true;
- } else if (is_ex_exactly_of_type(e, add) || is_ex_exactly_of_type(e, mul)) {
- for (unsigned i=0; i<e.nops(); i++)
- if (get_first_symbol(e.op(i), x))
- return true;
- } else if (is_ex_exactly_of_type(e, power)) {
- if (get_first_symbol(e.op(0), x))
- return true;
- }
- return false;
+ if (is_ex_exactly_of_type(e, symbol)) {
+ x = static_cast<symbol *>(e.bp);
+ return true;
+ } else if (is_ex_exactly_of_type(e, add) || is_ex_exactly_of_type(e, mul)) {
+ for (unsigned i=0; i<e.nops(); i++)
+ if (get_first_symbol(e.op(i), x))
+ return true;
+ } else if (is_ex_exactly_of_type(e, power)) {
+ if (get_first_symbol(e.op(0), x))
+ return true;
+ }
+ return false;
}
*
* @see get_symbol_stats */
struct sym_desc {
- /** Pointer to symbol */
- const symbol *sym;
+ /** Pointer to symbol */
+ const symbol *sym;
- /** Highest degree of symbol in polynomial "a" */
- int deg_a;
+ /** Highest degree of symbol in polynomial "a" */
+ int deg_a;
- /** Highest degree of symbol in polynomial "b" */
- int deg_b;
+ /** Highest degree of symbol in polynomial "b" */
+ int deg_b;
- /** Lowest degree of symbol in polynomial "a" */
- int ldeg_a;
+ /** Lowest degree of symbol in polynomial "a" */
+ int ldeg_a;
- /** Lowest degree of symbol in polynomial "b" */
- int ldeg_b;
+ /** Lowest degree of symbol in polynomial "b" */
+ int ldeg_b;
- /** Maximum of deg_a and deg_b (Used for sorting) */
- int max_deg;
+ /** Maximum of deg_a and deg_b (Used for sorting) */
+ int max_deg;
- /** Commparison operator for sorting */
- bool operator<(const sym_desc &x) const {return max_deg < x.max_deg;}
+ /** Commparison operator for sorting */
+ bool operator<(const sym_desc &x) const {return max_deg < x.max_deg;}
};
// Vector of sym_desc structures
// Add symbol the sym_desc_vec (used internally by get_symbol_stats())
static void add_symbol(const symbol *s, sym_desc_vec &v)
{
- sym_desc_vec::iterator it = v.begin(), itend = v.end();
- while (it != itend) {
- if (it->sym->compare(*s) == 0) // If it's already in there, don't add it a second time
- return;
- it++;
- }
- sym_desc d;
- d.sym = s;
- v.push_back(d);
+ sym_desc_vec::iterator it = v.begin(), itend = v.end();
+ while (it != itend) {
+ if (it->sym->compare(*s) == 0) // If it's already in there, don't add it a second time
+ return;
+ it++;
+ }
+ sym_desc d;
+ d.sym = s;
+ v.push_back(d);
}
// Collect all symbols of an expression (used internally by get_symbol_stats())
static void collect_symbols(const ex &e, sym_desc_vec &v)
{
- if (is_ex_exactly_of_type(e, symbol)) {
- add_symbol(static_cast<symbol *>(e.bp), v);
- } else if (is_ex_exactly_of_type(e, add) || is_ex_exactly_of_type(e, mul)) {
- for (unsigned i=0; i<e.nops(); i++)
- collect_symbols(e.op(i), v);
- } else if (is_ex_exactly_of_type(e, power)) {
- collect_symbols(e.op(0), v);
- }
+ if (is_ex_exactly_of_type(e, symbol)) {
+ add_symbol(static_cast<symbol *>(e.bp), v);
+ } else if (is_ex_exactly_of_type(e, add) || is_ex_exactly_of_type(e, mul)) {
+ for (unsigned i=0; i<e.nops(); i++)
+ collect_symbols(e.op(i), v);
+ } else if (is_ex_exactly_of_type(e, power)) {
+ collect_symbols(e.op(0), v);
+ }
}
/** Collect statistical information about symbols in polynomials.
* @param v vector of sym_desc structs (filled in) */
static void get_symbol_stats(const ex &a, const ex &b, sym_desc_vec &v)
{
- collect_symbols(a.eval(), v); // eval() to expand assigned symbols
- collect_symbols(b.eval(), v);
- sym_desc_vec::iterator it = v.begin(), itend = v.end();
- while (it != itend) {
- int deg_a = a.degree(*(it->sym));
- int deg_b = b.degree(*(it->sym));
- it->deg_a = deg_a;
- it->deg_b = deg_b;
- it->max_deg = max(deg_a, deg_b);
- it->ldeg_a = a.ldegree(*(it->sym));
- it->ldeg_b = b.ldegree(*(it->sym));
- it++;
- }
- sort(v.begin(), v.end());
+ collect_symbols(a.eval(), v); // eval() to expand assigned symbols
+ collect_symbols(b.eval(), v);
+ sym_desc_vec::iterator it = v.begin(), itend = v.end();
+ while (it != itend) {
+ int deg_a = a.degree(*(it->sym));
+ int deg_b = b.degree(*(it->sym));
+ it->deg_a = deg_a;
+ it->deg_b = deg_b;
+ it->max_deg = max(deg_a, deg_b);
+ it->ldeg_a = a.ldegree(*(it->sym));
+ it->ldeg_b = b.ldegree(*(it->sym));
+ it++;
+ }
+ sort(v.begin(), v.end());
#if 0
std::clog << "Symbols:\n";
it = v.begin(); itend = v.end();
// expression recursively (used internally by lcm_of_coefficients_denominators())
static numeric lcmcoeff(const ex &e, const numeric &l)
{
- if (e.info(info_flags::rational))
- return lcm(ex_to_numeric(e).denom(), l);
- else if (is_ex_exactly_of_type(e, add)) {
- numeric c = _num1();
- for (unsigned i=0; i<e.nops(); i++)
- c = lcmcoeff(e.op(i), c);
- return lcm(c, l);
- } else if (is_ex_exactly_of_type(e, mul)) {
- numeric c = _num1();
- for (unsigned i=0; i<e.nops(); i++)
- c *= lcmcoeff(e.op(i), _num1());
- return lcm(c, l);
- } else if (is_ex_exactly_of_type(e, power))
- return pow(lcmcoeff(e.op(0), l), ex_to_numeric(e.op(1)));
- return l;
+ if (e.info(info_flags::rational))
+ return lcm(ex_to_numeric(e).denom(), l);
+ else if (is_ex_exactly_of_type(e, add)) {
+ numeric c = _num1();
+ for (unsigned i=0; i<e.nops(); i++)
+ c = lcmcoeff(e.op(i), c);
+ return lcm(c, l);
+ } else if (is_ex_exactly_of_type(e, mul)) {
+ numeric c = _num1();
+ for (unsigned i=0; i<e.nops(); i++)
+ c *= lcmcoeff(e.op(i), _num1());
+ return lcm(c, l);
+ } else if (is_ex_exactly_of_type(e, power))
+ return pow(lcmcoeff(e.op(0), l), ex_to_numeric(e.op(1)));
+ return l;
}
/** Compute LCM of denominators of coefficients of a polynomial.
* @return LCM of denominators of coefficients */
static numeric lcm_of_coefficients_denominators(const ex &e)
{
- return lcmcoeff(e, _num1());
+ return lcmcoeff(e, _num1());
}
/** Bring polynomial from Q[X] to Z[X] by multiplying in the previously
* @return integer content */
numeric ex::integer_content(void) const
{
- GINAC_ASSERT(bp!=0);
- return bp->integer_content();
+ GINAC_ASSERT(bp!=0);
+ return bp->integer_content();
}
numeric basic::integer_content(void) const
{
- return _num1();
+ return _num1();
}
numeric numeric::integer_content(void) const
{
- return abs(*this);
+ return abs(*this);
}
numeric add::integer_content(void) const
{
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- numeric c = _num0();
- while (it != itend) {
- GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
- GINAC_ASSERT(is_ex_exactly_of_type(it->coeff,numeric));
- c = gcd(ex_to_numeric(it->coeff), c);
- it++;
- }
- GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
- c = gcd(ex_to_numeric(overall_coeff),c);
- return c;
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ numeric c = _num0();
+ while (it != itend) {
+ GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(it->coeff,numeric));
+ c = gcd(ex_to_numeric(it->coeff), c);
+ it++;
+ }
+ GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+ c = gcd(ex_to_numeric(overall_coeff),c);
+ return c;
}
numeric mul::integer_content(void) const
{
#ifdef DO_GINAC_ASSERT
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- while (it != itend) {
- GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
- ++it;
- }
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ while (it != itend) {
+ GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
+ ++it;
+ }
#endif // def DO_GINAC_ASSERT
- GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
- return abs(ex_to_numeric(overall_coeff));
+ GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+ return abs(ex_to_numeric(overall_coeff));
}
* @return quotient of a and b in Q[x] */
ex quo(const ex &a, const ex &b, const symbol &x, bool check_args)
{
- if (b.is_zero())
- throw(std::overflow_error("quo: division by zero"));
- if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric))
- return a / b;
+ if (b.is_zero())
+ throw(std::overflow_error("quo: division by zero"));
+ if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric))
+ return a / b;
#if FAST_COMPARE
- if (a.is_equal(b))
- return _ex1();
+ if (a.is_equal(b))
+ return _ex1();
#endif
- if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
- throw(std::invalid_argument("quo: arguments must be polynomials over the rationals"));
-
- // Polynomial long division
- ex q = _ex0();
- ex r = a.expand();
- if (r.is_zero())
- return r;
- int bdeg = b.degree(x);
- int rdeg = r.degree(x);
- ex blcoeff = b.expand().coeff(x, bdeg);
- bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
- while (rdeg >= bdeg) {
- ex term, rcoeff = r.coeff(x, rdeg);
- if (blcoeff_is_numeric)
- term = rcoeff / blcoeff;
- else {
- if (!divide(rcoeff, blcoeff, term, false))
- return *new ex(fail());
- }
- term *= power(x, rdeg - bdeg);
- q += term;
- r -= (term * b).expand();
- if (r.is_zero())
- break;
- rdeg = r.degree(x);
- }
- return q;
+ if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
+ throw(std::invalid_argument("quo: arguments must be polynomials over the rationals"));
+
+ // Polynomial long division
+ ex q = _ex0();
+ ex r = a.expand();
+ if (r.is_zero())
+ return r;
+ int bdeg = b.degree(x);
+ int rdeg = r.degree(x);
+ ex blcoeff = b.expand().coeff(x, bdeg);
+ bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
+ while (rdeg >= bdeg) {
+ ex term, rcoeff = r.coeff(x, rdeg);
+ if (blcoeff_is_numeric)
+ term = rcoeff / blcoeff;
+ else {
+ if (!divide(rcoeff, blcoeff, term, false))
+ return *new ex(fail());
+ }
+ term *= power(x, rdeg - bdeg);
+ q += term;
+ r -= (term * b).expand();
+ if (r.is_zero())
+ break;
+ rdeg = r.degree(x);
+ }
+ return q;
}
* @return remainder of a(x) and b(x) in Q[x] */
ex rem(const ex &a, const ex &b, const symbol &x, bool check_args)
{
- if (b.is_zero())
- throw(std::overflow_error("rem: division by zero"));
- if (is_ex_exactly_of_type(a, numeric)) {
- if (is_ex_exactly_of_type(b, numeric))
- return _ex0();
- else
- return b;
- }
+ if (b.is_zero())
+ throw(std::overflow_error("rem: division by zero"));
+ if (is_ex_exactly_of_type(a, numeric)) {
+ if (is_ex_exactly_of_type(b, numeric))
+ return _ex0();
+ else
+ return b;
+ }
#if FAST_COMPARE
- if (a.is_equal(b))
- return _ex0();
+ if (a.is_equal(b))
+ return _ex0();
#endif
- if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
- throw(std::invalid_argument("rem: arguments must be polynomials over the rationals"));
-
- // Polynomial long division
- ex r = a.expand();
- if (r.is_zero())
- return r;
- int bdeg = b.degree(x);
- int rdeg = r.degree(x);
- ex blcoeff = b.expand().coeff(x, bdeg);
- bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
- while (rdeg >= bdeg) {
- ex term, rcoeff = r.coeff(x, rdeg);
- if (blcoeff_is_numeric)
- term = rcoeff / blcoeff;
- else {
- if (!divide(rcoeff, blcoeff, term, false))
- return *new ex(fail());
- }
- term *= power(x, rdeg - bdeg);
- r -= (term * b).expand();
- if (r.is_zero())
- break;
- rdeg = r.degree(x);
- }
- return r;
+ if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
+ throw(std::invalid_argument("rem: arguments must be polynomials over the rationals"));
+
+ // Polynomial long division
+ ex r = a.expand();
+ if (r.is_zero())
+ return r;
+ int bdeg = b.degree(x);
+ int rdeg = r.degree(x);
+ ex blcoeff = b.expand().coeff(x, bdeg);
+ bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
+ while (rdeg >= bdeg) {
+ ex term, rcoeff = r.coeff(x, rdeg);
+ if (blcoeff_is_numeric)
+ term = rcoeff / blcoeff;
+ else {
+ if (!divide(rcoeff, blcoeff, term, false))
+ return *new ex(fail());
+ }
+ term *= power(x, rdeg - bdeg);
+ r -= (term * b).expand();
+ if (r.is_zero())
+ break;
+ rdeg = r.degree(x);
+ }
+ return r;
}
* @return pseudo-remainder of a(x) and b(x) in Z[x] */
ex prem(const ex &a, const ex &b, const symbol &x, bool check_args)
{
- if (b.is_zero())
- throw(std::overflow_error("prem: division by zero"));
- if (is_ex_exactly_of_type(a, numeric)) {
- if (is_ex_exactly_of_type(b, numeric))
- return _ex0();
- else
- return b;
- }
- if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
- throw(std::invalid_argument("prem: arguments must be polynomials over the rationals"));
-
- // Polynomial long division
- ex r = a.expand();
- ex eb = b.expand();
- int rdeg = r.degree(x);
- int bdeg = eb.degree(x);
- ex blcoeff;
- if (bdeg <= rdeg) {
- blcoeff = eb.coeff(x, bdeg);
- if (bdeg == 0)
- eb = _ex0();
- else
- eb -= blcoeff * power(x, bdeg);
- } else
- blcoeff = _ex1();
-
- int delta = rdeg - bdeg + 1, i = 0;
- while (rdeg >= bdeg && !r.is_zero()) {
- ex rlcoeff = r.coeff(x, rdeg);
- ex term = (power(x, rdeg - bdeg) * eb * rlcoeff).expand();
- if (rdeg == 0)
- r = _ex0();
- else
- r -= rlcoeff * power(x, rdeg);
- r = (blcoeff * r).expand() - term;
- rdeg = r.degree(x);
- i++;
- }
- return power(blcoeff, delta - i) * r;
+ if (b.is_zero())
+ throw(std::overflow_error("prem: division by zero"));
+ if (is_ex_exactly_of_type(a, numeric)) {
+ if (is_ex_exactly_of_type(b, numeric))
+ return _ex0();
+ else
+ return b;
+ }
+ if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
+ throw(std::invalid_argument("prem: arguments must be polynomials over the rationals"));
+
+ // Polynomial long division
+ ex r = a.expand();
+ ex eb = b.expand();
+ int rdeg = r.degree(x);
+ int bdeg = eb.degree(x);
+ ex blcoeff;
+ if (bdeg <= rdeg) {
+ blcoeff = eb.coeff(x, bdeg);
+ if (bdeg == 0)
+ eb = _ex0();
+ else
+ eb -= blcoeff * power(x, bdeg);
+ } else
+ blcoeff = _ex1();
+
+ int delta = rdeg - bdeg + 1, i = 0;
+ while (rdeg >= bdeg && !r.is_zero()) {
+ ex rlcoeff = r.coeff(x, rdeg);
+ ex term = (power(x, rdeg - bdeg) * eb * rlcoeff).expand();
+ if (rdeg == 0)
+ r = _ex0();
+ else
+ r -= rlcoeff * power(x, rdeg);
+ r = (blcoeff * r).expand() - term;
+ rdeg = r.degree(x);
+ i++;
+ }
+ return power(blcoeff, delta - i) * r;
}
ex sprem(const ex &a, const ex &b, const symbol &x, bool check_args)
{
- if (b.is_zero())
- throw(std::overflow_error("prem: division by zero"));
- if (is_ex_exactly_of_type(a, numeric)) {
- if (is_ex_exactly_of_type(b, numeric))
- return _ex0();
- else
- return b;
- }
- if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
- throw(std::invalid_argument("prem: arguments must be polynomials over the rationals"));
-
- // Polynomial long division
- ex r = a.expand();
- ex eb = b.expand();
- int rdeg = r.degree(x);
- int bdeg = eb.degree(x);
- ex blcoeff;
- if (bdeg <= rdeg) {
- blcoeff = eb.coeff(x, bdeg);
- if (bdeg == 0)
- eb = _ex0();
- else
- eb -= blcoeff * power(x, bdeg);
- } else
- blcoeff = _ex1();
-
- while (rdeg >= bdeg && !r.is_zero()) {
- ex rlcoeff = r.coeff(x, rdeg);
- ex term = (power(x, rdeg - bdeg) * eb * rlcoeff).expand();
- if (rdeg == 0)
- r = _ex0();
- else
- r -= rlcoeff * power(x, rdeg);
- r = (blcoeff * r).expand() - term;
- rdeg = r.degree(x);
- }
- return r;
+ if (b.is_zero())
+ throw(std::overflow_error("prem: division by zero"));
+ if (is_ex_exactly_of_type(a, numeric)) {
+ if (is_ex_exactly_of_type(b, numeric))
+ return _ex0();
+ else
+ return b;
+ }
+ if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
+ throw(std::invalid_argument("prem: arguments must be polynomials over the rationals"));
+
+ // Polynomial long division
+ ex r = a.expand();
+ ex eb = b.expand();
+ int rdeg = r.degree(x);
+ int bdeg = eb.degree(x);
+ ex blcoeff;
+ if (bdeg <= rdeg) {
+ blcoeff = eb.coeff(x, bdeg);
+ if (bdeg == 0)
+ eb = _ex0();
+ else
+ eb -= blcoeff * power(x, bdeg);
+ } else
+ blcoeff = _ex1();
+
+ while (rdeg >= bdeg && !r.is_zero()) {
+ ex rlcoeff = r.coeff(x, rdeg);
+ ex term = (power(x, rdeg - bdeg) * eb * rlcoeff).expand();
+ if (rdeg == 0)
+ r = _ex0();
+ else
+ r -= rlcoeff * power(x, rdeg);
+ r = (blcoeff * r).expand() - term;
+ rdeg = r.degree(x);
+ }
+ return r;
}
* "false" otherwise */
bool divide(const ex &a, const ex &b, ex &q, bool check_args)
{
- q = _ex0();
- if (b.is_zero())
- throw(std::overflow_error("divide: division by zero"));
- if (a.is_zero())
- return true;
- if (is_ex_exactly_of_type(b, numeric)) {
- q = a / b;
- return true;
- } else if (is_ex_exactly_of_type(a, numeric))
- return false;
+ q = _ex0();
+ if (b.is_zero())
+ throw(std::overflow_error("divide: division by zero"));
+ if (a.is_zero())
+ return true;
+ if (is_ex_exactly_of_type(b, numeric)) {
+ q = a / b;
+ return true;
+ } else if (is_ex_exactly_of_type(a, numeric))
+ return false;
#if FAST_COMPARE
- if (a.is_equal(b)) {
- q = _ex1();
- return true;
- }
+ if (a.is_equal(b)) {
+ q = _ex1();
+ return true;
+ }
#endif
- if (check_args && (!a.info(info_flags::rational_polynomial) ||
- !b.info(info_flags::rational_polynomial)))
- throw(std::invalid_argument("divide: arguments must be polynomials over the rationals"));
-
- // Find first symbol
- const symbol *x;
- if (!get_first_symbol(a, x) && !get_first_symbol(b, x))
- throw(std::invalid_argument("invalid expression in divide()"));
-
- // Polynomial long division (recursive)
- ex r = a.expand();
- if (r.is_zero())
- return true;
- int bdeg = b.degree(*x);
- int rdeg = r.degree(*x);
- ex blcoeff = b.expand().coeff(*x, bdeg);
- bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
- while (rdeg >= bdeg) {
- ex term, rcoeff = r.coeff(*x, rdeg);
- if (blcoeff_is_numeric)
- term = rcoeff / blcoeff;
- else
- if (!divide(rcoeff, blcoeff, term, false))
- return false;
- term *= power(*x, rdeg - bdeg);
- q += term;
- r -= (term * b).expand();
- if (r.is_zero())
- return true;
- rdeg = r.degree(*x);
- }
- return false;
+ if (check_args && (!a.info(info_flags::rational_polynomial) ||
+ !b.info(info_flags::rational_polynomial)))
+ throw(std::invalid_argument("divide: arguments must be polynomials over the rationals"));
+
+ // Find first symbol
+ const symbol *x;
+ if (!get_first_symbol(a, x) && !get_first_symbol(b, x))
+ throw(std::invalid_argument("invalid expression in divide()"));
+
+ // Polynomial long division (recursive)
+ ex r = a.expand();
+ if (r.is_zero())
+ return true;
+ int bdeg = b.degree(*x);
+ int rdeg = r.degree(*x);
+ ex blcoeff = b.expand().coeff(*x, bdeg);
+ bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
+ while (rdeg >= bdeg) {
+ ex term, rcoeff = r.coeff(*x, rdeg);
+ if (blcoeff_is_numeric)
+ term = rcoeff / blcoeff;
+ else
+ if (!divide(rcoeff, blcoeff, term, false))
+ return false;
+ term *= power(*x, rdeg - bdeg);
+ q += term;
+ r -= (term * b).expand();
+ if (r.is_zero())
+ return true;
+ rdeg = r.degree(*x);
+ }
+ return false;
}
typedef std::pair<ex, bool> exbool;
struct ex2_less {
- bool operator() (const ex2 p, const ex2 q) const
- {
- return p.first.compare(q.first) < 0 || (!(q.first.compare(p.first) < 0) && p.second.compare(q.second) < 0);
- }
+ bool operator() (const ex2 p, const ex2 q) const
+ {
+ return p.first.compare(q.first) < 0 || (!(q.first.compare(p.first) < 0) && p.second.compare(q.second) < 0);
+ }
};
typedef std::map<ex2, exbool, ex2_less> ex2_exbool_remember;
* @see get_symbol_stats, heur_gcd */
static bool divide_in_z(const ex &a, const ex &b, ex &q, sym_desc_vec::const_iterator var)
{
- q = _ex0();
- if (b.is_zero())
- throw(std::overflow_error("divide_in_z: division by zero"));
- if (b.is_equal(_ex1())) {
- q = a;
- return true;
- }
- if (is_ex_exactly_of_type(a, numeric)) {
- if (is_ex_exactly_of_type(b, numeric)) {
- q = a / b;
- return q.info(info_flags::integer);
- } else
- return false;
- }
+ q = _ex0();
+ if (b.is_zero())
+ throw(std::overflow_error("divide_in_z: division by zero"));
+ if (b.is_equal(_ex1())) {
+ q = a;
+ return true;
+ }
+ if (is_ex_exactly_of_type(a, numeric)) {
+ if (is_ex_exactly_of_type(b, numeric)) {
+ q = a / b;
+ return q.info(info_flags::integer);
+ } else
+ return false;
+ }
#if FAST_COMPARE
- if (a.is_equal(b)) {
- q = _ex1();
- return true;
- }
+ if (a.is_equal(b)) {
+ q = _ex1();
+ return true;
+ }
#endif
#if USE_REMEMBER
- // Remembering
- static ex2_exbool_remember dr_remember;
- ex2_exbool_remember::const_iterator remembered = dr_remember.find(ex2(a, b));
- if (remembered != dr_remember.end()) {
- q = remembered->second.first;
- return remembered->second.second;
- }
+ // Remembering
+ static ex2_exbool_remember dr_remember;
+ ex2_exbool_remember::const_iterator remembered = dr_remember.find(ex2(a, b));
+ if (remembered != dr_remember.end()) {
+ q = remembered->second.first;
+ return remembered->second.second;
+ }
#endif
- // Main symbol
- const symbol *x = var->sym;
+ // Main symbol
+ const symbol *x = var->sym;
- // Compare degrees
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- if (bdeg > adeg)
- return false;
+ // Compare degrees
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ if (bdeg > adeg)
+ return false;
#if USE_TRIAL_DIVISION
- // Trial division with polynomial interpolation
- int i, k;
-
- // Compute values at evaluation points 0..adeg
- vector<numeric> alpha; alpha.reserve(adeg + 1);
- exvector u; u.reserve(adeg + 1);
- numeric point = _num0();
- ex c;
- for (i=0; i<=adeg; i++) {
- ex bs = b.subs(*x == point);
- while (bs.is_zero()) {
- point += _num1();
- bs = b.subs(*x == point);
- }
- if (!divide_in_z(a.subs(*x == point), bs, c, var+1))
- return false;
- alpha.push_back(point);
- u.push_back(c);
- point += _num1();
- }
-
- // Compute inverses
- vector<numeric> rcp; rcp.reserve(adeg + 1);
- rcp.push_back(_num0());
- for (k=1; k<=adeg; k++) {
- numeric product = alpha[k] - alpha[0];
- for (i=1; i<k; i++)
- product *= alpha[k] - alpha[i];
- rcp.push_back(product.inverse());
- }
-
- // Compute Newton coefficients
- exvector v; v.reserve(adeg + 1);
- v.push_back(u[0]);
- for (k=1; k<=adeg; k++) {
- ex temp = v[k - 1];
- for (i=k-2; i>=0; i--)
- temp = temp * (alpha[k] - alpha[i]) + v[i];
- v.push_back((u[k] - temp) * rcp[k]);
- }
-
- // Convert from Newton form to standard form
- c = v[adeg];
- for (k=adeg-1; k>=0; k--)
- c = c * (*x - alpha[k]) + v[k];
-
- if (c.degree(*x) == (adeg - bdeg)) {
- q = c.expand();
- return true;
- } else
- return false;
+ // Trial division with polynomial interpolation
+ int i, k;
+
+ // Compute values at evaluation points 0..adeg
+ vector<numeric> alpha; alpha.reserve(adeg + 1);
+ exvector u; u.reserve(adeg + 1);
+ numeric point = _num0();
+ ex c;
+ for (i=0; i<=adeg; i++) {
+ ex bs = b.subs(*x == point);
+ while (bs.is_zero()) {
+ point += _num1();
+ bs = b.subs(*x == point);
+ }
+ if (!divide_in_z(a.subs(*x == point), bs, c, var+1))
+ return false;
+ alpha.push_back(point);
+ u.push_back(c);
+ point += _num1();
+ }
+
+ // Compute inverses
+ vector<numeric> rcp; rcp.reserve(adeg + 1);
+ rcp.push_back(_num0());
+ for (k=1; k<=adeg; k++) {
+ numeric product = alpha[k] - alpha[0];
+ for (i=1; i<k; i++)
+ product *= alpha[k] - alpha[i];
+ rcp.push_back(product.inverse());
+ }
+
+ // Compute Newton coefficients
+ exvector v; v.reserve(adeg + 1);
+ v.push_back(u[0]);
+ for (k=1; k<=adeg; k++) {
+ ex temp = v[k - 1];
+ for (i=k-2; i>=0; i--)
+ temp = temp * (alpha[k] - alpha[i]) + v[i];
+ v.push_back((u[k] - temp) * rcp[k]);
+ }
+
+ // Convert from Newton form to standard form
+ c = v[adeg];
+ for (k=adeg-1; k>=0; k--)
+ c = c * (*x - alpha[k]) + v[k];
+
+ if (c.degree(*x) == (adeg - bdeg)) {
+ q = c.expand();
+ return true;
+ } else
+ return false;
#else
- // Polynomial long division (recursive)
- ex r = a.expand();
- if (r.is_zero())
- return true;
- int rdeg = adeg;
- ex eb = b.expand();
- ex blcoeff = eb.coeff(*x, bdeg);
- while (rdeg >= bdeg) {
- ex term, rcoeff = r.coeff(*x, rdeg);
- if (!divide_in_z(rcoeff, blcoeff, term, var+1))
- break;
- term = (term * power(*x, rdeg - bdeg)).expand();
- q += term;
- r -= (term * eb).expand();
- if (r.is_zero()) {
+ // Polynomial long division (recursive)
+ ex r = a.expand();
+ if (r.is_zero())
+ return true;
+ int rdeg = adeg;
+ ex eb = b.expand();
+ ex blcoeff = eb.coeff(*x, bdeg);
+ while (rdeg >= bdeg) {
+ ex term, rcoeff = r.coeff(*x, rdeg);
+ if (!divide_in_z(rcoeff, blcoeff, term, var+1))
+ break;
+ term = (term * power(*x, rdeg - bdeg)).expand();
+ q += term;
+ r -= (term * eb).expand();
+ if (r.is_zero()) {
#if USE_REMEMBER
- dr_remember[ex2(a, b)] = exbool(q, true);
+ dr_remember[ex2(a, b)] = exbool(q, true);
#endif
- return true;
- }
- rdeg = r.degree(*x);
- }
+ return true;
+ }
+ rdeg = r.degree(*x);
+ }
#if USE_REMEMBER
- dr_remember[ex2(a, b)] = exbool(q, false);
+ dr_remember[ex2(a, b)] = exbool(q, false);
#endif
- return false;
+ return false;
#endif
}
* @see ex::content, ex::primpart */
ex ex::unit(const symbol &x) const
{
- ex c = expand().lcoeff(x);
- if (is_ex_exactly_of_type(c, numeric))
- return c < _ex0() ? _ex_1() : _ex1();
- else {
- const symbol *y;
- if (get_first_symbol(c, y))
- return c.unit(*y);
- else
- throw(std::invalid_argument("invalid expression in unit()"));
- }
+ ex c = expand().lcoeff(x);
+ if (is_ex_exactly_of_type(c, numeric))
+ return c < _ex0() ? _ex_1() : _ex1();
+ else {
+ const symbol *y;
+ if (get_first_symbol(c, y))
+ return c.unit(*y);
+ else
+ throw(std::invalid_argument("invalid expression in unit()"));
+ }
}
* @see ex::unit, ex::primpart */
ex ex::content(const symbol &x) const
{
- if (is_zero())
- return _ex0();
- if (is_ex_exactly_of_type(*this, numeric))
- return info(info_flags::negative) ? -*this : *this;
- ex e = expand();
- if (e.is_zero())
- return _ex0();
-
- // First, try the integer content
- ex c = e.integer_content();
- ex r = e / c;
- ex lcoeff = r.lcoeff(x);
- if (lcoeff.info(info_flags::integer))
- return c;
-
- // GCD of all coefficients
- int deg = e.degree(x);
- int ldeg = e.ldegree(x);
- if (deg == ldeg)
- return e.lcoeff(x) / e.unit(x);
- c = _ex0();
- for (int i=ldeg; i<=deg; i++)
- c = gcd(e.coeff(x, i), c, NULL, NULL, false);
- return c;
+ if (is_zero())
+ return _ex0();
+ if (is_ex_exactly_of_type(*this, numeric))
+ return info(info_flags::negative) ? -*this : *this;
+ ex e = expand();
+ if (e.is_zero())
+ return _ex0();
+
+ // First, try the integer content
+ ex c = e.integer_content();
+ ex r = e / c;
+ ex lcoeff = r.lcoeff(x);
+ if (lcoeff.info(info_flags::integer))
+ return c;
+
+ // GCD of all coefficients
+ int deg = e.degree(x);
+ int ldeg = e.ldegree(x);
+ if (deg == ldeg)
+ return e.lcoeff(x) / e.unit(x);
+ c = _ex0();
+ for (int i=ldeg; i<=deg; i++)
+ c = gcd(e.coeff(x, i), c, NULL, NULL, false);
+ return c;
}
* @see ex::unit, ex::content */
ex ex::primpart(const symbol &x) const
{
- if (is_zero())
- return _ex0();
- if (is_ex_exactly_of_type(*this, numeric))
- return _ex1();
-
- ex c = content(x);
- if (c.is_zero())
- return _ex0();
- ex u = unit(x);
- if (is_ex_exactly_of_type(c, numeric))
- return *this / (c * u);
- else
- return quo(*this, c * u, x, false);
+ if (is_zero())
+ return _ex0();
+ if (is_ex_exactly_of_type(*this, numeric))
+ return _ex1();
+
+ ex c = content(x);
+ if (c.is_zero())
+ return _ex0();
+ ex u = unit(x);
+ if (is_ex_exactly_of_type(c, numeric))
+ return *this / (c * u);
+ else
+ return quo(*this, c * u, x, false);
}
* @return primitive part */
ex ex::primpart(const symbol &x, const ex &c) const
{
- if (is_zero())
- return _ex0();
- if (c.is_zero())
- return _ex0();
- if (is_ex_exactly_of_type(*this, numeric))
- return _ex1();
-
- ex u = unit(x);
- if (is_ex_exactly_of_type(c, numeric))
- return *this / (c * u);
- else
- return quo(*this, c * u, x, false);
+ if (is_zero())
+ return _ex0();
+ if (c.is_zero())
+ return _ex0();
+ if (is_ex_exactly_of_type(*this, numeric))
+ return _ex1();
+
+ ex u = unit(x);
+ if (is_ex_exactly_of_type(c, numeric))
+ return *this / (c * u);
+ else
+ return quo(*this, c * u, x, false);
}
{
//std::clog << "eu_gcd(" << a << "," << b << ")\n";
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- if (adeg >= bdeg) {
- c = a;
- d = b;
- } else {
- c = b;
- d = a;
- }
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ } else {
+ c = b;
+ d = a;
+ }
// Normalize in Q[x]
c = c / c.lcoeff(*x);
d = d / d.lcoeff(*x);
// Euclidean algorithm
- ex r;
- for (;;) {
+ ex r;
+ for (;;) {
//std::clog << " d = " << d << endl;
- r = rem(c, d, *x, false);
- if (r.is_zero())
- return d / d.lcoeff(*x);
- c = d;
+ r = rem(c, d, *x, false);
+ if (r.is_zero())
+ return d / d.lcoeff(*x);
+ c = d;
d = r;
- }
+ }
}
{
//std::clog << "euprem_gcd(" << a << "," << b << ")\n";
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- if (adeg >= bdeg) {
- c = a;
- d = b;
- } else {
- c = b;
- d = a;
- }
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ } else {
+ c = b;
+ d = a;
+ }
// Calculate GCD of contents
ex gamma = gcd(c.content(*x), d.content(*x), NULL, NULL, false);
// Euclidean algorithm with pseudo-remainders
- ex r;
- for (;;) {
+ ex r;
+ for (;;) {
//std::clog << " d = " << d << endl;
- r = prem(c, d, *x, false);
- if (r.is_zero())
- return d.primpart(*x) * gamma;
- c = d;
+ r = prem(c, d, *x, false);
+ if (r.is_zero())
+ return d.primpart(*x) * gamma;
+ c = d;
d = r;
- }
+ }
}
{
//std::clog << "peu_gcd(" << a << "," << b << ")\n";
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- int ddeg;
- if (adeg >= bdeg) {
- c = a;
- d = b;
- ddeg = bdeg;
- } else {
- c = b;
- d = a;
- ddeg = adeg;
- }
-
- // Remove content from c and d, to be attached to GCD later
- ex cont_c = c.content(*x);
- ex cont_d = d.content(*x);
- ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
- if (ddeg == 0)
- return gamma;
- c = c.primpart(*x, cont_c);
- d = d.primpart(*x, cont_d);
-
- // Euclidean algorithm with content removal
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ int ddeg;
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ ddeg = bdeg;
+ } else {
+ c = b;
+ d = a;
+ ddeg = adeg;
+ }
+
+ // Remove content from c and d, to be attached to GCD later
+ ex cont_c = c.content(*x);
+ ex cont_d = d.content(*x);
+ ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
+ if (ddeg == 0)
+ return gamma;
+ c = c.primpart(*x, cont_c);
+ d = d.primpart(*x, cont_d);
+
+ // Euclidean algorithm with content removal
ex r;
- for (;;) {
+ for (;;) {
//std::clog << " d = " << d << endl;
- r = prem(c, d, *x, false);
- if (r.is_zero())
- return gamma * d;
- c = d;
+ r = prem(c, d, *x, false);
+ if (r.is_zero())
+ return gamma * d;
+ c = d;
d = r.primpart(*x);
- }
+ }
}
{
//std::clog << "red_gcd(" << a << "," << b << ")\n";
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- int cdeg, ddeg;
- if (adeg >= bdeg) {
- c = a;
- d = b;
- cdeg = adeg;
- ddeg = bdeg;
- } else {
- c = b;
- d = a;
- cdeg = bdeg;
- ddeg = adeg;
- }
-
- // Remove content from c and d, to be attached to GCD later
- ex cont_c = c.content(*x);
- ex cont_d = d.content(*x);
- ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
- if (ddeg == 0)
- return gamma;
- c = c.primpart(*x, cont_c);
- d = d.primpart(*x, cont_d);
-
- // First element of divisor sequence
- ex r, ri = _ex1();
- int delta = cdeg - ddeg;
-
- for (;;) {
- // Calculate polynomial pseudo-remainder
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(*x), bdeg = b.degree(*x);
+ int cdeg, ddeg;
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ cdeg = adeg;
+ ddeg = bdeg;
+ } else {
+ c = b;
+ d = a;
+ cdeg = bdeg;
+ ddeg = adeg;
+ }
+
+ // Remove content from c and d, to be attached to GCD later
+ ex cont_c = c.content(*x);
+ ex cont_d = d.content(*x);
+ ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
+ if (ddeg == 0)
+ return gamma;
+ c = c.primpart(*x, cont_c);
+ d = d.primpart(*x, cont_d);
+
+ // First element of divisor sequence
+ ex r, ri = _ex1();
+ int delta = cdeg - ddeg;
+
+ for (;;) {
+ // Calculate polynomial pseudo-remainder
//std::clog << " d = " << d << endl;
- r = prem(c, d, *x, false);
- if (r.is_zero())
- return gamma * d.primpart(*x);
- c = d;
- cdeg = ddeg;
-
- if (!divide(r, pow(ri, delta), d, false))
- throw(std::runtime_error("invalid expression in red_gcd(), division failed"));
- ddeg = d.degree(*x);
- if (ddeg == 0) {
- if (is_ex_exactly_of_type(r, numeric))
- return gamma;
- else
- return gamma * r.primpart(*x);
- }
-
- ri = c.expand().lcoeff(*x);
- delta = cdeg - ddeg;
- }
+ r = prem(c, d, *x, false);
+ if (r.is_zero())
+ return gamma * d.primpart(*x);
+ c = d;
+ cdeg = ddeg;
+
+ if (!divide(r, pow(ri, delta), d, false))
+ throw(std::runtime_error("invalid expression in red_gcd(), division failed"));
+ ddeg = d.degree(*x);
+ if (ddeg == 0) {
+ if (is_ex_exactly_of_type(r, numeric))
+ return gamma;
+ else
+ return gamma * r.primpart(*x);
+ }
+
+ ri = c.expand().lcoeff(*x);
+ delta = cdeg - ddeg;
+ }
}
sr_gcd_called++;
#endif
- // The first symbol is our main variable
- const symbol &x = *(var->sym);
-
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(x), bdeg = b.degree(x);
- int cdeg, ddeg;
- if (adeg >= bdeg) {
- c = a;
- d = b;
- cdeg = adeg;
- ddeg = bdeg;
- } else {
- c = b;
- d = a;
- cdeg = bdeg;
- ddeg = adeg;
- }
-
- // Remove content from c and d, to be attached to GCD later
- ex cont_c = c.content(x);
- ex cont_d = d.content(x);
- ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
- if (ddeg == 0)
- return gamma;
- c = c.primpart(x, cont_c);
- d = d.primpart(x, cont_d);
+ // The first symbol is our main variable
+ const symbol &x = *(var->sym);
+
+ // Sort c and d so that c has higher degree
+ ex c, d;
+ int adeg = a.degree(x), bdeg = b.degree(x);
+ int cdeg, ddeg;
+ if (adeg >= bdeg) {
+ c = a;
+ d = b;
+ cdeg = adeg;
+ ddeg = bdeg;
+ } else {
+ c = b;
+ d = a;
+ cdeg = bdeg;
+ ddeg = adeg;
+ }
+
+ // Remove content from c and d, to be attached to GCD later
+ ex cont_c = c.content(x);
+ ex cont_d = d.content(x);
+ ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
+ if (ddeg == 0)
+ return gamma;
+ c = c.primpart(x, cont_c);
+ d = d.primpart(x, cont_d);
//std::clog << " content " << gamma << " removed, continuing with sr_gcd(" << c << "," << d << ")\n";
- // First element of subresultant sequence
- ex r = _ex0(), ri = _ex1(), psi = _ex1();
- int delta = cdeg - ddeg;
+ // First element of subresultant sequence
+ ex r = _ex0(), ri = _ex1(), psi = _ex1();
+ int delta = cdeg - ddeg;
- for (;;) {
- // Calculate polynomial pseudo-remainder
+ for (;;) {
+ // Calculate polynomial pseudo-remainder
//std::clog << " start of loop, psi = " << psi << ", calculating pseudo-remainder...\n";
//std::clog << " d = " << d << endl;
- r = prem(c, d, x, false);
- if (r.is_zero())
- return gamma * d.primpart(x);
- c = d;
- cdeg = ddeg;
+ r = prem(c, d, x, false);
+ if (r.is_zero())
+ return gamma * d.primpart(x);
+ c = d;
+ cdeg = ddeg;
//std::clog << " dividing...\n";
- if (!divide_in_z(r, ri * pow(psi, delta), d, var))
- throw(std::runtime_error("invalid expression in sr_gcd(), division failed"));
- ddeg = d.degree(x);
- if (ddeg == 0) {
- if (is_ex_exactly_of_type(r, numeric))
- return gamma;
- else
- return gamma * r.primpart(x);
- }
-
- // Next element of subresultant sequence
+ if (!divide_in_z(r, ri * pow(psi, delta), d, var))
+ throw(std::runtime_error("invalid expression in sr_gcd(), division failed"));
+ ddeg = d.degree(x);
+ if (ddeg == 0) {
+ if (is_ex_exactly_of_type(r, numeric))
+ return gamma;
+ else
+ return gamma * r.primpart(x);
+ }
+
+ // Next element of subresultant sequence
//std::clog << " calculating next subresultant...\n";
- ri = c.expand().lcoeff(x);
- if (delta == 1)
- psi = ri;
- else if (delta)
- divide_in_z(pow(ri, delta), pow(psi, delta-1), psi, var+1);
- delta = cdeg - ddeg;
- }
+ ri = c.expand().lcoeff(x);
+ if (delta == 1)
+ psi = ri;
+ else if (delta)
+ divide_in_z(pow(ri, delta), pow(psi, delta-1), psi, var+1);
+ delta = cdeg - ddeg;
+ }
}
* @see heur_gcd */
numeric ex::max_coefficient(void) const
{
- GINAC_ASSERT(bp!=0);
- return bp->max_coefficient();
+ GINAC_ASSERT(bp!=0);
+ return bp->max_coefficient();
}
numeric basic::max_coefficient(void) const
{
- return _num1();
+ return _num1();
}
numeric numeric::max_coefficient(void) const
{
- return abs(*this);
+ return abs(*this);
}
numeric add::max_coefficient(void) const
{
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
- numeric cur_max = abs(ex_to_numeric(overall_coeff));
- while (it != itend) {
- numeric a;
- GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
- a = abs(ex_to_numeric(it->coeff));
- if (a > cur_max)
- cur_max = a;
- it++;
- }
- return cur_max;
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+ numeric cur_max = abs(ex_to_numeric(overall_coeff));
+ while (it != itend) {
+ numeric a;
+ GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
+ a = abs(ex_to_numeric(it->coeff));
+ if (a > cur_max)
+ cur_max = a;
+ it++;
+ }
+ return cur_max;
}
numeric mul::max_coefficient(void) const
{
#ifdef DO_GINAC_ASSERT
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- while (it != itend) {
- GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
- it++;
- }
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ while (it != itend) {
+ GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
+ it++;
+ }
#endif // def DO_GINAC_ASSERT
- GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
- return abs(ex_to_numeric(overall_coeff));
+ GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+ return abs(ex_to_numeric(overall_coeff));
}
* @see heur_gcd */
ex ex::smod(const numeric &xi) const
{
- GINAC_ASSERT(bp!=0);
- return bp->smod(xi);
+ GINAC_ASSERT(bp!=0);
+ return bp->smod(xi);
}
ex basic::smod(const numeric &xi) const
{
- return *this;
+ return *this;
}
ex numeric::smod(const numeric &xi) const
{
#ifndef NO_NAMESPACE_GINAC
- return GiNaC::smod(*this, xi);
+ return GiNaC::smod(*this, xi);
#else // ndef NO_NAMESPACE_GINAC
- return ::smod(*this, xi);
+ return ::smod(*this, xi);
#endif // ndef NO_NAMESPACE_GINAC
}
ex add::smod(const numeric &xi) const
{
- epvector newseq;
- newseq.reserve(seq.size()+1);
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- while (it != itend) {
- GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
+ epvector newseq;
+ newseq.reserve(seq.size()+1);
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ while (it != itend) {
+ GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
#ifndef NO_NAMESPACE_GINAC
- numeric coeff = GiNaC::smod(ex_to_numeric(it->coeff), xi);
+ numeric coeff = GiNaC::smod(ex_to_numeric(it->coeff), xi);
#else // ndef NO_NAMESPACE_GINAC
- numeric coeff = ::smod(ex_to_numeric(it->coeff), xi);
+ numeric coeff = ::smod(ex_to_numeric(it->coeff), xi);
#endif // ndef NO_NAMESPACE_GINAC
- if (!coeff.is_zero())
- newseq.push_back(expair(it->rest, coeff));
- it++;
- }
- GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+ if (!coeff.is_zero())
+ newseq.push_back(expair(it->rest, coeff));
+ it++;
+ }
+ GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
#ifndef NO_NAMESPACE_GINAC
- numeric coeff = GiNaC::smod(ex_to_numeric(overall_coeff), xi);
+ numeric coeff = GiNaC::smod(ex_to_numeric(overall_coeff), xi);
#else // ndef NO_NAMESPACE_GINAC
- numeric coeff = ::smod(ex_to_numeric(overall_coeff), xi);
+ numeric coeff = ::smod(ex_to_numeric(overall_coeff), xi);
#endif // ndef NO_NAMESPACE_GINAC
- return (new add(newseq,coeff))->setflag(status_flags::dynallocated);
+ return (new add(newseq,coeff))->setflag(status_flags::dynallocated);
}
ex mul::smod(const numeric &xi) const
{
#ifdef DO_GINAC_ASSERT
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- while (it != itend) {
- GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
- it++;
- }
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ while (it != itend) {
+ GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
+ it++;
+ }
#endif // def DO_GINAC_ASSERT
- mul * mulcopyp=new mul(*this);
- GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+ mul * mulcopyp=new mul(*this);
+ GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
#ifndef NO_NAMESPACE_GINAC
- mulcopyp->overall_coeff = GiNaC::smod(ex_to_numeric(overall_coeff),xi);
+ mulcopyp->overall_coeff = GiNaC::smod(ex_to_numeric(overall_coeff),xi);
#else // ndef NO_NAMESPACE_GINAC
- mulcopyp->overall_coeff = ::smod(ex_to_numeric(overall_coeff),xi);
+ mulcopyp->overall_coeff = ::smod(ex_to_numeric(overall_coeff),xi);
#endif // ndef NO_NAMESPACE_GINAC
- mulcopyp->clearflag(status_flags::evaluated);
- mulcopyp->clearflag(status_flags::hash_calculated);
- return mulcopyp->setflag(status_flags::dynallocated);
+ mulcopyp->clearflag(status_flags::evaluated);
+ mulcopyp->clearflag(status_flags::hash_calculated);
+ return mulcopyp->setflag(status_flags::dynallocated);
}
return *new ex(fail());
// GCD of two numeric values -> CLN
- if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) {
- numeric g = gcd(ex_to_numeric(a), ex_to_numeric(b));
- if (ca)
- *ca = ex_to_numeric(a) / g;
- if (cb)
- *cb = ex_to_numeric(b) / g;
- return g;
- }
-
- // The first symbol is our main variable
- const symbol &x = *(var->sym);
-
- // Remove integer content
- numeric gc = gcd(a.integer_content(), b.integer_content());
- numeric rgc = gc.inverse();
- ex p = a * rgc;
- ex q = b * rgc;
- int maxdeg = max(p.degree(x), q.degree(x));
-
- // Find evaluation point
- numeric mp = p.max_coefficient(), mq = q.max_coefficient();
- numeric xi;
- if (mp > mq)
- xi = mq * _num2() + _num2();
- else
- xi = mp * _num2() + _num2();
-
- // 6 tries maximum
- for (int t=0; t<6; t++) {
- if (xi.int_length() * maxdeg > 100000) {
+ if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) {
+ numeric g = gcd(ex_to_numeric(a), ex_to_numeric(b));
+ if (ca)
+ *ca = ex_to_numeric(a) / g;
+ if (cb)
+ *cb = ex_to_numeric(b) / g;
+ return g;
+ }
+
+ // The first symbol is our main variable
+ const symbol &x = *(var->sym);
+
+ // Remove integer content
+ numeric gc = gcd(a.integer_content(), b.integer_content());
+ numeric rgc = gc.inverse();
+ ex p = a * rgc;
+ ex q = b * rgc;
+ int maxdeg = max(p.degree(x), q.degree(x));
+
+ // Find evaluation point
+ numeric mp = p.max_coefficient(), mq = q.max_coefficient();
+ numeric xi;
+ if (mp > mq)
+ xi = mq * _num2() + _num2();
+ else
+ xi = mp * _num2() + _num2();
+
+ // 6 tries maximum
+ for (int t=0; t<6; t++) {
+ if (xi.int_length() * maxdeg > 100000) {
//std::clog << "giving up heur_gcd, xi.int_length = " << xi.int_length() << ", maxdeg = " << maxdeg << endl;
- throw gcdheu_failed();
+ throw gcdheu_failed();
}
- // Apply evaluation homomorphism and calculate GCD
+ // Apply evaluation homomorphism and calculate GCD
ex cp, cq;
- ex gamma = heur_gcd(p.subs(x == xi), q.subs(x == xi), &cp, &cq, var+1).expand();
- if (!is_ex_exactly_of_type(gamma, fail)) {
+ ex gamma = heur_gcd(p.subs(x == xi), q.subs(x == xi), &cp, &cq, var+1).expand();
+ if (!is_ex_exactly_of_type(gamma, fail)) {
- // Reconstruct polynomial from GCD of mapped polynomials
+ // Reconstruct polynomial from GCD of mapped polynomials
ex g = interpolate(gamma, xi, x);
- // Remove integer content
- g /= g.integer_content();
-
- // If the calculated polynomial divides both p and q, this is the GCD
- ex dummy;
- if (divide_in_z(p, g, ca ? *ca : dummy, var) && divide_in_z(q, g, cb ? *cb : dummy, var)) {
- g *= gc;
- ex lc = g.lcoeff(x);
- if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative())
- return -g;
- else
- return g;
- }
+ // Remove integer content
+ g /= g.integer_content();
+
+ // If the calculated polynomial divides both p and q, this is the GCD
+ ex dummy;
+ if (divide_in_z(p, g, ca ? *ca : dummy, var) && divide_in_z(q, g, cb ? *cb : dummy, var)) {
+ g *= gc;
+ ex lc = g.lcoeff(x);
+ if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative())
+ return -g;
+ else
+ return g;
+ }
#if 0
cp = interpolate(cp, xi, x);
if (divide_in_z(cp, p, g, var)) {
g *= gc;
if (ca)
*ca = cp;
- ex lc = g.lcoeff(x);
- if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative())
- return -g;
- else
- return g;
+ ex lc = g.lcoeff(x);
+ if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative())
+ return -g;
+ else
+ return g;
}
}
cq = interpolate(cq, xi, x);
g *= gc;
if (cb)
*cb = cq;
- ex lc = g.lcoeff(x);
- if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative())
- return -g;
- else
- return g;
+ ex lc = g.lcoeff(x);
+ if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative())
+ return -g;
+ else
+ return g;
}
}
#endif
- }
+ }
- // Next evaluation point
- xi = iquo(xi * isqrt(isqrt(xi)) * numeric(73794), numeric(27011));
- }
- return *new ex(fail());
+ // Next evaluation point
+ xi = iquo(xi * isqrt(isqrt(xi)) * numeric(73794), numeric(27011));
+ }
+ return *new ex(fail());
}
#endif
// GCD of numerics -> CLN
- if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) {
- numeric g = gcd(ex_to_numeric(a), ex_to_numeric(b));
+ if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) {
+ numeric g = gcd(ex_to_numeric(a), ex_to_numeric(b));
if (ca || cb) {
if (g.is_zero()) {
if (ca)
if (cb)
*cb = _ex0();
} else {
- if (ca)
- *ca = ex_to_numeric(a) / g;
- if (cb)
- *cb = ex_to_numeric(b) / g;
+ if (ca)
+ *ca = ex_to_numeric(a) / g;
+ if (cb)
+ *cb = ex_to_numeric(b) / g;
}
}
- return g;
- }
+ return g;
+ }
// Check arguments
- if (check_args && !a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)) {
- throw(std::invalid_argument("gcd: arguments must be polynomials over the rationals"));
- }
+ if (check_args && !a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)) {
+ throw(std::invalid_argument("gcd: arguments must be polynomials over the rationals"));
+ }
// Partially factored cases (to avoid expanding large expressions)
if (is_ex_exactly_of_type(a, mul)) {
}
#endif
- // Some trivial cases
+ // Some trivial cases
ex aex = a.expand(), bex = b.expand();
- if (aex.is_zero()) {
- if (ca)
- *ca = _ex0();
- if (cb)
- *cb = _ex1();
- return b;
- }
- if (bex.is_zero()) {
- if (ca)
- *ca = _ex1();
- if (cb)
- *cb = _ex0();
- return a;
- }
- if (aex.is_equal(_ex1()) || bex.is_equal(_ex1())) {
- if (ca)
- *ca = a;
- if (cb)
- *cb = b;
- return _ex1();
- }
+ if (aex.is_zero()) {
+ if (ca)
+ *ca = _ex0();
+ if (cb)
+ *cb = _ex1();
+ return b;
+ }
+ if (bex.is_zero()) {
+ if (ca)
+ *ca = _ex1();
+ if (cb)
+ *cb = _ex0();
+ return a;
+ }
+ if (aex.is_equal(_ex1()) || bex.is_equal(_ex1())) {
+ if (ca)
+ *ca = a;
+ if (cb)
+ *cb = b;
+ return _ex1();
+ }
#if FAST_COMPARE
- if (a.is_equal(b)) {
- if (ca)
- *ca = _ex1();
- if (cb)
- *cb = _ex1();
- return a;
- }
+ if (a.is_equal(b)) {
+ if (ca)
+ *ca = _ex1();
+ if (cb)
+ *cb = _ex1();
+ return a;
+ }
#endif
- // Gather symbol statistics
- sym_desc_vec sym_stats;
- get_symbol_stats(a, b, sym_stats);
+ // Gather symbol statistics
+ sym_desc_vec sym_stats;
+ get_symbol_stats(a, b, sym_stats);
- // The symbol with least degree is our main variable
- sym_desc_vec::const_iterator var = sym_stats.begin();
- const symbol &x = *(var->sym);
+ // The symbol with least degree is our main variable
+ sym_desc_vec::const_iterator var = sym_stats.begin();
+ const symbol &x = *(var->sym);
- // Cancel trivial common factor
- int ldeg_a = var->ldeg_a;
- int ldeg_b = var->ldeg_b;
- int min_ldeg = min(ldeg_a, ldeg_b);
- if (min_ldeg > 0) {
- ex common = power(x, min_ldeg);
+ // Cancel trivial common factor
+ int ldeg_a = var->ldeg_a;
+ int ldeg_b = var->ldeg_b;
+ int min_ldeg = min(ldeg_a, ldeg_b);
+ if (min_ldeg > 0) {
+ ex common = power(x, min_ldeg);
//std::clog << "trivial common factor " << common << endl;
- return gcd((aex / common).expand(), (bex / common).expand(), ca, cb, false) * common;
- }
+ return gcd((aex / common).expand(), (bex / common).expand(), ca, cb, false) * common;
+ }
- // Try to eliminate variables
- if (var->deg_a == 0) {
+ // Try to eliminate variables
+ if (var->deg_a == 0) {
//std::clog << "eliminating variable " << x << " from b" << endl;
- ex c = bex.content(x);
- ex g = gcd(aex, c, ca, cb, false);
- if (cb)
- *cb *= bex.unit(x) * bex.primpart(x, c);
- return g;
- } else if (var->deg_b == 0) {
+ ex c = bex.content(x);
+ ex g = gcd(aex, c, ca, cb, false);
+ if (cb)
+ *cb *= bex.unit(x) * bex.primpart(x, c);
+ return g;
+ } else if (var->deg_b == 0) {
//std::clog << "eliminating variable " << x << " from a" << endl;
- ex c = aex.content(x);
- ex g = gcd(c, bex, ca, cb, false);
- if (ca)
- *ca *= aex.unit(x) * aex.primpart(x, c);
- return g;
- }
-
- ex g;
+ ex c = aex.content(x);
+ ex g = gcd(c, bex, ca, cb, false);
+ if (ca)
+ *ca *= aex.unit(x) * aex.primpart(x, c);
+ return g;
+ }
+
+ ex g;
#if 1
- // Try heuristic algorithm first, fall back to PRS if that failed
- try {
- g = heur_gcd(aex, bex, ca, cb, var);
- } catch (gcdheu_failed) {
- g = *new ex(fail());
- }
- if (is_ex_exactly_of_type(g, fail)) {
+ // Try heuristic algorithm first, fall back to PRS if that failed
+ try {
+ g = heur_gcd(aex, bex, ca, cb, var);
+ } catch (gcdheu_failed) {
+ g = *new ex(fail());
+ }
+ if (is_ex_exactly_of_type(g, fail)) {
//std::clog << "heuristics failed" << endl;
#if STATISTICS
heur_gcd_failed++;
if (cb)
*cb = b;
} else {
- if (ca)
- divide(aex, g, *ca, false);
- if (cb)
- divide(bex, g, *cb, false);
+ if (ca)
+ divide(aex, g, *ca, false);
+ if (cb)
+ divide(bex, g, *cb, false);
}
#if 1
- } else {
+ } else {
if (g.is_equal(_ex1())) {
// Keep cofactors factored if possible
if (ca)
}
}
#endif
- return g;
+ return g;
}
* @return the LCM as a new expression */
ex lcm(const ex &a, const ex &b, bool check_args)
{
- if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric))
- return lcm(ex_to_numeric(a), ex_to_numeric(b));
- if (check_args && !a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))
- throw(std::invalid_argument("lcm: arguments must be polynomials over the rationals"));
-
- ex ca, cb;
- ex g = gcd(a, b, &ca, &cb, false);
- return ca * cb * g;
+ if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric))
+ return lcm(ex_to_numeric(a), ex_to_numeric(b));
+ if (check_args && !a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))
+ throw(std::invalid_argument("lcm: arguments must be polynomials over the rationals"));
+
+ ex ca, cb;
+ ex g = gcd(a, b, &ca, &cb, false);
+ return ca * cb * g;
}
// a and b can be multivariate polynomials but they are treated as univariate polynomials in x.
static ex univariate_gcd(const ex &a, const ex &b, const symbol &x)
{
- if (a.is_zero())
- return b;
- if (b.is_zero())
- return a;
- if (a.is_equal(_ex1()) || b.is_equal(_ex1()))
- return _ex1();
- if (is_ex_of_type(a, numeric) && is_ex_of_type(b, numeric))
- return gcd(ex_to_numeric(a), ex_to_numeric(b));
- if (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))
- throw(std::invalid_argument("univariate_gcd: arguments must be polynomials over the rationals"));
-
- // Euclidean algorithm
- ex c, d, r;
- if (a.degree(x) >= b.degree(x)) {
- c = a;
- d = b;
- } else {
- c = b;
- d = a;
- }
- for (;;) {
- r = rem(c, d, x, false);
- if (r.is_zero())
- break;
- c = d;
- d = r;
- }
- return d / d.lcoeff(x);
+ if (a.is_zero())
+ return b;
+ if (b.is_zero())
+ return a;
+ if (a.is_equal(_ex1()) || b.is_equal(_ex1()))
+ return _ex1();
+ if (is_ex_of_type(a, numeric) && is_ex_of_type(b, numeric))
+ return gcd(ex_to_numeric(a), ex_to_numeric(b));
+ if (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))
+ throw(std::invalid_argument("univariate_gcd: arguments must be polynomials over the rationals"));
+
+ // Euclidean algorithm
+ ex c, d, r;
+ if (a.degree(x) >= b.degree(x)) {
+ c = a;
+ d = b;
+ } else {
+ c = b;
+ d = a;
+ }
+ for (;;) {
+ r = rem(c, d, x, false);
+ if (r.is_zero())
+ break;
+ c = d;
+ d = r;
+ }
+ return d / d.lcoeff(x);
}
* @return factored polynomial */
ex sqrfree(const ex &a, const symbol &x)
{
- int i = 1;
- ex res = _ex1();
- ex b = a.diff(x);
- ex c = univariate_gcd(a, b, x);
- ex w;
- if (c.is_equal(_ex1())) {
- w = a;
- } else {
- w = quo(a, c, x);
- ex y = quo(b, c, x);
- ex z = y - w.diff(x);
- while (!z.is_zero()) {
- ex g = univariate_gcd(w, z, x);
- res *= power(g, i);
- w = quo(w, g, x);
- y = quo(z, g, x);
- z = y - w.diff(x);
- i++;
- }
- }
- return res * power(w, i);
+ int i = 1;
+ ex res = _ex1();
+ ex b = a.diff(x);
+ ex c = univariate_gcd(a, b, x);
+ ex w;
+ if (c.is_equal(_ex1())) {
+ w = a;
+ } else {
+ w = quo(a, c, x);
+ ex y = quo(b, c, x);
+ ex z = y - w.diff(x);
+ while (!z.is_zero()) {
+ ex g = univariate_gcd(w, z, x);
+ res *= power(g, i);
+ w = quo(w, g, x);
+ y = quo(z, g, x);
+ z = y - w.diff(x);
+ i++;
+ }
+ }
+ return res * power(w, i);
}
* @see ex::normal */
static ex replace_with_symbol(const ex &e, lst &sym_lst, lst &repl_lst)
{
- // Expression already in repl_lst? Then return the assigned symbol
- for (unsigned i=0; i<repl_lst.nops(); i++)
- if (repl_lst.op(i).is_equal(e))
- return sym_lst.op(i);
-
- // Otherwise create new symbol and add to list, taking care that the
+ // Expression already in repl_lst? Then return the assigned symbol
+ for (unsigned i=0; i<repl_lst.nops(); i++)
+ if (repl_lst.op(i).is_equal(e))
+ return sym_lst.op(i);
+
+ // Otherwise create new symbol and add to list, taking care that the
// replacement expression doesn't contain symbols from the sym_lst
// because subs() is not recursive
symbol s;
ex es(s);
ex e_replaced = e.subs(sym_lst, repl_lst);
- sym_lst.append(es);
- repl_lst.append(e_replaced);
- return es;
+ sym_lst.append(es);
+ repl_lst.append(e_replaced);
+ return es;
}
/** Create a symbol for replacing the expression "e" (or return a previously
* @see ex::to_rational */
static ex replace_with_symbol(const ex &e, lst &repl_lst)
{
- // Expression already in repl_lst? Then return the assigned symbol
- for (unsigned i=0; i<repl_lst.nops(); i++)
- if (repl_lst.op(i).op(1).is_equal(e))
- return repl_lst.op(i).op(0);
-
- // Otherwise create new symbol and add to list, taking care that the
+ // Expression already in repl_lst? Then return the assigned symbol
+ for (unsigned i=0; i<repl_lst.nops(); i++)
+ if (repl_lst.op(i).op(1).is_equal(e))
+ return repl_lst.op(i).op(0);
+
+ // Otherwise create new symbol and add to list, taking care that the
// replacement expression doesn't contain symbols from the sym_lst
// because subs() is not recursive
symbol s;
ex es(s);
ex e_replaced = e.subs(repl_lst);
- repl_lst.append(es == e_replaced);
- return es;
+ repl_lst.append(es == e_replaced);
+ return es;
}
/** Default implementation of ex::normal(). It replaces the object with a
* @see ex::normal */
ex basic::normal(lst &sym_lst, lst &repl_lst, int level) const
{
- return (new lst(replace_with_symbol(*this, sym_lst, repl_lst), _ex1()))->setflag(status_flags::dynallocated);
+ return (new lst(replace_with_symbol(*this, sym_lst, repl_lst), _ex1()))->setflag(status_flags::dynallocated);
}
* @see ex::normal */
ex symbol::normal(lst &sym_lst, lst &repl_lst, int level) const
{
- return (new lst(*this, _ex1()))->setflag(status_flags::dynallocated);
+ return (new lst(*this, _ex1()))->setflag(status_flags::dynallocated);
}
numeric num = numer();
ex numex = num;
- if (num.is_real()) {
- if (!num.is_integer())
- numex = replace_with_symbol(numex, sym_lst, repl_lst);
- } else { // complex
- numeric re = num.real(), im = num.imag();
- ex re_ex = re.is_rational() ? re : replace_with_symbol(re, sym_lst, repl_lst);
- ex im_ex = im.is_rational() ? im : replace_with_symbol(im, sym_lst, repl_lst);
- numex = re_ex + im_ex * replace_with_symbol(I, sym_lst, repl_lst);
- }
+ if (num.is_real()) {
+ if (!num.is_integer())
+ numex = replace_with_symbol(numex, sym_lst, repl_lst);
+ } else { // complex
+ numeric re = num.real(), im = num.imag();
+ ex re_ex = re.is_rational() ? re : replace_with_symbol(re, sym_lst, repl_lst);
+ ex im_ex = im.is_rational() ? im : replace_with_symbol(im, sym_lst, repl_lst);
+ numex = re_ex + im_ex * replace_with_symbol(I, sym_lst, repl_lst);
+ }
// Denominator is always a real integer (see numeric::denom())
return (new lst(numex, denom()))->setflag(status_flags::dynallocated);
* @return cancelled fraction {n, d} as a list */
static ex frac_cancel(const ex &n, const ex &d)
{
- ex num = n;
- ex den = d;
- numeric pre_factor = _num1();
+ ex num = n;
+ ex den = d;
+ numeric pre_factor = _num1();
//std::clog << "frac_cancel num = " << num << ", den = " << den << endl;
- // Handle special cases where numerator or denominator is 0
- if (num.is_zero())
+ // Handle special cases where numerator or denominator is 0
+ if (num.is_zero())
return (new lst(_ex0(), _ex1()))->setflag(status_flags::dynallocated);
- if (den.expand().is_zero())
- throw(std::overflow_error("frac_cancel: division by zero in frac_cancel"));
+ if (den.expand().is_zero())
+ throw(std::overflow_error("frac_cancel: division by zero in frac_cancel"));
- // Bring numerator and denominator to Z[X] by multiplying with
- // LCM of all coefficients' denominators
- numeric num_lcm = lcm_of_coefficients_denominators(num);
- numeric den_lcm = lcm_of_coefficients_denominators(den);
+ // Bring numerator and denominator to Z[X] by multiplying with
+ // LCM of all coefficients' denominators
+ numeric num_lcm = lcm_of_coefficients_denominators(num);
+ numeric den_lcm = lcm_of_coefficients_denominators(den);
num = multiply_lcm(num, num_lcm);
den = multiply_lcm(den, den_lcm);
- pre_factor = den_lcm / num_lcm;
+ pre_factor = den_lcm / num_lcm;
- // Cancel GCD from numerator and denominator
- ex cnum, cden;
- if (gcd(num, den, &cnum, &cden, false) != _ex1()) {
+ // Cancel GCD from numerator and denominator
+ ex cnum, cden;
+ if (gcd(num, den, &cnum, &cden, false) != _ex1()) {
num = cnum;
den = cden;
}
// as defined by get_first_symbol() is made positive)
const symbol *x;
if (get_first_symbol(den, x)) {
- GINAC_ASSERT(is_ex_exactly_of_type(den.unit(*x),numeric));
+ GINAC_ASSERT(is_ex_exactly_of_type(den.unit(*x),numeric));
if (ex_to_numeric(den.unit(*x)).is_negative()) {
num *= _ex_1();
den *= _ex_1();
// Return result as list
//std::clog << " returns num = " << num << ", den = " << den << ", pre_factor = " << pre_factor << endl;
- return (new lst(num * pre_factor.numer(), den * pre_factor.denom()))->setflag(status_flags::dynallocated);
+ return (new lst(num * pre_factor.numer(), den * pre_factor.denom()))->setflag(status_flags::dynallocated);
}
if (level == 1)
return (new lst(*this, _ex1()))->setflag(status_flags::dynallocated);
else if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
+ throw(std::runtime_error("max recursion level reached"));
- // Normalize and expand children, chop into summands
- exvector o;
- o.reserve(seq.size()+1);
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
+ // Normalize and expand children, chop into summands
+ exvector o;
+ o.reserve(seq.size()+1);
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
// Normalize and expand child
- ex n = recombine_pair_to_ex(*it).bp->normal(sym_lst, repl_lst, level-1).expand();
+ ex n = recombine_pair_to_ex(*it).bp->normal(sym_lst, repl_lst, level-1).expand();
// If numerator is a sum, chop into summands
- if (is_ex_exactly_of_type(n.op(0), add)) {
- epvector::const_iterator bit = ex_to_add(n.op(0)).seq.begin(), bitend = ex_to_add(n.op(0)).seq.end();
- while (bit != bitend) {
- o.push_back((new lst(recombine_pair_to_ex(*bit), n.op(1)))->setflag(status_flags::dynallocated));
- bit++;
- }
+ if (is_ex_exactly_of_type(n.op(0), add)) {
+ epvector::const_iterator bit = ex_to_add(n.op(0)).seq.begin(), bitend = ex_to_add(n.op(0)).seq.end();
+ while (bit != bitend) {
+ o.push_back((new lst(recombine_pair_to_ex(*bit), n.op(1)))->setflag(status_flags::dynallocated));
+ bit++;
+ }
// The overall_coeff is already normalized (== rational), we just
// split it into numerator and denominator
GINAC_ASSERT(ex_to_numeric(ex_to_add(n.op(0)).overall_coeff).is_rational());
numeric overall = ex_to_numeric(ex_to_add(n.op(0)).overall_coeff);
- o.push_back((new lst(overall.numer(), overall.denom() * n.op(1)))->setflag(status_flags::dynallocated));
- } else
- o.push_back(n);
- it++;
- }
- o.push_back(overall_coeff.bp->normal(sym_lst, repl_lst, level-1));
+ o.push_back((new lst(overall.numer(), overall.denom() * n.op(1)))->setflag(status_flags::dynallocated));
+ } else
+ o.push_back(n);
+ it++;
+ }
+ o.push_back(overall_coeff.bp->normal(sym_lst, repl_lst, level-1));
// o is now a vector of {numerator, denominator} lists
- // Determine common denominator
- ex den = _ex1();
- exvector::const_iterator ait = o.begin(), aitend = o.end();
+ // Determine common denominator
+ ex den = _ex1();
+ exvector::const_iterator ait = o.begin(), aitend = o.end();
//std::clog << "add::normal uses the following summands:\n";
- while (ait != aitend) {
+ while (ait != aitend) {
//std::clog << " num = " << ait->op(0) << ", den = " << ait->op(1) << endl;
- den = lcm(ait->op(1), den, false);
- ait++;
- }
+ den = lcm(ait->op(1), den, false);
+ ait++;
+ }
//std::clog << " common denominator = " << den << endl;
- // Add fractions
- if (den.is_equal(_ex1())) {
+ // Add fractions
+ if (den.is_equal(_ex1())) {
// Common denominator is 1, simply add all fractions
- exvector num_seq;
+ exvector num_seq;
for (ait=o.begin(); ait!=aitend; ait++) {
num_seq.push_back(ait->op(0) / ait->op(1));
}
} else {
// Perform fractional addition
- exvector num_seq;
- for (ait=o.begin(); ait!=aitend; ait++) {
- ex q;
- if (!divide(den, ait->op(1), q, false)) {
- // should not happen
- throw(std::runtime_error("invalid expression in add::normal, division failed"));
- }
- num_seq.push_back((ait->op(0) * q).expand());
- }
- ex num = (new add(num_seq))->setflag(status_flags::dynallocated);
-
- // Cancel common factors from num/den
- return frac_cancel(num, den);
- }
+ exvector num_seq;
+ for (ait=o.begin(); ait!=aitend; ait++) {
+ ex q;
+ if (!divide(den, ait->op(1), q, false)) {
+ // should not happen
+ throw(std::runtime_error("invalid expression in add::normal, division failed"));
+ }
+ num_seq.push_back((ait->op(0) * q).expand());
+ }
+ ex num = (new add(num_seq))->setflag(status_flags::dynallocated);
+
+ // Cancel common factors from num/den
+ return frac_cancel(num, den);
+ }
}
if (level == 1)
return (new lst(*this, _ex1()))->setflag(status_flags::dynallocated);
else if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
+ throw(std::runtime_error("max recursion level reached"));
- // Normalize children, separate into numerator and denominator
+ // Normalize children, separate into numerator and denominator
ex num = _ex1();
ex den = _ex1();
ex n;
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
n = recombine_pair_to_ex(*it).bp->normal(sym_lst, repl_lst, level-1);
num *= n.op(0);
den *= n.op(1);
- it++;
- }
+ it++;
+ }
n = overall_coeff.bp->normal(sym_lst, repl_lst, level-1);
num *= n.op(0);
den *= n.op(1);
// Perform fraction cancellation
- return frac_cancel(num, den);
+ return frac_cancel(num, den);
}
if (level == 1)
return (new lst(*this, _ex1()))->setflag(status_flags::dynallocated);
else if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
+ throw(std::runtime_error("max recursion level reached"));
// Normalize basis
- ex n = basis.bp->normal(sym_lst, repl_lst, level-1);
+ ex n = basis.bp->normal(sym_lst, repl_lst, level-1);
if (exponent.info(info_flags::integer)) {
- if (exponent.info(info_flags::positive)) {
+ if (exponent.info(info_flags::positive)) {
// (a/b)^n -> {a^n, b^n}
return (new lst(power(n.op(0), exponent), power(n.op(1), exponent)))->setflag(status_flags::dynallocated);
// (a/b)^x -> {sym((a/b)^x, 1}
return (new lst(replace_with_symbol(power(n.op(0) / n.op(1), exponent), sym_lst, repl_lst), _ex1()))->setflag(status_flags::dynallocated);
}
- }
+ }
}
* @see ex::normal */
ex pseries::normal(lst &sym_lst, lst &repl_lst, int level) const
{
- epvector new_seq;
- new_seq.reserve(seq.size());
-
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
- new_seq.push_back(expair(it->rest.normal(), it->coeff));
- it++;
- }
- ex n = pseries(relational(var,point), new_seq);
+ epvector new_seq;
+ new_seq.reserve(seq.size());
+
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ new_seq.push_back(expair(it->rest.normal(), it->coeff));
+ it++;
+ }
+ ex n = pseries(relational(var,point), new_seq);
return (new lst(replace_with_symbol(n, sym_lst, repl_lst), _ex1()))->setflag(status_flags::dynallocated);
}
* @return normalized expression */
ex ex::normal(int level) const
{
- lst sym_lst, repl_lst;
+ lst sym_lst, repl_lst;
- ex e = bp->normal(sym_lst, repl_lst, level);
+ ex e = bp->normal(sym_lst, repl_lst, level);
GINAC_ASSERT(is_ex_of_type(e, lst));
// Re-insert replaced symbols
- if (sym_lst.nops() > 0)
- e = e.subs(sym_lst, repl_lst);
+ if (sym_lst.nops() > 0)
+ e = e.subs(sym_lst, repl_lst);
// Convert {numerator, denominator} form back to fraction
- return e.op(0) / e.op(1);
+ return e.op(0) / e.op(1);
}
/** Numerator of an expression. If the expression is not of the normal form
* @return numerator */
ex ex::numer(void) const
{
- lst sym_lst, repl_lst;
+ lst sym_lst, repl_lst;
- ex e = bp->normal(sym_lst, repl_lst, 0);
+ ex e = bp->normal(sym_lst, repl_lst, 0);
GINAC_ASSERT(is_ex_of_type(e, lst));
// Re-insert replaced symbols
- if (sym_lst.nops() > 0)
- return e.op(0).subs(sym_lst, repl_lst);
+ if (sym_lst.nops() > 0)
+ return e.op(0).subs(sym_lst, repl_lst);
else
return e.op(0);
}
* @return denominator */
ex ex::denom(void) const
{
- lst sym_lst, repl_lst;
+ lst sym_lst, repl_lst;
- ex e = bp->normal(sym_lst, repl_lst, 0);
+ ex e = bp->normal(sym_lst, repl_lst, 0);
GINAC_ASSERT(is_ex_of_type(e, lst));
// Re-insert replaced symbols
- if (sym_lst.nops() > 0)
- return e.op(1).subs(sym_lst, repl_lst);
+ if (sym_lst.nops() > 0)
+ return e.op(1).subs(sym_lst, repl_lst);
else
return e.op(1);
}
* @see ex::to_rational */
ex symbol::to_rational(lst &repl_lst) const
{
- return *this;
+ return *this;
}
* @see ex::to_rational */
ex numeric::to_rational(lst &repl_lst) const
{
- if (is_real()) {
- if (!is_rational())
- return replace_with_symbol(*this, repl_lst);
- } else { // complex
- numeric re = real();
- numeric im = imag();
- ex re_ex = re.is_rational() ? re : replace_with_symbol(re, repl_lst);
- ex im_ex = im.is_rational() ? im : replace_with_symbol(im, repl_lst);
- return re_ex + im_ex * replace_with_symbol(I, repl_lst);
- }
+ if (is_real()) {
+ if (!is_rational())
+ return replace_with_symbol(*this, repl_lst);
+ } else { // complex
+ numeric re = real();
+ numeric im = imag();
+ ex re_ex = re.is_rational() ? re : replace_with_symbol(re, repl_lst);
+ ex im_ex = im.is_rational() ? im : replace_with_symbol(im, repl_lst);
+ return re_ex + im_ex * replace_with_symbol(I, repl_lst);
+ }
return *this;
}
* @see ex::to_rational */
ex expairseq::to_rational(lst &repl_lst) 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(recombine_pair_to_ex(*it).to_rational(repl_lst)));
- // s.push_back(combine_ex_with_coeff_to_pair((*it).rest.to_rational(repl_lst),
- }
- ex oc = overall_coeff.to_rational(repl_lst);
- if (oc.info(info_flags::numeric))
- return thisexpairseq(s, overall_coeff);
- else s.push_back(combine_ex_with_coeff_to_pair(oc,_ex1()));
- return thisexpairseq(s, default_overall_coeff());
+ epvector s;
+ s.reserve(seq.size());
+ for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ s.push_back(split_ex_to_pair(recombine_pair_to_ex(*it).to_rational(repl_lst)));
+ // s.push_back(combine_ex_with_coeff_to_pair((*it).rest.to_rational(repl_lst),
+ }
+ ex oc = overall_coeff.to_rational(repl_lst);
+ if (oc.info(info_flags::numeric))
+ return thisexpairseq(s, overall_coeff);
+ else s.push_back(combine_ex_with_coeff_to_pair(oc,_ex1()));
+ return thisexpairseq(s, default_overall_coeff());
}
/** default ctor. Numerically it initializes to an integer zero. */
numeric::numeric() : basic(TINFO_numeric)
{
- debugmsg("numeric default constructor", LOGLEVEL_CONSTRUCT);
- value = new ::cl_N;
- *value = ::cl_I(0);
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ debugmsg("numeric default constructor", LOGLEVEL_CONSTRUCT);
+ value = new ::cl_N;
+ *value = ::cl_I(0);
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
numeric::~numeric()
{
- debugmsg("numeric destructor" ,LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("numeric destructor" ,LOGLEVEL_DESTRUCT);
+ destroy(0);
}
numeric::numeric(const numeric & other)
{
- debugmsg("numeric copy constructor", LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("numeric copy constructor", LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const numeric & numeric::operator=(const numeric & other)
{
- debugmsg("numeric operator=", LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("numeric operator=", LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void numeric::copy(const numeric & other)
{
- basic::copy(other);
- value = new ::cl_N(*other.value);
+ basic::copy(other);
+ value = new ::cl_N(*other.value);
}
void numeric::destroy(bool call_parent)
{
- delete value;
- if (call_parent) basic::destroy(call_parent);
+ delete value;
+ if (call_parent) basic::destroy(call_parent);
}
//////////
numeric::numeric(int i) : basic(TINFO_numeric)
{
- debugmsg("numeric constructor from int",LOGLEVEL_CONSTRUCT);
- // Not the whole int-range is available if we don't cast to long
- // first. This is due to the behaviour of the cl_I-ctor, which
- // emphasizes efficiency:
- value = new ::cl_I((long) i);
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ debugmsg("numeric constructor from int",LOGLEVEL_CONSTRUCT);
+ // Not the whole int-range is available if we don't cast to long
+ // first. This is due to the behaviour of the cl_I-ctor, which
+ // emphasizes efficiency:
+ value = new ::cl_I((long) i);
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
numeric::numeric(unsigned int i) : basic(TINFO_numeric)
{
- debugmsg("numeric constructor from uint",LOGLEVEL_CONSTRUCT);
- // Not the whole uint-range is available if we don't cast to ulong
- // first. This is due to the behaviour of the cl_I-ctor, which
- // emphasizes efficiency:
- value = new ::cl_I((unsigned long)i);
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ debugmsg("numeric constructor from uint",LOGLEVEL_CONSTRUCT);
+ // Not the whole uint-range is available if we don't cast to ulong
+ // first. This is due to the behaviour of the cl_I-ctor, which
+ // emphasizes efficiency:
+ value = new ::cl_I((unsigned long)i);
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
numeric::numeric(long i) : basic(TINFO_numeric)
{
- debugmsg("numeric constructor from long",LOGLEVEL_CONSTRUCT);
- value = new ::cl_I(i);
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ debugmsg("numeric constructor from long",LOGLEVEL_CONSTRUCT);
+ value = new ::cl_I(i);
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
numeric::numeric(unsigned long i) : basic(TINFO_numeric)
{
- debugmsg("numeric constructor from ulong",LOGLEVEL_CONSTRUCT);
- value = new ::cl_I(i);
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ debugmsg("numeric constructor from ulong",LOGLEVEL_CONSTRUCT);
+ value = new ::cl_I(i);
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
/** Ctor for rational numerics a/b.
* @exception overflow_error (division by zero) */
numeric::numeric(long numer, long denom) : basic(TINFO_numeric)
{
- debugmsg("numeric constructor from long/long",LOGLEVEL_CONSTRUCT);
- if (!denom)
- throw std::overflow_error("division by zero");
- value = new ::cl_I(numer);
- *value = *value / ::cl_I(denom);
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ debugmsg("numeric constructor from long/long",LOGLEVEL_CONSTRUCT);
+ if (!denom)
+ throw std::overflow_error("division by zero");
+ value = new ::cl_I(numer);
+ *value = *value / ::cl_I(denom);
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
numeric::numeric(double d) : basic(TINFO_numeric)
{
- debugmsg("numeric constructor from double",LOGLEVEL_CONSTRUCT);
- // We really want to explicitly use the type cl_LF instead of the
- // more general cl_F, since that would give us a cl_DF only which
- // will not be promoted to cl_LF if overflow occurs:
- value = new cl_N;
- *value = cl_float(d, cl_default_float_format);
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ debugmsg("numeric constructor from double",LOGLEVEL_CONSTRUCT);
+ // We really want to explicitly use the type cl_LF instead of the
+ // more general cl_F, since that would give us a cl_DF only which
+ // will not be promoted to cl_LF if overflow occurs:
+ value = new cl_N;
+ *value = cl_float(d, cl_default_float_format);
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
* notation like "2+5*I". */
numeric::numeric(const char *s) : basic(TINFO_numeric)
{
- debugmsg("numeric constructor from string",LOGLEVEL_CONSTRUCT);
- value = new ::cl_N(0);
- // parse complex numbers (functional but not completely safe, unfortunately
- // std::string does not understand regexpese):
- // ss should represent a simple sum like 2+5*I
- std::string ss(s);
- // make it safe by adding explicit sign
- if (ss.at(0) != '+' && ss.at(0) != '-' && ss.at(0) != '#')
- ss = '+' + ss;
- std::string::size_type delim;
- do {
- // chop ss into terms from left to right
- std::string term;
- bool imaginary = false;
- delim = ss.find_first_of(std::string("+-"),1);
- // Do we have an exponent marker like "31.415E-1"? If so, hop on!
- if (delim != std::string::npos &&
- ss.at(delim-1) == 'E')
- delim = ss.find_first_of(std::string("+-"),delim+1);
- term = ss.substr(0,delim);
- if (delim != std::string::npos)
- ss = ss.substr(delim);
- // is the term imaginary?
- if (term.find("I") != std::string::npos) {
- // erase 'I':
- term = term.replace(term.find("I"),1,"");
- // erase '*':
- if (term.find("*") != std::string::npos)
- term = term.replace(term.find("*"),1,"");
- // correct for trivial +/-I without explicit factor on I:
- if (term.size() == 1)
- term += "1";
- imaginary = true;
- }
- const char *cs = term.c_str();
- // CLN's short types are not useful within the GiNaC framework, hence
- // we go straight to the construction of a long float. Simply using
- // cl_N(s) would require us to use add a CLN exponent mark, otherwise
- // we would not be save from over-/underflows.
- if (strchr(cs, '.'))
- if (imaginary)
- *value = *value + ::complex(cl_I(0),::cl_LF(cs));
- else
- *value = *value + ::cl_LF(cs);
- else
- if (imaginary)
- *value = *value + ::complex(cl_I(0),::cl_R(cs));
- else
- *value = *value + ::cl_R(cs);
- } while(delim != std::string::npos);
- calchash();
- setflag(status_flags::evaluated|
- status_flags::hash_calculated);
+ debugmsg("numeric constructor from string",LOGLEVEL_CONSTRUCT);
+ value = new ::cl_N(0);
+ // parse complex numbers (functional but not completely safe, unfortunately
+ // std::string does not understand regexpese):
+ // ss should represent a simple sum like 2+5*I
+ std::string ss(s);
+ // make it safe by adding explicit sign
+ if (ss.at(0) != '+' && ss.at(0) != '-' && ss.at(0) != '#')
+ ss = '+' + ss;
+ std::string::size_type delim;
+ do {
+ // chop ss into terms from left to right
+ std::string term;
+ bool imaginary = false;
+ delim = ss.find_first_of(std::string("+-"),1);
+ // Do we have an exponent marker like "31.415E-1"? If so, hop on!
+ if (delim != std::string::npos &&
+ ss.at(delim-1) == 'E')
+ delim = ss.find_first_of(std::string("+-"),delim+1);
+ term = ss.substr(0,delim);
+ if (delim != std::string::npos)
+ ss = ss.substr(delim);
+ // is the term imaginary?
+ if (term.find("I") != std::string::npos) {
+ // erase 'I':
+ term = term.replace(term.find("I"),1,"");
+ // erase '*':
+ if (term.find("*") != std::string::npos)
+ term = term.replace(term.find("*"),1,"");
+ // correct for trivial +/-I without explicit factor on I:
+ if (term.size() == 1)
+ term += "1";
+ imaginary = true;
+ }
+ const char *cs = term.c_str();
+ // CLN's short types are not useful within the GiNaC framework, hence
+ // we go straight to the construction of a long float. Simply using
+ // cl_N(s) would require us to use add a CLN exponent mark, otherwise
+ // we would not be save from over-/underflows.
+ if (strchr(cs, '.'))
+ if (imaginary)
+ *value = *value + ::complex(cl_I(0),::cl_LF(cs));
+ else
+ *value = *value + ::cl_LF(cs);
+ else
+ if (imaginary)
+ *value = *value + ::complex(cl_I(0),::cl_R(cs));
+ else
+ *value = *value + ::cl_R(cs);
+ } while(delim != std::string::npos);
+ calchash();
+ setflag(status_flags::evaluated|
+ status_flags::hash_calculated);
}
/** Ctor from CLN types. This is for the initiated user or internal use
* only. */
numeric::numeric(const cl_N & z) : basic(TINFO_numeric)
{
- debugmsg("numeric constructor from cl_N", LOGLEVEL_CONSTRUCT);
- value = new ::cl_N(z);
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ debugmsg("numeric constructor from cl_N", LOGLEVEL_CONSTRUCT);
+ value = new ::cl_N(z);
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
//////////
/** Construct object from archive_node. */
numeric::numeric(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("numeric constructor from archive_node", LOGLEVEL_CONSTRUCT);
- value = new ::cl_N;
+ debugmsg("numeric constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ value = new ::cl_N;
- // Read number as string
- std::string str;
- if (n.find_string("number", str)) {
+ // Read number as string
+ std::string str;
+ if (n.find_string("number", str)) {
#ifdef HAVE_SSTREAM
- std::istringstream s(str);
+ std::istringstream s(str);
#else
- std::istrstream s(str.c_str(), str.size() + 1);
+ std::istrstream s(str.c_str(), str.size() + 1);
#endif
- ::cl_idecoded_float re, im;
- char c;
- s.get(c);
- switch (c) {
- case 'R': // Integer-decoded real number
- s >> re.sign >> re.mantissa >> re.exponent;
- *value = re.sign * re.mantissa * ::expt(cl_float(2.0, cl_default_float_format), re.exponent);
- break;
- case 'C': // Integer-decoded complex number
- s >> re.sign >> re.mantissa >> re.exponent;
- s >> im.sign >> im.mantissa >> im.exponent;
- *value = ::complex(re.sign * re.mantissa * ::expt(cl_float(2.0, cl_default_float_format), re.exponent),
- im.sign * im.mantissa * ::expt(cl_float(2.0, cl_default_float_format), im.exponent));
- break;
- default: // Ordinary number
- s.putback(c);
- s >> *value;
- break;
- }
- }
- calchash();
- setflag(status_flags::evaluated |
- status_flags::expanded |
- status_flags::hash_calculated);
+ ::cl_idecoded_float re, im;
+ char c;
+ s.get(c);
+ switch (c) {
+ case 'R': // Integer-decoded real number
+ s >> re.sign >> re.mantissa >> re.exponent;
+ *value = re.sign * re.mantissa * ::expt(cl_float(2.0, cl_default_float_format), re.exponent);
+ break;
+ case 'C': // Integer-decoded complex number
+ s >> re.sign >> re.mantissa >> re.exponent;
+ s >> im.sign >> im.mantissa >> im.exponent;
+ *value = ::complex(re.sign * re.mantissa * ::expt(cl_float(2.0, cl_default_float_format), re.exponent),
+ im.sign * im.mantissa * ::expt(cl_float(2.0, cl_default_float_format), im.exponent));
+ break;
+ default: // Ordinary number
+ s.putback(c);
+ s >> *value;
+ break;
+ }
+ }
+ calchash();
+ setflag(status_flags::evaluated |
+ status_flags::expanded |
+ status_flags::hash_calculated);
}
/** Unarchive the object. */
ex numeric::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new numeric(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new numeric(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void numeric::archive(archive_node &n) const
{
- inherited::archive(n);
+ inherited::archive(n);
- // Write number as string
+ // Write number as string
#ifdef HAVE_SSTREAM
- std::ostringstream s;
+ std::ostringstream s;
#else
- char buf[1024];
- std::ostrstream s(buf, 1024);
+ char buf[1024];
+ std::ostrstream s(buf, 1024);
#endif
- if (this->is_crational())
- s << *value;
- else {
- // Non-rational numbers are written in an integer-decoded format
- // to preserve the precision
- if (this->is_real()) {
- cl_idecoded_float re = integer_decode_float(The(::cl_F)(*value));
- s << "R";
- s << re.sign << " " << re.mantissa << " " << re.exponent;
- } else {
- cl_idecoded_float re = integer_decode_float(The(::cl_F)(::realpart(*value)));
- cl_idecoded_float im = integer_decode_float(The(::cl_F)(::imagpart(*value)));
- s << "C";
- s << re.sign << " " << re.mantissa << " " << re.exponent << " ";
- s << im.sign << " " << im.mantissa << " " << im.exponent;
- }
- }
+ if (this->is_crational())
+ s << *value;
+ else {
+ // Non-rational numbers are written in an integer-decoded format
+ // to preserve the precision
+ if (this->is_real()) {
+ cl_idecoded_float re = integer_decode_float(The(::cl_F)(*value));
+ s << "R";
+ s << re.sign << " " << re.mantissa << " " << re.exponent;
+ } else {
+ cl_idecoded_float re = integer_decode_float(The(::cl_F)(::realpart(*value)));
+ cl_idecoded_float im = integer_decode_float(The(::cl_F)(::imagpart(*value)));
+ s << "C";
+ s << re.sign << " " << re.mantissa << " " << re.exponent << " ";
+ s << im.sign << " " << im.mantissa << " " << im.exponent;
+ }
+ }
#ifdef HAVE_SSTREAM
- n.add_string("number", s.str());
+ n.add_string("number", s.str());
#else
- s << ends;
- std::string str(buf);
- n.add_string("number", str);
+ s << ends;
+ std::string str(buf);
+ n.add_string("number", str);
#endif
}
basic * numeric::duplicate() const
{
- debugmsg("numeric duplicate", LOGLEVEL_DUPLICATE);
- return new numeric(*this);
+ debugmsg("numeric duplicate", LOGLEVEL_DUPLICATE);
+ return new numeric(*this);
}
* @see numeric::print() */
static void print_real_number(std::ostream & os, const cl_R & num)
{
- cl_print_flags ourflags;
- if (::instanceof(num, ::cl_RA_ring)) {
- // case 1: integer or rational, nothing special to do:
- ::print_real(os, ourflags, num);
- } else {
- // case 2: float
- // make CLN believe this number has default_float_format, so it prints
- // 'E' as exponent marker instead of 'L':
- ourflags.default_float_format = ::cl_float_format(The(::cl_F)(num));
- ::print_real(os, ourflags, num);
- }
- return;
+ cl_print_flags ourflags;
+ if (::instanceof(num, ::cl_RA_ring)) {
+ // case 1: integer or rational, nothing special to do:
+ ::print_real(os, ourflags, num);
+ } else {
+ // case 2: float
+ // make CLN believe this number has default_float_format, so it prints
+ // 'E' as exponent marker instead of 'L':
+ ourflags.default_float_format = ::cl_float_format(The(::cl_F)(num));
+ ::print_real(os, ourflags, num);
+ }
+ return;
}
/** This method adds to the output so it blends more consistently together
* @see print_real_number() */
void numeric::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("numeric print", LOGLEVEL_PRINT);
- if (this->is_real()) {
- // case 1, real: x or -x
- if ((precedence<=upper_precedence) && (!this->is_nonneg_integer())) {
- os << "(";
- print_real_number(os, The(::cl_R)(*value));
- os << ")";
- } else {
- print_real_number(os, The(::cl_R)(*value));
- }
- } else {
- // case 2, imaginary: y*I or -y*I
- if (::realpart(*value) == 0) {
- if ((precedence<=upper_precedence) && (::imagpart(*value) < 0)) {
- if (::imagpart(*value) == -1) {
- os << "(-I)";
- } else {
- os << "(";
- print_real_number(os, The(::cl_R)(::imagpart(*value)));
- os << "*I)";
- }
- } else {
- if (::imagpart(*value) == 1) {
- os << "I";
- } else {
- if (::imagpart (*value) == -1) {
- os << "-I";
- } else {
- print_real_number(os, The(::cl_R)(::imagpart(*value)));
- os << "*I";
- }
- }
- }
- } else {
- // case 3, complex: x+y*I or x-y*I or -x+y*I or -x-y*I
- if (precedence <= upper_precedence)
- os << "(";
- print_real_number(os, The(::cl_R)(::realpart(*value)));
- if (::imagpart(*value) < 0) {
- if (::imagpart(*value) == -1) {
- os << "-I";
- } else {
- print_real_number(os, The(::cl_R)(::imagpart(*value)));
- os << "*I";
- }
- } else {
- if (::imagpart(*value) == 1) {
- os << "+I";
- } else {
- os << "+";
- print_real_number(os, The(::cl_R)(::imagpart(*value)));
- os << "*I";
- }
- }
- if (precedence <= upper_precedence)
- os << ")";
- }
- }
+ debugmsg("numeric print", LOGLEVEL_PRINT);
+ if (this->is_real()) {
+ // case 1, real: x or -x
+ if ((precedence<=upper_precedence) && (!this->is_nonneg_integer())) {
+ os << "(";
+ print_real_number(os, The(::cl_R)(*value));
+ os << ")";
+ } else {
+ print_real_number(os, The(::cl_R)(*value));
+ }
+ } else {
+ // case 2, imaginary: y*I or -y*I
+ if (::realpart(*value) == 0) {
+ if ((precedence<=upper_precedence) && (::imagpart(*value) < 0)) {
+ if (::imagpart(*value) == -1) {
+ os << "(-I)";
+ } else {
+ os << "(";
+ print_real_number(os, The(::cl_R)(::imagpart(*value)));
+ os << "*I)";
+ }
+ } else {
+ if (::imagpart(*value) == 1) {
+ os << "I";
+ } else {
+ if (::imagpart (*value) == -1) {
+ os << "-I";
+ } else {
+ print_real_number(os, The(::cl_R)(::imagpart(*value)));
+ os << "*I";
+ }
+ }
+ }
+ } else {
+ // case 3, complex: x+y*I or x-y*I or -x+y*I or -x-y*I
+ if (precedence <= upper_precedence)
+ os << "(";
+ print_real_number(os, The(::cl_R)(::realpart(*value)));
+ if (::imagpart(*value) < 0) {
+ if (::imagpart(*value) == -1) {
+ os << "-I";
+ } else {
+ print_real_number(os, The(::cl_R)(::imagpart(*value)));
+ os << "*I";
+ }
+ } else {
+ if (::imagpart(*value) == 1) {
+ os << "+I";
+ } else {
+ os << "+";
+ print_real_number(os, The(::cl_R)(::imagpart(*value)));
+ os << "*I";
+ }
+ }
+ if (precedence <= upper_precedence)
+ os << ")";
+ }
+ }
}
void numeric::printraw(std::ostream & os) const
{
- // The method printraw doesn't do much, it simply uses CLN's operator<<()
- // for output, which is ugly but reliable. e.g: 2+2i
- debugmsg("numeric printraw", LOGLEVEL_PRINT);
- os << "numeric(" << *value << ")";
+ // The method printraw doesn't do much, it simply uses CLN's operator<<()
+ // for output, which is ugly but reliable. e.g: 2+2i
+ debugmsg("numeric printraw", LOGLEVEL_PRINT);
+ os << "numeric(" << *value << ")";
}
void numeric::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("numeric printtree", LOGLEVEL_PRINT);
- os << std::string(indent,' ') << *value
- << " (numeric): "
- << "hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("numeric printtree", LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << *value
+ << " (numeric): "
+ << "hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void numeric::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("numeric print csrc", LOGLEVEL_PRINT);
- ios::fmtflags oldflags = os.flags();
- os.setf(ios::scientific);
- if (this->is_rational() && !this->is_integer()) {
- if (compare(_num0()) > 0) {
- os << "(";
- if (type == csrc_types::ctype_cl_N)
- os << "cl_F(\"" << numer().evalf() << "\")";
- else
- os << numer().to_double();
- } else {
- os << "-(";
- if (type == csrc_types::ctype_cl_N)
- os << "cl_F(\"" << -numer().evalf() << "\")";
- else
- os << -numer().to_double();
- }
- os << "/";
- if (type == csrc_types::ctype_cl_N)
- os << "cl_F(\"" << denom().evalf() << "\")";
- else
- os << denom().to_double();
- os << ")";
- } else {
- if (type == csrc_types::ctype_cl_N)
- os << "cl_F(\"" << evalf() << "\")";
- else
- os << to_double();
- }
- os.flags(oldflags);
+ debugmsg("numeric print csrc", LOGLEVEL_PRINT);
+ ios::fmtflags oldflags = os.flags();
+ os.setf(ios::scientific);
+ if (this->is_rational() && !this->is_integer()) {
+ if (compare(_num0()) > 0) {
+ os << "(";
+ if (type == csrc_types::ctype_cl_N)
+ os << "cl_F(\"" << numer().evalf() << "\")";
+ else
+ os << numer().to_double();
+ } else {
+ os << "-(";
+ if (type == csrc_types::ctype_cl_N)
+ os << "cl_F(\"" << -numer().evalf() << "\")";
+ else
+ os << -numer().to_double();
+ }
+ os << "/";
+ if (type == csrc_types::ctype_cl_N)
+ os << "cl_F(\"" << denom().evalf() << "\")";
+ else
+ os << denom().to_double();
+ os << ")";
+ } else {
+ if (type == csrc_types::ctype_cl_N)
+ os << "cl_F(\"" << evalf() << "\")";
+ else
+ os << to_double();
+ }
+ os.flags(oldflags);
}
bool numeric::info(unsigned inf) const
{
- switch (inf) {
- case info_flags::numeric:
- case info_flags::polynomial:
- case info_flags::rational_function:
- return true;
- case info_flags::real:
- return is_real();
- case info_flags::rational:
- case info_flags::rational_polynomial:
- return is_rational();
- case info_flags::crational:
- case info_flags::crational_polynomial:
- return is_crational();
- case info_flags::integer:
- case info_flags::integer_polynomial:
- return is_integer();
- case info_flags::cinteger:
- case info_flags::cinteger_polynomial:
- return is_cinteger();
- case info_flags::positive:
- return is_positive();
- case info_flags::negative:
- return is_negative();
- case info_flags::nonnegative:
- return !is_negative();
- case info_flags::posint:
- return is_pos_integer();
- case info_flags::negint:
- return is_integer() && is_negative();
- case info_flags::nonnegint:
- return is_nonneg_integer();
- case info_flags::even:
- return is_even();
- case info_flags::odd:
- return is_odd();
- case info_flags::prime:
- return is_prime();
- case info_flags::algebraic:
- return !is_real();
- }
- return false;
+ switch (inf) {
+ case info_flags::numeric:
+ case info_flags::polynomial:
+ case info_flags::rational_function:
+ return true;
+ case info_flags::real:
+ return is_real();
+ case info_flags::rational:
+ case info_flags::rational_polynomial:
+ return is_rational();
+ case info_flags::crational:
+ case info_flags::crational_polynomial:
+ return is_crational();
+ case info_flags::integer:
+ case info_flags::integer_polynomial:
+ return is_integer();
+ case info_flags::cinteger:
+ case info_flags::cinteger_polynomial:
+ return is_cinteger();
+ case info_flags::positive:
+ return is_positive();
+ case info_flags::negative:
+ return is_negative();
+ case info_flags::nonnegative:
+ return !is_negative();
+ case info_flags::posint:
+ return is_pos_integer();
+ case info_flags::negint:
+ return is_integer() && is_negative();
+ case info_flags::nonnegint:
+ return is_nonneg_integer();
+ case info_flags::even:
+ return is_even();
+ case info_flags::odd:
+ return is_odd();
+ case info_flags::prime:
+ return is_prime();
+ case info_flags::algebraic:
+ return !is_real();
+ }
+ return false;
}
/** Disassemble real part and imaginary part to scan for the occurrence of a
* sign as a multiplicative factor. */
bool numeric::has(const ex & other) const
{
- if (!is_exactly_of_type(*other.bp, numeric))
- return false;
- const numeric & o = static_cast<numeric &>(const_cast<basic &>(*other.bp));
- if (this->is_equal(o) || this->is_equal(-o))
- return true;
- if (o.imag().is_zero()) // e.g. scan for 3 in -3*I
- return (this->real().is_equal(o) || this->imag().is_equal(o) ||
- this->real().is_equal(-o) || this->imag().is_equal(-o));
- else {
- if (o.is_equal(I)) // e.g scan for I in 42*I
- return !this->is_real();
- if (o.real().is_zero()) // e.g. scan for 2*I in 2*I+1
- return (this->real().has(o*I) || this->imag().has(o*I) ||
- this->real().has(-o*I) || this->imag().has(-o*I));
- }
- return false;
+ if (!is_exactly_of_type(*other.bp, numeric))
+ return false;
+ const numeric & o = static_cast<numeric &>(const_cast<basic &>(*other.bp));
+ if (this->is_equal(o) || this->is_equal(-o))
+ return true;
+ if (o.imag().is_zero()) // e.g. scan for 3 in -3*I
+ return (this->real().is_equal(o) || this->imag().is_equal(o) ||
+ this->real().is_equal(-o) || this->imag().is_equal(-o));
+ else {
+ if (o.is_equal(I)) // e.g scan for I in 42*I
+ return !this->is_real();
+ if (o.real().is_zero()) // e.g. scan for 2*I in 2*I+1
+ return (this->real().has(o*I) || this->imag().has(o*I) ||
+ this->real().has(-o*I) || this->imag().has(-o*I));
+ }
+ return false;
}
/** Evaluation of numbers doesn't do anything at all. */
ex numeric::eval(int level) const
{
- // Warning: if this is ever gonna do something, the ex ctors from all kinds
- // of numbers should be checking for status_flags::evaluated.
- return this->hold();
+ // Warning: if this is ever gonna do something, the ex ctors from all kinds
+ // of numbers should be checking for status_flags::evaluated.
+ return this->hold();
}
* @return an ex-handle to a numeric. */
ex numeric::evalf(int level) const
{
- // level can safely be discarded for numeric objects.
- return numeric(::cl_float(1.0, ::cl_default_float_format) * (*value)); // -> CLN
+ // level can safely be discarded for numeric objects.
+ return numeric(::cl_float(1.0, ::cl_default_float_format) * (*value)); // -> CLN
}
// protected
* @see ex::diff */
ex numeric::derivative(const symbol & s) const
{
- return _ex0();
+ return _ex0();
}
int numeric::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_exactly_of_type(other, numeric));
- const numeric & o = static_cast<numeric &>(const_cast<basic &>(other));
+ GINAC_ASSERT(is_exactly_of_type(other, numeric));
+ const numeric & o = static_cast<numeric &>(const_cast<basic &>(other));
- if (*value == *o.value) {
- return 0;
- }
+ if (*value == *o.value) {
+ return 0;
+ }
- return compare(o);
+ return compare(o);
}
bool numeric::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(is_exactly_of_type(other,numeric));
- const numeric *o = static_cast<const numeric *>(&other);
-
- return this->is_equal(*o);
+ GINAC_ASSERT(is_exactly_of_type(other,numeric));
+ const numeric *o = static_cast<const numeric *>(&other);
+
+ return this->is_equal(*o);
}
unsigned numeric::calchash(void) const
{
- // Use CLN's hashcode. Warning: It depends only on the number's value, not
- // its type or precision (i.e. a true equivalence relation on numbers). As
- // a consequence, 3 and 3.0 share the same hashvalue.
- return (hashvalue = cl_equal_hashcode(*value) | 0x80000000U);
+ // Use CLN's hashcode. Warning: It depends only on the number's value, not
+ // its type or precision (i.e. a true equivalence relation on numbers). As
+ // a consequence, 3 and 3.0 share the same hashvalue.
+ return (hashvalue = cl_equal_hashcode(*value) | 0x80000000U);
}
* a new numeric object. */
numeric numeric::add(const numeric & other) const
{
- return numeric((*value)+(*other.value));
+ return numeric((*value)+(*other.value));
}
/** Numerical subtraction method. Subtracts argument from *this and returns
* result as a new numeric object. */
numeric numeric::sub(const numeric & other) const
{
- return numeric((*value)-(*other.value));
+ return numeric((*value)-(*other.value));
}
/** Numerical multiplication method. Multiplies *this and argument and returns
* result as a new numeric object. */
numeric numeric::mul(const numeric & other) const
{
- static const numeric * _num1p=&_num1();
- if (this==_num1p) {
- return other;
- } else if (&other==_num1p) {
- return *this;
- }
- return numeric((*value)*(*other.value));
+ static const numeric * _num1p=&_num1();
+ if (this==_num1p) {
+ return other;
+ } else if (&other==_num1p) {
+ return *this;
+ }
+ return numeric((*value)*(*other.value));
}
/** Numerical division method. Divides *this by argument and returns result as
* @exception overflow_error (division by zero) */
numeric numeric::div(const numeric & other) const
{
- if (::zerop(*other.value))
- throw std::overflow_error("numeric::div(): division by zero");
- return numeric((*value)/(*other.value));
+ if (::zerop(*other.value))
+ throw std::overflow_error("numeric::div(): division by zero");
+ return numeric((*value)/(*other.value));
}
numeric numeric::power(const numeric & other) const
{
- static const numeric * _num1p = &_num1();
- if (&other==_num1p)
- return *this;
- if (::zerop(*value)) {
- if (::zerop(*other.value))
- throw std::domain_error("numeric::eval(): pow(0,0) is undefined");
- else if (::zerop(::realpart(*other.value)))
- throw std::domain_error("numeric::eval(): pow(0,I) is undefined");
- else if (::minusp(::realpart(*other.value)))
- throw std::overflow_error("numeric::eval(): division by zero");
- else
- return _num0();
- }
- return numeric(::expt(*value,*other.value));
+ static const numeric * _num1p = &_num1();
+ if (&other==_num1p)
+ return *this;
+ if (::zerop(*value)) {
+ if (::zerop(*other.value))
+ throw std::domain_error("numeric::eval(): pow(0,0) is undefined");
+ else if (::zerop(::realpart(*other.value)))
+ throw std::domain_error("numeric::eval(): pow(0,I) is undefined");
+ else if (::minusp(::realpart(*other.value)))
+ throw std::overflow_error("numeric::eval(): division by zero");
+ else
+ return _num0();
+ }
+ return numeric(::expt(*value,*other.value));
}
/** Inverse of a number. */
numeric numeric::inverse(void) const
{
- if (::zerop(*value))
- throw std::overflow_error("numeric::inverse(): division by zero");
- return numeric(::recip(*value)); // -> CLN
+ if (::zerop(*value))
+ throw std::overflow_error("numeric::inverse(): division by zero");
+ return numeric(::recip(*value)); // -> CLN
}
const numeric & numeric::add_dyn(const numeric & other) const
{
- return static_cast<const numeric &>((new numeric((*value)+(*other.value)))->
- setflag(status_flags::dynallocated));
+ return static_cast<const numeric &>((new numeric((*value)+(*other.value)))->
+ setflag(status_flags::dynallocated));
}
const numeric & numeric::sub_dyn(const numeric & other) const
{
- return static_cast<const numeric &>((new numeric((*value)-(*other.value)))->
- setflag(status_flags::dynallocated));
+ return static_cast<const numeric &>((new numeric((*value)-(*other.value)))->
+ setflag(status_flags::dynallocated));
}
const numeric & numeric::mul_dyn(const numeric & other) const
{
- static const numeric * _num1p=&_num1();
- if (this==_num1p) {
- return other;
- } else if (&other==_num1p) {
- return *this;
- }
- return static_cast<const numeric &>((new numeric((*value)*(*other.value)))->
- setflag(status_flags::dynallocated));
+ static const numeric * _num1p=&_num1();
+ if (this==_num1p) {
+ return other;
+ } else if (&other==_num1p) {
+ return *this;
+ }
+ return static_cast<const numeric &>((new numeric((*value)*(*other.value)))->
+ setflag(status_flags::dynallocated));
}
const numeric & numeric::div_dyn(const numeric & other) const
{
- if (::zerop(*other.value))
- throw std::overflow_error("division by zero");
- return static_cast<const numeric &>((new numeric((*value)/(*other.value)))->
- setflag(status_flags::dynallocated));
+ if (::zerop(*other.value))
+ throw std::overflow_error("division by zero");
+ return static_cast<const numeric &>((new numeric((*value)/(*other.value)))->
+ setflag(status_flags::dynallocated));
}
const numeric & numeric::power_dyn(const numeric & other) const
{
- static const numeric * _num1p=&_num1();
- if (&other==_num1p)
- return *this;
- if (::zerop(*value)) {
- if (::zerop(*other.value))
- throw std::domain_error("numeric::eval(): pow(0,0) is undefined");
- else if (::zerop(::realpart(*other.value)))
- throw std::domain_error("numeric::eval(): pow(0,I) is undefined");
- else if (::minusp(::realpart(*other.value)))
- throw std::overflow_error("numeric::eval(): division by zero");
- else
- return _num0();
- }
- return static_cast<const numeric &>((new numeric(::expt(*value,*other.value)))->
- setflag(status_flags::dynallocated));
+ static const numeric * _num1p=&_num1();
+ if (&other==_num1p)
+ return *this;
+ if (::zerop(*value)) {
+ if (::zerop(*other.value))
+ throw std::domain_error("numeric::eval(): pow(0,0) is undefined");
+ else if (::zerop(::realpart(*other.value)))
+ throw std::domain_error("numeric::eval(): pow(0,I) is undefined");
+ else if (::minusp(::realpart(*other.value)))
+ throw std::overflow_error("numeric::eval(): division by zero");
+ else
+ return _num0();
+ }
+ return static_cast<const numeric &>((new numeric(::expt(*value,*other.value)))->
+ setflag(status_flags::dynallocated));
}
const numeric & numeric::operator=(int i)
{
- return operator=(numeric(i));
+ return operator=(numeric(i));
}
const numeric & numeric::operator=(unsigned int i)
{
- return operator=(numeric(i));
+ return operator=(numeric(i));
}
const numeric & numeric::operator=(long i)
{
- return operator=(numeric(i));
+ return operator=(numeric(i));
}
const numeric & numeric::operator=(unsigned long i)
{
- return operator=(numeric(i));
+ return operator=(numeric(i));
}
const numeric & numeric::operator=(double d)
{
- return operator=(numeric(d));
+ return operator=(numeric(d));
}
const numeric & numeric::operator=(const char * s)
{
- return operator=(numeric(s));
+ return operator=(numeric(s));
}
/** Return the complex half-plane (left or right) in which the number lies.
* @see numeric::compare(const numeric & other) */
int numeric::csgn(void) const
{
- if (this->is_zero())
- return 0;
- if (!::zerop(::realpart(*value))) {
- if (::plusp(::realpart(*value)))
- return 1;
- else
- return -1;
- } else {
- if (::plusp(::imagpart(*value)))
- return 1;
- else
- return -1;
- }
+ if (this->is_zero())
+ return 0;
+ if (!::zerop(::realpart(*value))) {
+ if (::plusp(::realpart(*value)))
+ return 1;
+ else
+ return -1;
+ } else {
+ if (::plusp(::imagpart(*value)))
+ return 1;
+ else
+ return -1;
+ }
}
/** This method establishes a canonical order on all numbers. For complex
* @see numeric::csgn(void) */
int numeric::compare(const numeric & other) const
{
- // Comparing two real numbers?
- if (this->is_real() && other.is_real())
- // Yes, just compare them
- return ::cl_compare(The(::cl_R)(*value), The(::cl_R)(*other.value));
- else {
- // No, first compare real parts
- cl_signean real_cmp = ::cl_compare(::realpart(*value), ::realpart(*other.value));
- if (real_cmp)
- return real_cmp;
+ // Comparing two real numbers?
+ if (this->is_real() && other.is_real())
+ // Yes, just compare them
+ return ::cl_compare(The(::cl_R)(*value), The(::cl_R)(*other.value));
+ else {
+ // No, first compare real parts
+ cl_signean real_cmp = ::cl_compare(::realpart(*value), ::realpart(*other.value));
+ if (real_cmp)
+ return real_cmp;
- return ::cl_compare(::imagpart(*value), ::imagpart(*other.value));
- }
+ return ::cl_compare(::imagpart(*value), ::imagpart(*other.value));
+ }
}
bool numeric::is_equal(const numeric & other) const
{
- return (*value == *other.value);
+ return (*value == *other.value);
}
/** True if object is zero. */
bool numeric::is_zero(void) const
{
- return ::zerop(*value); // -> CLN
+ return ::zerop(*value); // -> CLN
}
/** True if object is not complex and greater than zero. */
bool numeric::is_positive(void) const
{
- if (this->is_real())
- return ::plusp(The(::cl_R)(*value)); // -> CLN
- return false;
+ if (this->is_real())
+ return ::plusp(The(::cl_R)(*value)); // -> CLN
+ return false;
}
/** True if object is not complex and less than zero. */
bool numeric::is_negative(void) const
{
- if (this->is_real())
- return ::minusp(The(::cl_R)(*value)); // -> CLN
- return false;
+ if (this->is_real())
+ return ::minusp(The(::cl_R)(*value)); // -> CLN
+ return false;
}
/** True if object is a non-complex integer. */
bool numeric::is_integer(void) const
{
- return ::instanceof(*value, ::cl_I_ring); // -> CLN
+ return ::instanceof(*value, ::cl_I_ring); // -> CLN
}
/** True if object is an exact integer greater than zero. */
bool numeric::is_pos_integer(void) const
{
- return (this->is_integer() && ::plusp(The(::cl_I)(*value))); // -> CLN
+ return (this->is_integer() && ::plusp(The(::cl_I)(*value))); // -> CLN
}
/** True if object is an exact integer greater or equal zero. */
bool numeric::is_nonneg_integer(void) const
{
- return (this->is_integer() && !::minusp(The(::cl_I)(*value))); // -> CLN
+ return (this->is_integer() && !::minusp(The(::cl_I)(*value))); // -> CLN
}
/** True if object is an exact even integer. */
bool numeric::is_even(void) const
{
- return (this->is_integer() && ::evenp(The(::cl_I)(*value))); // -> CLN
+ return (this->is_integer() && ::evenp(The(::cl_I)(*value))); // -> CLN
}
/** True if object is an exact odd integer. */
bool numeric::is_odd(void) const
{
- return (this->is_integer() && ::oddp(The(::cl_I)(*value))); // -> CLN
+ return (this->is_integer() && ::oddp(The(::cl_I)(*value))); // -> CLN
}
/** Probabilistic primality test.
* @return true if object is exact integer and prime. */
bool numeric::is_prime(void) const
{
- return (this->is_integer() && ::isprobprime(The(::cl_I)(*value))); // -> CLN
+ return (this->is_integer() && ::isprobprime(The(::cl_I)(*value))); // -> CLN
}
/** True if object is an exact rational number, may even be complex
* (denominator may be unity). */
bool numeric::is_rational(void) const
{
- return ::instanceof(*value, ::cl_RA_ring); // -> CLN
+ return ::instanceof(*value, ::cl_RA_ring); // -> CLN
}
/** True if object is a real integer, rational or float (but not complex). */
bool numeric::is_real(void) const
{
- return ::instanceof(*value, ::cl_R_ring); // -> CLN
+ return ::instanceof(*value, ::cl_R_ring); // -> CLN
}
bool numeric::operator==(const numeric & other) const
{
- return (*value == *other.value); // -> CLN
+ return (*value == *other.value); // -> CLN
}
bool numeric::operator!=(const numeric & other) const
{
- return (*value != *other.value); // -> CLN
+ return (*value != *other.value); // -> CLN
}
/** True if object is element of the domain of integers extended by I, i.e. is
* of the form a+b*I, where a and b are integers. */
bool numeric::is_cinteger(void) const
{
- if (::instanceof(*value, ::cl_I_ring))
- return true;
- else if (!this->is_real()) { // complex case, handle n+m*I
- if (::instanceof(::realpart(*value), ::cl_I_ring) &&
- ::instanceof(::imagpart(*value), ::cl_I_ring))
- return true;
- }
- return false;
+ if (::instanceof(*value, ::cl_I_ring))
+ return true;
+ else if (!this->is_real()) { // complex case, handle n+m*I
+ if (::instanceof(::realpart(*value), ::cl_I_ring) &&
+ ::instanceof(::imagpart(*value), ::cl_I_ring))
+ return true;
+ }
+ return false;
}
/** True if object is an exact rational number, may even be complex
* (denominator may be unity). */
bool numeric::is_crational(void) const
{
- if (::instanceof(*value, ::cl_RA_ring))
- return true;
- else if (!this->is_real()) { // complex case, handle Q(i):
- if (::instanceof(::realpart(*value), ::cl_RA_ring) &&
- ::instanceof(::imagpart(*value), ::cl_RA_ring))
- return true;
- }
- return false;
+ if (::instanceof(*value, ::cl_RA_ring))
+ return true;
+ else if (!this->is_real()) { // complex case, handle Q(i):
+ if (::instanceof(::realpart(*value), ::cl_RA_ring) &&
+ ::instanceof(::imagpart(*value), ::cl_RA_ring))
+ return true;
+ }
+ return false;
}
/** Numerical comparison: less.
* @exception invalid_argument (complex inequality) */
bool numeric::operator<(const numeric & other) const
{
- if (this->is_real() && other.is_real())
- return (The(::cl_R)(*value) < The(::cl_R)(*other.value)); // -> CLN
- throw std::invalid_argument("numeric::operator<(): complex inequality");
- return false; // make compiler shut up
+ if (this->is_real() && other.is_real())
+ return (The(::cl_R)(*value) < The(::cl_R)(*other.value)); // -> CLN
+ throw std::invalid_argument("numeric::operator<(): complex inequality");
+ return false; // make compiler shut up
}
/** Numerical comparison: less or equal.
* @exception invalid_argument (complex inequality) */
bool numeric::operator<=(const numeric & other) const
{
- if (this->is_real() && other.is_real())
- return (The(::cl_R)(*value) <= The(::cl_R)(*other.value)); // -> CLN
- throw std::invalid_argument("numeric::operator<=(): complex inequality");
- return false; // make compiler shut up
+ if (this->is_real() && other.is_real())
+ return (The(::cl_R)(*value) <= The(::cl_R)(*other.value)); // -> CLN
+ throw std::invalid_argument("numeric::operator<=(): complex inequality");
+ return false; // make compiler shut up
}
/** Numerical comparison: greater.
* @exception invalid_argument (complex inequality) */
bool numeric::operator>(const numeric & other) const
{
- if (this->is_real() && other.is_real())
- return (The(::cl_R)(*value) > The(::cl_R)(*other.value)); // -> CLN
- throw std::invalid_argument("numeric::operator>(): complex inequality");
- return false; // make compiler shut up
+ if (this->is_real() && other.is_real())
+ return (The(::cl_R)(*value) > The(::cl_R)(*other.value)); // -> CLN
+ throw std::invalid_argument("numeric::operator>(): complex inequality");
+ return false; // make compiler shut up
}
/** Numerical comparison: greater or equal.
* @exception invalid_argument (complex inequality) */
bool numeric::operator>=(const numeric & other) const
{
- if (this->is_real() && other.is_real())
- return (The(::cl_R)(*value) >= The(::cl_R)(*other.value)); // -> CLN
- throw std::invalid_argument("numeric::operator>=(): complex inequality");
- return false; // make compiler shut up
+ if (this->is_real() && other.is_real())
+ return (The(::cl_R)(*value) >= The(::cl_R)(*other.value)); // -> CLN
+ throw std::invalid_argument("numeric::operator>=(): complex inequality");
+ return false; // make compiler shut up
}
/** Converts numeric types to machine's int. You should check with
* You may also consider checking the range first. */
int numeric::to_int(void) const
{
- GINAC_ASSERT(this->is_integer());
- return ::cl_I_to_int(The(::cl_I)(*value)); // -> CLN
+ GINAC_ASSERT(this->is_integer());
+ return ::cl_I_to_int(The(::cl_I)(*value)); // -> CLN
}
/** Converts numeric types to machine's long. You should check with
* You may also consider checking the range first. */
long numeric::to_long(void) const
{
- GINAC_ASSERT(this->is_integer());
- return ::cl_I_to_long(The(::cl_I)(*value)); // -> CLN
+ GINAC_ASSERT(this->is_integer());
+ return ::cl_I_to_long(The(::cl_I)(*value)); // -> CLN
}
/** Converts numeric types to machine's double. You should check with is_real()
* if the number is really not complex before calling this method. */
double numeric::to_double(void) const
{
- GINAC_ASSERT(this->is_real());
- return ::cl_double_approx(::realpart(*value)); // -> CLN
+ GINAC_ASSERT(this->is_real());
+ return ::cl_double_approx(::realpart(*value)); // -> CLN
}
/** Real part of a number. */
const numeric numeric::real(void) const
{
- return numeric(::realpart(*value)); // -> CLN
+ return numeric(::realpart(*value)); // -> CLN
}
/** Imaginary part of a number. */
const numeric numeric::imag(void) const
{
- return numeric(::imagpart(*value)); // -> CLN
+ return numeric(::imagpart(*value)); // -> CLN
}
#ifndef SANE_LINKER
// or denominator of a rational number (cl_RA). Doing some excavations in CLN
// one finds how it works internally in src/rational/cl_RA.h:
struct cl_heap_ratio : cl_heap {
- cl_I numerator;
- cl_I denominator;
+ cl_I numerator;
+ cl_I denominator;
};
inline cl_heap_ratio* TheRatio (const cl_N& obj)
* cases. */
const numeric numeric::numer(void) const
{
- if (this->is_integer()) {
- return numeric(*this);
- }
+ if (this->is_integer()) {
+ return numeric(*this);
+ }
#ifdef SANE_LINKER
- else if (::instanceof(*value, ::cl_RA_ring)) {
- return numeric(::numerator(The(::cl_RA)(*value)));
- }
- else if (!this->is_real()) { // complex case, handle Q(i):
- cl_R r = ::realpart(*value);
- cl_R i = ::imagpart(*value);
- if (::instanceof(r, ::cl_I_ring) && ::instanceof(i, ::cl_I_ring))
- return numeric(*this);
- if (::instanceof(r, ::cl_I_ring) && ::instanceof(i, ::cl_RA_ring))
- return numeric(::complex(r*::denominator(The(::cl_RA)(i)), ::numerator(The(::cl_RA)(i))));
- if (::instanceof(r, ::cl_RA_ring) && ::instanceof(i, ::cl_I_ring))
- return numeric(::complex(::numerator(The(::cl_RA)(r)), i*::denominator(The(::cl_RA)(r))));
- if (::instanceof(r, ::cl_RA_ring) && ::instanceof(i, ::cl_RA_ring)) {
- cl_I s = ::lcm(::denominator(The(::cl_RA)(r)), ::denominator(The(::cl_RA)(i)));
- return numeric(::complex(::numerator(The(::cl_RA)(r))*(exquo(s,::denominator(The(::cl_RA)(r)))),
- ::numerator(The(::cl_RA)(i))*(exquo(s,::denominator(The(::cl_RA)(i))))));
- }
- }
+ else if (::instanceof(*value, ::cl_RA_ring)) {
+ return numeric(::numerator(The(::cl_RA)(*value)));
+ }
+ else if (!this->is_real()) { // complex case, handle Q(i):
+ cl_R r = ::realpart(*value);
+ cl_R i = ::imagpart(*value);
+ if (::instanceof(r, ::cl_I_ring) && ::instanceof(i, ::cl_I_ring))
+ return numeric(*this);
+ if (::instanceof(r, ::cl_I_ring) && ::instanceof(i, ::cl_RA_ring))
+ return numeric(::complex(r*::denominator(The(::cl_RA)(i)), ::numerator(The(::cl_RA)(i))));
+ if (::instanceof(r, ::cl_RA_ring) && ::instanceof(i, ::cl_I_ring))
+ return numeric(::complex(::numerator(The(::cl_RA)(r)), i*::denominator(The(::cl_RA)(r))));
+ if (::instanceof(r, ::cl_RA_ring) && ::instanceof(i, ::cl_RA_ring)) {
+ cl_I s = ::lcm(::denominator(The(::cl_RA)(r)), ::denominator(The(::cl_RA)(i)));
+ return numeric(::complex(::numerator(The(::cl_RA)(r))*(exquo(s,::denominator(The(::cl_RA)(r)))),
+ ::numerator(The(::cl_RA)(i))*(exquo(s,::denominator(The(::cl_RA)(i))))));
+ }
+ }
#else
- else if (instanceof(*value, ::cl_RA_ring)) {
- return numeric(TheRatio(*value)->numerator);
- }
- else if (!this->is_real()) { // complex case, handle Q(i):
- cl_R r = ::realpart(*value);
- cl_R i = ::imagpart(*value);
- if (instanceof(r, ::cl_I_ring) && instanceof(i, ::cl_I_ring))
- return numeric(*this);
- if (instanceof(r, ::cl_I_ring) && instanceof(i, ::cl_RA_ring))
- return numeric(::complex(r*TheRatio(i)->denominator, TheRatio(i)->numerator));
- if (instanceof(r, ::cl_RA_ring) && instanceof(i, ::cl_I_ring))
- return numeric(::complex(TheRatio(r)->numerator, i*TheRatio(r)->denominator));
- if (instanceof(r, ::cl_RA_ring) && instanceof(i, ::cl_RA_ring)) {
- cl_I s = ::lcm(TheRatio(r)->denominator, TheRatio(i)->denominator);
- return numeric(::complex(TheRatio(r)->numerator*(exquo(s,TheRatio(r)->denominator)),
- TheRatio(i)->numerator*(exquo(s,TheRatio(i)->denominator))));
- }
- }
+ else if (instanceof(*value, ::cl_RA_ring)) {
+ return numeric(TheRatio(*value)->numerator);
+ }
+ else if (!this->is_real()) { // complex case, handle Q(i):
+ cl_R r = ::realpart(*value);
+ cl_R i = ::imagpart(*value);
+ if (instanceof(r, ::cl_I_ring) && instanceof(i, ::cl_I_ring))
+ return numeric(*this);
+ if (instanceof(r, ::cl_I_ring) && instanceof(i, ::cl_RA_ring))
+ return numeric(::complex(r*TheRatio(i)->denominator, TheRatio(i)->numerator));
+ if (instanceof(r, ::cl_RA_ring) && instanceof(i, ::cl_I_ring))
+ return numeric(::complex(TheRatio(r)->numerator, i*TheRatio(r)->denominator));
+ if (instanceof(r, ::cl_RA_ring) && instanceof(i, ::cl_RA_ring)) {
+ cl_I s = ::lcm(TheRatio(r)->denominator, TheRatio(i)->denominator);
+ return numeric(::complex(TheRatio(r)->numerator*(exquo(s,TheRatio(r)->denominator)),
+ TheRatio(i)->numerator*(exquo(s,TheRatio(i)->denominator))));
+ }
+ }
#endif // def SANE_LINKER
- // at least one float encountered
- return numeric(*this);
+ // at least one float encountered
+ return numeric(*this);
}
/** Denominator. Computes the denominator of rational numbers, common integer
* (i.e denom(4/3+5/6*I) == 6), one in all other cases. */
const numeric numeric::denom(void) const
{
- if (this->is_integer()) {
- return _num1();
- }
+ if (this->is_integer()) {
+ return _num1();
+ }
#ifdef SANE_LINKER
- if (instanceof(*value, ::cl_RA_ring)) {
- return numeric(::denominator(The(::cl_RA)(*value)));
- }
- if (!this->is_real()) { // complex case, handle Q(i):
- cl_R r = ::realpart(*value);
- cl_R i = ::imagpart(*value);
- if (::instanceof(r, ::cl_I_ring) && ::instanceof(i, ::cl_I_ring))
- return _num1();
- if (::instanceof(r, ::cl_I_ring) && ::instanceof(i, ::cl_RA_ring))
- return numeric(::denominator(The(::cl_RA)(i)));
- if (::instanceof(r, ::cl_RA_ring) && ::instanceof(i, ::cl_I_ring))
- return numeric(::denominator(The(::cl_RA)(r)));
- if (::instanceof(r, ::cl_RA_ring) && ::instanceof(i, ::cl_RA_ring))
- return numeric(::lcm(::denominator(The(::cl_RA)(r)), ::denominator(The(::cl_RA)(i))));
- }
+ if (instanceof(*value, ::cl_RA_ring)) {
+ return numeric(::denominator(The(::cl_RA)(*value)));
+ }
+ if (!this->is_real()) { // complex case, handle Q(i):
+ cl_R r = ::realpart(*value);
+ cl_R i = ::imagpart(*value);
+ if (::instanceof(r, ::cl_I_ring) && ::instanceof(i, ::cl_I_ring))
+ return _num1();
+ if (::instanceof(r, ::cl_I_ring) && ::instanceof(i, ::cl_RA_ring))
+ return numeric(::denominator(The(::cl_RA)(i)));
+ if (::instanceof(r, ::cl_RA_ring) && ::instanceof(i, ::cl_I_ring))
+ return numeric(::denominator(The(::cl_RA)(r)));
+ if (::instanceof(r, ::cl_RA_ring) && ::instanceof(i, ::cl_RA_ring))
+ return numeric(::lcm(::denominator(The(::cl_RA)(r)), ::denominator(The(::cl_RA)(i))));
+ }
#else
- if (instanceof(*value, ::cl_RA_ring)) {
- return numeric(TheRatio(*value)->denominator);
- }
- if (!this->is_real()) { // complex case, handle Q(i):
- cl_R r = ::realpart(*value);
- cl_R i = ::imagpart(*value);
- if (instanceof(r, ::cl_I_ring) && instanceof(i, ::cl_I_ring))
- return _num1();
- if (instanceof(r, ::cl_I_ring) && instanceof(i, ::cl_RA_ring))
- return numeric(TheRatio(i)->denominator);
- if (instanceof(r, ::cl_RA_ring) && instanceof(i, ::cl_I_ring))
- return numeric(TheRatio(r)->denominator);
- if (instanceof(r, ::cl_RA_ring) && instanceof(i, ::cl_RA_ring))
- return numeric(::lcm(TheRatio(r)->denominator, TheRatio(i)->denominator));
- }
+ if (instanceof(*value, ::cl_RA_ring)) {
+ return numeric(TheRatio(*value)->denominator);
+ }
+ if (!this->is_real()) { // complex case, handle Q(i):
+ cl_R r = ::realpart(*value);
+ cl_R i = ::imagpart(*value);
+ if (instanceof(r, ::cl_I_ring) && instanceof(i, ::cl_I_ring))
+ return _num1();
+ if (instanceof(r, ::cl_I_ring) && instanceof(i, ::cl_RA_ring))
+ return numeric(TheRatio(i)->denominator);
+ if (instanceof(r, ::cl_RA_ring) && instanceof(i, ::cl_I_ring))
+ return numeric(TheRatio(r)->denominator);
+ if (instanceof(r, ::cl_RA_ring) && instanceof(i, ::cl_RA_ring))
+ return numeric(::lcm(TheRatio(r)->denominator, TheRatio(i)->denominator));
+ }
#endif // def SANE_LINKER
- // at least one float encountered
- return _num1();
+ // at least one float encountered
+ return _num1();
}
/** Size in binary notation. For integers, this is the smallest n >= 0 such
* in two's complement if it is an integer, 0 otherwise. */
int numeric::int_length(void) const
{
- if (this->is_integer())
- return ::integer_length(The(::cl_I)(*value)); // -> CLN
- else
- return 0;
+ if (this->is_integer())
+ return ::integer_length(The(::cl_I)(*value)); // -> CLN
+ else
+ return 0;
}
* @return arbitrary precision numerical exp(x). */
const numeric exp(const numeric & x)
{
- return ::exp(*x.value); // -> CLN
+ return ::exp(*x.value); // -> CLN
}
* @exception pole_error("log(): logarithmic pole",0) */
const numeric log(const numeric & z)
{
- if (z.is_zero())
- throw pole_error("log(): logarithmic pole",0);
- return ::log(*z.value); // -> CLN
+ if (z.is_zero())
+ throw pole_error("log(): logarithmic pole",0);
+ return ::log(*z.value); // -> CLN
}
* @return arbitrary precision numerical sin(x). */
const numeric sin(const numeric & x)
{
- return ::sin(*x.value); // -> CLN
+ return ::sin(*x.value); // -> CLN
}
* @return arbitrary precision numerical cos(x). */
const numeric cos(const numeric & x)
{
- return ::cos(*x.value); // -> CLN
+ return ::cos(*x.value); // -> CLN
}
* @return arbitrary precision numerical tan(x). */
const numeric tan(const numeric & x)
{
- return ::tan(*x.value); // -> CLN
+ return ::tan(*x.value); // -> CLN
}
-
+
/** Numeric inverse sine (trigonometric function).
*
* @return arbitrary precision numerical asin(x). */
const numeric asin(const numeric & x)
{
- return ::asin(*x.value); // -> CLN
+ return ::asin(*x.value); // -> CLN
}
* @return arbitrary precision numerical acos(x). */
const numeric acos(const numeric & x)
{
- return ::acos(*x.value); // -> CLN
+ return ::acos(*x.value); // -> CLN
}
-
+
/** Arcustangent.
*
* @exception pole_error("atan(): logarithmic pole",0) */
const numeric atan(const numeric & x)
{
- if (!x.is_real() &&
- x.real().is_zero() &&
- abs(x.imag()).is_equal(_num1()))
- throw pole_error("atan(): logarithmic pole",0);
- return ::atan(*x.value); // -> CLN
+ if (!x.is_real() &&
+ x.real().is_zero() &&
+ abs(x.imag()).is_equal(_num1()))
+ throw pole_error("atan(): logarithmic pole",0);
+ return ::atan(*x.value); // -> CLN
}
* @return atan(y/x) */
const numeric atan(const numeric & y, const numeric & x)
{
- if (x.is_real() && y.is_real())
- return ::atan(::realpart(*x.value), ::realpart(*y.value)); // -> CLN
- else
- throw std::invalid_argument("atan(): complex argument");
+ if (x.is_real() && y.is_real())
+ return ::atan(::realpart(*x.value), ::realpart(*y.value)); // -> CLN
+ else
+ throw std::invalid_argument("atan(): complex argument");
}
* @return arbitrary precision numerical sinh(x). */
const numeric sinh(const numeric & x)
{
- return ::sinh(*x.value); // -> CLN
+ return ::sinh(*x.value); // -> CLN
}
* @return arbitrary precision numerical cosh(x). */
const numeric cosh(const numeric & x)
{
- return ::cosh(*x.value); // -> CLN
+ return ::cosh(*x.value); // -> CLN
}
* @return arbitrary precision numerical tanh(x). */
const numeric tanh(const numeric & x)
{
- return ::tanh(*x.value); // -> CLN
+ return ::tanh(*x.value); // -> CLN
}
-
+
/** Numeric inverse hyperbolic sine (trigonometric function).
*
* @return arbitrary precision numerical asinh(x). */
const numeric asinh(const numeric & x)
{
- return ::asinh(*x.value); // -> CLN
+ return ::asinh(*x.value); // -> CLN
}
* @return arbitrary precision numerical acosh(x). */
const numeric acosh(const numeric & x)
{
- return ::acosh(*x.value); // -> CLN
+ return ::acosh(*x.value); // -> CLN
}
* @return arbitrary precision numerical atanh(x). */
const numeric atanh(const numeric & x)
{
- return ::atanh(*x.value); // -> CLN
+ return ::atanh(*x.value); // -> CLN
}
/*static ::cl_N Li2_series(const ::cl_N & x,
- const ::cl_float_format_t & prec)
-{
- // Note: argument must be in the unit circle
- // This is very inefficient unless we have fast floating point Bernoulli
- // numbers implemented!
- ::cl_N c1 = -::log(1-x);
- ::cl_N c2 = c1;
- // hard-wire the first two Bernoulli numbers
- ::cl_N acc = c1 - ::square(c1)/4;
- ::cl_N aug;
- ::cl_F pisq = ::square(::cl_pi(prec)); // pi^2
- ::cl_F piac = ::cl_float(1, prec); // accumulator: pi^(2*i)
- unsigned i = 1;
- c1 = ::square(c1);
- do {
- c2 = c1 * c2;
- piac = piac * pisq;
- aug = c2 * (*(bernoulli(numeric(2*i)).clnptr())) / ::factorial(2*i+1);
- // aug = c2 * ::cl_I(i%2 ? 1 : -1) / ::cl_I(2*i+1) * ::cl_zeta(2*i, prec) / piac / (::cl_I(1)<<(2*i-1));
- acc = acc + aug;
- ++i;
- } while (acc != acc+aug);
- return acc;
+ const ::cl_float_format_t & prec)
+{
+ // Note: argument must be in the unit circle
+ // This is very inefficient unless we have fast floating point Bernoulli
+ // numbers implemented!
+ ::cl_N c1 = -::log(1-x);
+ ::cl_N c2 = c1;
+ // hard-wire the first two Bernoulli numbers
+ ::cl_N acc = c1 - ::square(c1)/4;
+ ::cl_N aug;
+ ::cl_F pisq = ::square(::cl_pi(prec)); // pi^2
+ ::cl_F piac = ::cl_float(1, prec); // accumulator: pi^(2*i)
+ unsigned i = 1;
+ c1 = ::square(c1);
+ do {
+ c2 = c1 * c2;
+ piac = piac * pisq;
+ aug = c2 * (*(bernoulli(numeric(2*i)).clnptr())) / ::factorial(2*i+1);
+ // aug = c2 * ::cl_I(i%2 ? 1 : -1) / ::cl_I(2*i+1) * ::cl_zeta(2*i, prec) / piac / (::cl_I(1)<<(2*i-1));
+ acc = acc + aug;
+ ++i;
+ } while (acc != acc+aug);
+ return acc;
}*/
/** Numeric evaluation of Dilogarithm within circle of convergence (unit
* circle) using a power series. */
static ::cl_N Li2_series(const ::cl_N & x,
- const ::cl_float_format_t & prec)
-{
- // Note: argument must be in the unit circle
- ::cl_N aug, acc;
- ::cl_N num = ::complex(::cl_float(1, prec), 0);
- ::cl_I den = 0;
- unsigned i = 1;
- do {
- num = num * x;
- den = den + i; // 1, 4, 9, 16, ...
- i += 2;
- aug = num / den;
- acc = acc + aug;
- } while (acc != acc+aug);
- return acc;
+ const ::cl_float_format_t & prec)
+{
+ // Note: argument must be in the unit circle
+ ::cl_N aug, acc;
+ ::cl_N num = ::complex(::cl_float(1, prec), 0);
+ ::cl_I den = 0;
+ unsigned i = 1;
+ do {
+ num = num * x;
+ den = den + i; // 1, 4, 9, 16, ...
+ i += 2;
+ aug = num / den;
+ acc = acc + aug;
+ } while (acc != acc+aug);
+ return acc;
}
/** Folds Li2's argument inside a small rectangle to enhance convergence. */
static ::cl_N Li2_projection(const ::cl_N & x,
- const ::cl_float_format_t & prec)
-{
- const ::cl_R re = ::realpart(x);
- const ::cl_R im = ::imagpart(x);
- if (re > ::cl_F(".5"))
- // zeta(2) - Li2(1-x) - log(x)*log(1-x)
- return(::cl_zeta(2)
- - Li2_series(1-x, prec)
- - ::log(x)*::log(1-x));
- if ((re <= 0 && ::abs(im) > ::cl_F(".75")) || (re < ::cl_F("-.5")))
- // -log(1-x)^2 / 2 - Li2(x/(x-1))
- return(-::square(::log(1-x))/2
- - Li2_series(x/(x-1), prec));
- if (re > 0 && ::abs(im) > ::cl_LF(".75"))
- // Li2(x^2)/2 - Li2(-x)
- return(Li2_projection(::square(x), prec)/2
- - Li2_projection(-x, prec));
- return Li2_series(x, prec);
+ const ::cl_float_format_t & prec)
+{
+ const ::cl_R re = ::realpart(x);
+ const ::cl_R im = ::imagpart(x);
+ if (re > ::cl_F(".5"))
+ // zeta(2) - Li2(1-x) - log(x)*log(1-x)
+ return(::cl_zeta(2)
+ - Li2_series(1-x, prec)
+ - ::log(x)*::log(1-x));
+ if ((re <= 0 && ::abs(im) > ::cl_F(".75")) || (re < ::cl_F("-.5")))
+ // -log(1-x)^2 / 2 - Li2(x/(x-1))
+ return(-::square(::log(1-x))/2
+ - Li2_series(x/(x-1), prec));
+ if (re > 0 && ::abs(im) > ::cl_LF(".75"))
+ // Li2(x^2)/2 - Li2(-x)
+ return(Li2_projection(::square(x), prec)/2
+ - Li2_projection(-x, prec));
+ return Li2_series(x, prec);
}
/** Numeric evaluation of Dilogarithm. The domain is the entire complex plane,
* @return arbitrary precision numerical Li2(x). */
const numeric Li2(const numeric & x)
{
- if (::zerop(*x.value))
- return x;
-
- // what is the desired float format?
- // first guess: default format
- ::cl_float_format_t prec = ::cl_default_float_format;
- // second guess: the argument's format
- if (!::instanceof(::realpart(*x.value),cl_RA_ring))
- prec = ::cl_float_format(The(::cl_F)(::realpart(*x.value)));
- else if (!::instanceof(::imagpart(*x.value),cl_RA_ring))
- prec = ::cl_float_format(The(::cl_F)(::imagpart(*x.value)));
-
- if (*x.value==1) // may cause trouble with log(1-x)
- return ::cl_zeta(2, prec);
-
- if (::abs(*x.value) > 1)
- // -log(-x)^2 / 2 - zeta(2) - Li2(1/x)
- return(-::square(::log(-*x.value))/2
- - ::cl_zeta(2, prec)
- - Li2_projection(::recip(*x.value), prec));
- else
- return Li2_projection(*x.value, prec);
+ if (::zerop(*x.value))
+ return x;
+
+ // what is the desired float format?
+ // first guess: default format
+ ::cl_float_format_t prec = ::cl_default_float_format;
+ // second guess: the argument's format
+ if (!::instanceof(::realpart(*x.value),cl_RA_ring))
+ prec = ::cl_float_format(The(::cl_F)(::realpart(*x.value)));
+ else if (!::instanceof(::imagpart(*x.value),cl_RA_ring))
+ prec = ::cl_float_format(The(::cl_F)(::imagpart(*x.value)));
+
+ if (*x.value==1) // may cause trouble with log(1-x)
+ return ::cl_zeta(2, prec);
+
+ if (::abs(*x.value) > 1)
+ // -log(-x)^2 / 2 - zeta(2) - Li2(1/x)
+ return(-::square(::log(-*x.value))/2
+ - ::cl_zeta(2, prec)
+ - Li2_projection(::recip(*x.value), prec));
+ else
+ return Li2_projection(*x.value, prec);
}
* integer arguments. */
const numeric zeta(const numeric & x)
{
- // A dirty hack to allow for things like zeta(3.0), since CLN currently
- // only knows about integer arguments and zeta(3).evalf() automatically
- // cascades down to zeta(3.0).evalf(). The trick is to rely on 3.0-3
- // being an exact zero for CLN, which can be tested and then we can just
- // pass the number casted to an int:
- if (x.is_real()) {
- int aux = (int)(::cl_double_approx(::realpart(*x.value)));
- if (::zerop(*x.value-aux))
- return ::cl_zeta(aux); // -> CLN
- }
- std::clog << "zeta(" << x
- << "): Does anybody know good way to calculate this numerically?"
- << std::endl;
- return numeric(0);
+ // A dirty hack to allow for things like zeta(3.0), since CLN currently
+ // only knows about integer arguments and zeta(3).evalf() automatically
+ // cascades down to zeta(3.0).evalf(). The trick is to rely on 3.0-3
+ // being an exact zero for CLN, which can be tested and then we can just
+ // pass the number casted to an int:
+ if (x.is_real()) {
+ int aux = (int)(::cl_double_approx(::realpart(*x.value)));
+ if (::zerop(*x.value-aux))
+ return ::cl_zeta(aux); // -> CLN
+ }
+ std::clog << "zeta(" << x
+ << "): Does anybody know good way to calculate this numerically?"
+ << std::endl;
+ return numeric(0);
}
* This is only a stub! */
const numeric lgamma(const numeric & x)
{
- std::clog << "lgamma(" << x
- << "): Does anybody know good way to calculate this numerically?"
- << std::endl;
- return numeric(0);
+ std::clog << "lgamma(" << x
+ << "): Does anybody know good way to calculate this numerically?"
+ << std::endl;
+ return numeric(0);
}
const numeric tgamma(const numeric & x)
{
- std::clog << "tgamma(" << x
- << "): Does anybody know good way to calculate this numerically?"
- << std::endl;
- return numeric(0);
+ std::clog << "tgamma(" << x
+ << "): Does anybody know good way to calculate this numerically?"
+ << std::endl;
+ return numeric(0);
}
* This is only a stub! */
const numeric psi(const numeric & x)
{
- std::clog << "psi(" << x
- << "): Does anybody know good way to calculate this numerically?"
- << std::endl;
- return numeric(0);
+ std::clog << "psi(" << x
+ << "): Does anybody know good way to calculate this numerically?"
+ << std::endl;
+ return numeric(0);
}
* This is only a stub! */
const numeric psi(const numeric & n, const numeric & x)
{
- std::clog << "psi(" << n << "," << x
- << "): Does anybody know good way to calculate this numerically?"
- << std::endl;
- return numeric(0);
+ std::clog << "psi(" << n << "," << x
+ << "): Does anybody know good way to calculate this numerically?"
+ << std::endl;
+ return numeric(0);
}
* @exception range_error (argument must be integer >= 0) */
const numeric factorial(const numeric & n)
{
- if (!n.is_nonneg_integer())
- throw std::range_error("numeric::factorial(): argument must be integer >= 0");
- return numeric(::factorial(n.to_int())); // -> CLN
+ if (!n.is_nonneg_integer())
+ throw std::range_error("numeric::factorial(): argument must be integer >= 0");
+ return numeric(::factorial(n.to_int())); // -> CLN
}
* @exception range_error (argument must be integer >= -1) */
const numeric doublefactorial(const numeric & n)
{
- if (n == numeric(-1)) {
- return _num1();
- }
- if (!n.is_nonneg_integer()) {
- throw std::range_error("numeric::doublefactorial(): argument must be integer >= -1");
- }
- return numeric(::doublefactorial(n.to_int())); // -> CLN
+ if (n == numeric(-1)) {
+ return _num1();
+ }
+ if (!n.is_nonneg_integer()) {
+ throw std::range_error("numeric::doublefactorial(): argument must be integer >= -1");
+ }
+ return numeric(::doublefactorial(n.to_int())); // -> CLN
}
* binomial(n,k) == (-1)^k*binomial(k-n-1,k) is used to compute the result. */
const numeric binomial(const numeric & n, const numeric & k)
{
- if (n.is_integer() && k.is_integer()) {
- if (n.is_nonneg_integer()) {
- if (k.compare(n)!=1 && k.compare(_num0())!=-1)
- return numeric(::binomial(n.to_int(),k.to_int())); // -> CLN
- else
- return _num0();
- } else {
- return _num_1().power(k)*binomial(k-n-_num1(),k);
- }
- }
-
- // should really be gamma(n+1)/gamma(r+1)/gamma(n-r+1) or a suitable limit
- throw std::range_error("numeric::binomial(): don´t know how to evaluate that.");
+ if (n.is_integer() && k.is_integer()) {
+ if (n.is_nonneg_integer()) {
+ if (k.compare(n)!=1 && k.compare(_num0())!=-1)
+ return numeric(::binomial(n.to_int(),k.to_int())); // -> CLN
+ else
+ return _num0();
+ } else {
+ return _num_1().power(k)*binomial(k-n-_num1(),k);
+ }
+ }
+
+ // should really be gamma(n+1)/gamma(r+1)/gamma(n-r+1) or a suitable limit
+ throw std::range_error("numeric::binomial(): don´t know how to evaluate that.");
}
* @exception range_error (argument must be integer >= 0) */
const numeric bernoulli(const numeric & nn)
{
- if (!nn.is_integer() || nn.is_negative())
- throw std::range_error("numeric::bernoulli(): argument must be integer >= 0");
-
- // Method:
- //
- // The Bernoulli numbers are rational numbers that may be computed using
- // the relation
- //
- // B_n = - 1/(n+1) * sum_{k=0}^{n-1}(binomial(n+1,k)*B_k)
- //
- // with B(0) = 1. Since the n'th Bernoulli number depends on all the
- // previous ones, the computation is necessarily very expensive. There are
- // several other ways of computing them, a particularly good one being
- // cl_I s = 1;
- // cl_I c = n+1;
- // cl_RA Bern = 0;
- // for (unsigned i=0; i<n; i++) {
- // c = exquo(c*(i-n),(i+2));
- // Bern = Bern + c*s/(i+2);
- // s = s + expt_pos(cl_I(i+2),n);
- // }
- // return Bern;
- //
- // But if somebody works with the n'th Bernoulli number she is likely to
- // also need all previous Bernoulli numbers. So we need a complete remember
- // table and above divide and conquer algorithm is not suited to build one
- // up. The code below is adapted from Pari's function bernvec().
- //
- // (There is an interesting relation with the tangent polynomials described
- // in `Concrete Mathematics', which leads to a program twice as fast as our
- // implementation below, but it requires storing one such polynomial in
- // addition to the remember table. This doubles the memory footprint so
- // we don't use it.)
-
- // the special cases not covered by the algorithm below
- if (nn.is_equal(_num1()))
- return _num_1_2();
- if (nn.is_odd())
- return _num0();
-
- // store nonvanishing Bernoulli numbers here
- static std::vector< ::cl_RA > results;
- static int highest_result = 0;
- // algorithm not applicable to B(0), so just store it
- if (results.size()==0)
- results.push_back(::cl_RA(1));
-
- int n = nn.to_long();
- for (int i=highest_result; i<n/2; ++i) {
- ::cl_RA B = 0;
- long n = 8;
- long m = 5;
- long d1 = i;
- long d2 = 2*i-1;
- for (int j=i; j>0; --j) {
- B = ::cl_I(n*m) * (B+results[j]) / (d1*d2);
- n += 4;
- m += 2;
- d1 -= 1;
- d2 -= 2;
- }
- B = (1 - ((B+1)/(2*i+3))) / (::cl_I(1)<<(2*i+2));
- results.push_back(B);
- ++highest_result;
- }
- return results[n/2];
+ if (!nn.is_integer() || nn.is_negative())
+ throw std::range_error("numeric::bernoulli(): argument must be integer >= 0");
+
+ // Method:
+ //
+ // The Bernoulli numbers are rational numbers that may be computed using
+ // the relation
+ //
+ // B_n = - 1/(n+1) * sum_{k=0}^{n-1}(binomial(n+1,k)*B_k)
+ //
+ // with B(0) = 1. Since the n'th Bernoulli number depends on all the
+ // previous ones, the computation is necessarily very expensive. There are
+ // several other ways of computing them, a particularly good one being
+ // cl_I s = 1;
+ // cl_I c = n+1;
+ // cl_RA Bern = 0;
+ // for (unsigned i=0; i<n; i++) {
+ // c = exquo(c*(i-n),(i+2));
+ // Bern = Bern + c*s/(i+2);
+ // s = s + expt_pos(cl_I(i+2),n);
+ // }
+ // return Bern;
+ //
+ // But if somebody works with the n'th Bernoulli number she is likely to
+ // also need all previous Bernoulli numbers. So we need a complete remember
+ // table and above divide and conquer algorithm is not suited to build one
+ // up. The code below is adapted from Pari's function bernvec().
+ //
+ // (There is an interesting relation with the tangent polynomials described
+ // in `Concrete Mathematics', which leads to a program twice as fast as our
+ // implementation below, but it requires storing one such polynomial in
+ // addition to the remember table. This doubles the memory footprint so
+ // we don't use it.)
+
+ // the special cases not covered by the algorithm below
+ if (nn.is_equal(_num1()))
+ return _num_1_2();
+ if (nn.is_odd())
+ return _num0();
+
+ // store nonvanishing Bernoulli numbers here
+ static std::vector< ::cl_RA > results;
+ static int highest_result = 0;
+ // algorithm not applicable to B(0), so just store it
+ if (results.size()==0)
+ results.push_back(::cl_RA(1));
+
+ int n = nn.to_long();
+ for (int i=highest_result; i<n/2; ++i) {
+ ::cl_RA B = 0;
+ long n = 8;
+ long m = 5;
+ long d1 = i;
+ long d2 = 2*i-1;
+ for (int j=i; j>0; --j) {
+ B = ::cl_I(n*m) * (B+results[j]) / (d1*d2);
+ n += 4;
+ m += 2;
+ d1 -= 1;
+ d2 -= 2;
+ }
+ B = (1 - ((B+1)/(2*i+3))) / (::cl_I(1)<<(2*i+2));
+ results.push_back(B);
+ ++highest_result;
+ }
+ return results[n/2];
}
* @exception range_error (argument must be an integer) */
const numeric fibonacci(const numeric & n)
{
- if (!n.is_integer())
- throw std::range_error("numeric::fibonacci(): argument must be integer");
- // Method:
- //
- // This is based on an implementation that can be found in CLN's example
- // directory. There, it is done recursively, which may be more elegant
- // than our non-recursive implementation that has to resort to some bit-
- // fiddling. This is, however, a matter of taste.
- // The following addition formula holds:
- //
- // F(n+m) = F(m-1)*F(n) + F(m)*F(n+1) for m >= 1, n >= 0.
- //
- // (Proof: For fixed m, the LHS and the RHS satisfy the same recurrence
- // w.r.t. n, and the initial values (n=0, n=1) agree. Hence all values
- // agree.)
- // Replace m by m+1:
- // F(n+m+1) = F(m)*F(n) + F(m+1)*F(n+1) for m >= 0, n >= 0
- // Now put in m = n, to get
- // F(2n) = (F(n+1)-F(n))*F(n) + F(n)*F(n+1) = F(n)*(2*F(n+1) - F(n))
- // F(2n+1) = F(n)^2 + F(n+1)^2
- // hence
- // F(2n+2) = F(n+1)*(2*F(n) + F(n+1))
- if (n.is_zero())
- return _num0();
- if (n.is_negative())
- if (n.is_even())
- return -fibonacci(-n);
- else
- return fibonacci(-n);
-
- ::cl_I u(0);
- ::cl_I v(1);
- ::cl_I m = The(::cl_I)(*n.value) >> 1L; // floor(n/2);
- for (uintL bit=::integer_length(m); bit>0; --bit) {
- // Since a squaring is cheaper than a multiplication, better use
- // three squarings instead of one multiplication and two squarings.
- ::cl_I u2 = ::square(u);
- ::cl_I v2 = ::square(v);
- if (::logbitp(bit-1, m)) {
- v = ::square(u + v) - u2;
- u = u2 + v2;
- } else {
- u = v2 - ::square(v - u);
- v = u2 + v2;
- }
- }
- if (n.is_even())
- // Here we don't use the squaring formula because one multiplication
- // is cheaper than two squarings.
- return u * ((v << 1) - u);
- else
- return ::square(u) + ::square(v);
+ if (!n.is_integer())
+ throw std::range_error("numeric::fibonacci(): argument must be integer");
+ // Method:
+ //
+ // This is based on an implementation that can be found in CLN's example
+ // directory. There, it is done recursively, which may be more elegant
+ // than our non-recursive implementation that has to resort to some bit-
+ // fiddling. This is, however, a matter of taste.
+ // The following addition formula holds:
+ //
+ // F(n+m) = F(m-1)*F(n) + F(m)*F(n+1) for m >= 1, n >= 0.
+ //
+ // (Proof: For fixed m, the LHS and the RHS satisfy the same recurrence
+ // w.r.t. n, and the initial values (n=0, n=1) agree. Hence all values
+ // agree.)
+ // Replace m by m+1:
+ // F(n+m+1) = F(m)*F(n) + F(m+1)*F(n+1) for m >= 0, n >= 0
+ // Now put in m = n, to get
+ // F(2n) = (F(n+1)-F(n))*F(n) + F(n)*F(n+1) = F(n)*(2*F(n+1) - F(n))
+ // F(2n+1) = F(n)^2 + F(n+1)^2
+ // hence
+ // F(2n+2) = F(n+1)*(2*F(n) + F(n+1))
+ if (n.is_zero())
+ return _num0();
+ if (n.is_negative())
+ if (n.is_even())
+ return -fibonacci(-n);
+ else
+ return fibonacci(-n);
+
+ ::cl_I u(0);
+ ::cl_I v(1);
+ ::cl_I m = The(::cl_I)(*n.value) >> 1L; // floor(n/2);
+ for (uintL bit=::integer_length(m); bit>0; --bit) {
+ // Since a squaring is cheaper than a multiplication, better use
+ // three squarings instead of one multiplication and two squarings.
+ ::cl_I u2 = ::square(u);
+ ::cl_I v2 = ::square(v);
+ if (::logbitp(bit-1, m)) {
+ v = ::square(u + v) - u2;
+ u = u2 + v2;
+ } else {
+ u = v2 - ::square(v - u);
+ v = u2 + v2;
+ }
+ }
+ if (n.is_even())
+ // Here we don't use the squaring formula because one multiplication
+ // is cheaper than two squarings.
+ return u * ((v << 1) - u);
+ else
+ return ::square(u) + ::square(v);
}
/** Absolute value. */
numeric abs(const numeric & x)
{
- return ::abs(*x.value); // -> CLN
+ return ::abs(*x.value); // -> CLN
}
* integer, 0 otherwise. */
numeric mod(const numeric & a, const numeric & b)
{
- if (a.is_integer() && b.is_integer())
- return ::mod(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
- else
- return _num0(); // Throw?
+ if (a.is_integer() && b.is_integer())
+ return ::mod(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
+ else
+ return _num0(); // Throw?
}
* @return a mod b in the range [-iquo(abs(m)-1,2), iquo(abs(m),2)]. */
numeric smod(const numeric & a, const numeric & b)
{
- if (a.is_integer() && b.is_integer()) {
- cl_I b2 = The(::cl_I)(ceiling1(The(::cl_I)(*b.value) / 2)) - 1;
- return ::mod(The(::cl_I)(*a.value) + b2, The(::cl_I)(*b.value)) - b2;
- } else
- return _num0(); // Throw?
+ if (a.is_integer() && b.is_integer()) {
+ cl_I b2 = The(::cl_I)(ceiling1(The(::cl_I)(*b.value) / 2)) - 1;
+ return ::mod(The(::cl_I)(*a.value) + b2, The(::cl_I)(*b.value)) - b2;
+ } else
+ return _num0(); // Throw?
}
* @return remainder of a/b if both are integer, 0 otherwise. */
numeric irem(const numeric & a, const numeric & b)
{
- if (a.is_integer() && b.is_integer())
- return ::rem(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
- else
- return _num0(); // Throw?
+ if (a.is_integer() && b.is_integer())
+ return ::rem(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
+ else
+ return _num0(); // Throw?
}
* 0 otherwise. */
numeric irem(const numeric & a, const numeric & b, numeric & q)
{
- if (a.is_integer() && b.is_integer()) { // -> CLN
- cl_I_div_t rem_quo = truncate2(The(::cl_I)(*a.value), The(::cl_I)(*b.value));
- q = rem_quo.quotient;
- return rem_quo.remainder;
- }
- else {
- q = _num0();
- return _num0(); // Throw?
- }
+ if (a.is_integer() && b.is_integer()) { // -> CLN
+ cl_I_div_t rem_quo = truncate2(The(::cl_I)(*a.value), The(::cl_I)(*b.value));
+ q = rem_quo.quotient;
+ return rem_quo.remainder;
+ }
+ else {
+ q = _num0();
+ return _num0(); // Throw?
+ }
}
* @return truncated quotient of a/b if both are integer, 0 otherwise. */
numeric iquo(const numeric & a, const numeric & b)
{
- if (a.is_integer() && b.is_integer())
- return truncate1(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
- else
- return _num0(); // Throw?
+ if (a.is_integer() && b.is_integer())
+ return truncate1(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
+ else
+ return _num0(); // Throw?
}
* integer, 0 otherwise. */
numeric iquo(const numeric & a, const numeric & b, numeric & r)
{
- if (a.is_integer() && b.is_integer()) { // -> CLN
- cl_I_div_t rem_quo = truncate2(The(::cl_I)(*a.value), The(::cl_I)(*b.value));
- r = rem_quo.remainder;
- return rem_quo.quotient;
- } else {
- r = _num0();
- return _num0(); // Throw?
- }
+ if (a.is_integer() && b.is_integer()) { // -> CLN
+ cl_I_div_t rem_quo = truncate2(The(::cl_I)(*a.value), The(::cl_I)(*b.value));
+ r = rem_quo.remainder;
+ return rem_quo.quotient;
+ } else {
+ r = _num0();
+ return _num0(); // Throw?
+ }
}
* where imag(z)>0. */
numeric sqrt(const numeric & z)
{
- return ::sqrt(*z.value); // -> CLN
+ return ::sqrt(*z.value); // -> CLN
}
/** Integer numeric square root. */
numeric isqrt(const numeric & x)
{
- if (x.is_integer()) {
- cl_I root;
- ::isqrt(The(::cl_I)(*x.value), &root); // -> CLN
- return root;
- } else
- return _num0(); // Throw?
+ if (x.is_integer()) {
+ cl_I root;
+ ::isqrt(The(::cl_I)(*x.value), &root); // -> CLN
+ return root;
+ } else
+ return _num0(); // Throw?
}
* if they are not. */
numeric gcd(const numeric & a, const numeric & b)
{
- if (a.is_integer() && b.is_integer())
- return ::gcd(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
- else
- return _num1();
+ if (a.is_integer() && b.is_integer())
+ return ::gcd(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
+ else
+ return _num1();
}
* two numbers if they are not. */
numeric lcm(const numeric & a, const numeric & b)
{
- if (a.is_integer() && b.is_integer())
- return ::lcm(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
- else
- return *a.value * *b.value;
+ if (a.is_integer() && b.is_integer())
+ return ::lcm(The(::cl_I)(*a.value), The(::cl_I)(*b.value)); // -> CLN
+ else
+ return *a.value * *b.value;
}
/** Floating point evaluation of Archimedes' constant Pi. */
ex PiEvalf(void)
{
- return numeric(::cl_pi(cl_default_float_format)); // -> CLN
+ return numeric(::cl_pi(cl_default_float_format)); // -> CLN
}
/** Floating point evaluation of Euler's constant gamma. */
ex EulerEvalf(void)
{
- return numeric(::cl_eulerconst(cl_default_float_format)); // -> CLN
+ return numeric(::cl_eulerconst(cl_default_float_format)); // -> CLN
}
/** Floating point evaluation of Catalan's constant. */
ex CatalanEvalf(void)
{
- return numeric(::cl_catalanconst(cl_default_float_format)); // -> CLN
+ return numeric(::cl_catalanconst(cl_default_float_format)); // -> CLN
}
// be 61 (<64) while cl_float_format(18)=65. We want to have a cl_LF instead
// of cl_SF, cl_FF or cl_DF but everything else is basically arbitrary.
_numeric_digits::_numeric_digits()
- : digits(17)
+ : digits(17)
{
- assert(!too_late);
- too_late = true;
- cl_default_float_format = ::cl_float_format(17);
+ assert(!too_late);
+ too_late = true;
+ cl_default_float_format = ::cl_float_format(17);
}
_numeric_digits& _numeric_digits::operator=(long prec)
{
- digits=prec;
- cl_default_float_format = ::cl_float_format(prec);
- return *this;
+ digits=prec;
+ cl_default_float_format = ::cl_float_format(prec);
+ return *this;
}
_numeric_digits::operator long()
{
- return (long)digits;
+ return (long)digits;
}
void _numeric_digits::print(std::ostream & os) const
{
- debugmsg("_numeric_digits print", LOGLEVEL_PRINT);
- os << digits;
+ debugmsg("_numeric_digits print", LOGLEVEL_PRINT);
+ os << digits;
}
std::ostream& operator<<(std::ostream& os, const _numeric_digits & e)
{
- e.print(os);
- return os;
+ e.print(os);
+ return os;
}
//////////
#include "ex.h"
class cl_N; // We want to include cln.h only in numeric.cpp in order to
- // avoid namespace pollution and keep compile-time low.
+ // avoid namespace pollution and keep compile-time low.
#ifndef NO_NAMESPACE_GINAC
namespace GiNaC {
{
// member functions
public:
- _numeric_digits();
- _numeric_digits& operator=(long prec);
- operator long();
- void print(std::ostream & os) const;
+ _numeric_digits();
+ _numeric_digits& operator=(long prec);
+ operator long();
+ void print(std::ostream & os) const;
// member variables
private:
- long digits;
- static bool too_late;
+ long digits;
+ static bool too_late;
};
/** This class is a wrapper around CLN-numbers within the GiNaC class
* hierarchy. Objects of this type may directly be created by the user.*/
class numeric : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(numeric, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(numeric, basic)
// friends
- friend const numeric exp(const numeric & x);
- friend const numeric log(const numeric & x);
- friend const numeric sin(const numeric & x);
- friend const numeric cos(const numeric & x);
- friend const numeric tan(const numeric & x);
- friend const numeric asin(const numeric & x);
- friend const numeric acos(const numeric & x);
- friend const numeric atan(const numeric & x);
- friend const numeric atan(const numeric & y, const numeric & x);
- friend const numeric sinh(const numeric & x);
- friend const numeric cosh(const numeric & x);
- friend const numeric tanh(const numeric & x);
- friend const numeric asinh(const numeric & x);
- friend const numeric acosh(const numeric & x);
- friend const numeric atanh(const numeric & x);
- friend const numeric Li2(const numeric & x);
- friend const numeric zeta(const numeric & x);
- friend const numeric fibonacci(const numeric & n);
- friend numeric abs(const numeric & x);
- friend numeric mod(const numeric & a, const numeric & b);
- friend numeric smod(const numeric & a, const numeric & b);
- friend numeric irem(const numeric & a, const numeric & b);
- friend numeric irem(const numeric & a, const numeric & b, numeric & q);
- friend numeric iquo(const numeric & a, const numeric & b);
- friend numeric iquo(const numeric & a, const numeric & b, numeric & r);
- friend numeric sqrt(const numeric & x);
- friend numeric isqrt(const numeric & x);
- friend numeric gcd(const numeric & a, const numeric & b);
- friend numeric lcm(const numeric & a, const numeric & b);
+ friend const numeric exp(const numeric & x);
+ friend const numeric log(const numeric & x);
+ friend const numeric sin(const numeric & x);
+ friend const numeric cos(const numeric & x);
+ friend const numeric tan(const numeric & x);
+ friend const numeric asin(const numeric & x);
+ friend const numeric acos(const numeric & x);
+ friend const numeric atan(const numeric & x);
+ friend const numeric atan(const numeric & y, const numeric & x);
+ friend const numeric sinh(const numeric & x);
+ friend const numeric cosh(const numeric & x);
+ friend const numeric tanh(const numeric & x);
+ friend const numeric asinh(const numeric & x);
+ friend const numeric acosh(const numeric & x);
+ friend const numeric atanh(const numeric & x);
+ friend const numeric Li2(const numeric & x);
+ friend const numeric zeta(const numeric & x);
+ friend const numeric fibonacci(const numeric & n);
+ friend numeric abs(const numeric & x);
+ friend numeric mod(const numeric & a, const numeric & b);
+ friend numeric smod(const numeric & a, const numeric & b);
+ friend numeric irem(const numeric & a, const numeric & b);
+ friend numeric irem(const numeric & a, const numeric & b, numeric & q);
+ friend numeric iquo(const numeric & a, const numeric & b);
+ friend numeric iquo(const numeric & a, const numeric & b, numeric & r);
+ friend numeric sqrt(const numeric & x);
+ friend numeric isqrt(const numeric & x);
+ friend numeric gcd(const numeric & a, const numeric & b);
+ friend numeric lcm(const numeric & a, const numeric & b);
// member functions
- // default constructor, destructor, copy constructor assignment
- // operator and helpers
+ // default constructor, destructor, copy constructor assignment
+ // operator and helpers
public:
- numeric();
- ~numeric();
- numeric(const numeric & other);
- const numeric & operator=(const numeric & other);
+ numeric();
+ ~numeric();
+ numeric(const numeric & other);
+ const numeric & operator=(const numeric & other);
protected:
- void copy(const numeric & other);
- void destroy(bool call_parent);
+ void copy(const numeric & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- explicit numeric(int i);
- explicit numeric(unsigned int i);
- explicit numeric(long i);
- explicit numeric(unsigned long i);
- explicit numeric(long numer, long denom);
- explicit numeric(double d);
- explicit numeric(const char *);
- numeric(const cl_N & z);
-
- // functions overriding virtual functions from bases classes
+ explicit numeric(int i);
+ explicit numeric(unsigned int i);
+ explicit numeric(long i);
+ explicit numeric(unsigned long i);
+ explicit numeric(long numer, long denom);
+ explicit numeric(double d);
+ explicit numeric(const char *);
+ numeric(const cl_N & z);
+
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned precedence=0) const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned precedence=0) const;
- bool info(unsigned inf) const;
- bool has(const ex & other) const;
- ex eval(int level=0) const;
- ex evalf(int level=0) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
- ex to_rational(lst &repl_lst) const;
- numeric integer_content(void) const;
- ex smod(const numeric &xi) const;
- numeric max_coefficient(void) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned precedence=0) const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned precedence=0) const;
+ bool info(unsigned inf) const;
+ bool has(const ex & other) const;
+ ex eval(int level=0) const;
+ ex evalf(int level=0) const;
+ ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+ ex to_rational(lst &repl_lst) const;
+ numeric integer_content(void) const;
+ ex smod(const numeric &xi) const;
+ numeric max_coefficient(void) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned calchash(void) const;
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned calchash(void) const;
- // new virtual functions which can be overridden by derived classes
- // (none)
+ // new virtual functions which can be overridden by derived classes
+ // (none)
- // non-virtual functions in this class
+ // non-virtual functions in this class
public:
- numeric add(const numeric & other) const;
- numeric sub(const numeric & other) const;
- numeric mul(const numeric & other) const;
- numeric div(const numeric & other) const;
- numeric power(const numeric & other) const;
- const numeric & add_dyn(const numeric & other) const;
- const numeric & sub_dyn(const numeric & other) const;
- const numeric & mul_dyn(const numeric & other) const;
- const numeric & div_dyn(const numeric & other) const;
- const numeric & power_dyn(const numeric & other) const;
- const numeric & operator=(int i);
- const numeric & operator=(unsigned int i);
- const numeric & operator=(long i);
- const numeric & operator=(unsigned long i);
- const numeric & operator=(double d);
- const numeric & operator=(const char * s);
- numeric inverse(void) const;
- int csgn(void) const;
- ::cl_N* clnptr(void) const { return value; } /**< ptr to representation. */
- int compare(const numeric & other) const;
- bool is_equal(const numeric & other) const;
- bool is_zero(void) const;
- bool is_positive(void) const;
- bool is_negative(void) const;
- bool is_integer(void) const;
- bool is_pos_integer(void) const;
- bool is_nonneg_integer(void) const;
- bool is_even(void) const;
- bool is_odd(void) const;
- bool is_prime(void) const;
- bool is_rational(void) const;
- bool is_real(void) const;
- bool is_cinteger(void) const;
- bool is_crational(void) const;
- bool operator==(const numeric & other) const;
- bool operator!=(const numeric & other) const;
- bool operator<(const numeric & other) const;
- bool operator<=(const numeric & other) const;
- bool operator>(const numeric & other) const;
- bool operator>=(const numeric & other) const;
- int to_int(void) const;
- long to_long(void) const;
- double to_double(void) const;
- const numeric real(void) const;
- const numeric imag(void) const;
- const numeric numer(void) const;
- const numeric denom(void) const;
- int int_length(void) const;
+ numeric add(const numeric & other) const;
+ numeric sub(const numeric & other) const;
+ numeric mul(const numeric & other) const;
+ numeric div(const numeric & other) const;
+ numeric power(const numeric & other) const;
+ const numeric & add_dyn(const numeric & other) const;
+ const numeric & sub_dyn(const numeric & other) const;
+ const numeric & mul_dyn(const numeric & other) const;
+ const numeric & div_dyn(const numeric & other) const;
+ const numeric & power_dyn(const numeric & other) const;
+ const numeric & operator=(int i);
+ const numeric & operator=(unsigned int i);
+ const numeric & operator=(long i);
+ const numeric & operator=(unsigned long i);
+ const numeric & operator=(double d);
+ const numeric & operator=(const char * s);
+ numeric inverse(void) const;
+ int csgn(void) const;
+ ::cl_N* clnptr(void) const { return value; } /**< ptr to representation. */
+ int compare(const numeric & other) const;
+ bool is_equal(const numeric & other) const;
+ bool is_zero(void) const;
+ bool is_positive(void) const;
+ bool is_negative(void) const;
+ bool is_integer(void) const;
+ bool is_pos_integer(void) const;
+ bool is_nonneg_integer(void) const;
+ bool is_even(void) const;
+ bool is_odd(void) const;
+ bool is_prime(void) const;
+ bool is_rational(void) const;
+ bool is_real(void) const;
+ bool is_cinteger(void) const;
+ bool is_crational(void) const;
+ bool operator==(const numeric & other) const;
+ bool operator!=(const numeric & other) const;
+ bool operator<(const numeric & other) const;
+ bool operator<=(const numeric & other) const;
+ bool operator>(const numeric & other) const;
+ bool operator>=(const numeric & other) const;
+ int to_int(void) const;
+ long to_long(void) const;
+ double to_double(void) const;
+ const numeric real(void) const;
+ const numeric imag(void) const;
+ const numeric numer(void) const;
+ const numeric denom(void) const;
+ int int_length(void) const;
// member variables
protected:
- static unsigned precedence;
- ::cl_N *value;
+ static unsigned precedence;
+ ::cl_N *value;
};
// global constants
// utility functions
inline const numeric &ex_to_numeric(const ex &e)
{
- return static_cast<const numeric &>(*e.bp);
+ return static_cast<const numeric &>(*e.bp);
}
ex operator+(const ex & lh, const ex & rh)
{
- debugmsg("operator+(ex,ex)",LOGLEVEL_OPERATOR);
- return lh.exadd(rh);
+ debugmsg("operator+(ex,ex)",LOGLEVEL_OPERATOR);
+ return lh.exadd(rh);
}
ex operator-(const ex & lh, const ex & rh)
{
- debugmsg("operator-(ex,ex)",LOGLEVEL_OPERATOR);
- return lh.exadd(rh.exmul(_ex_1()));
+ debugmsg("operator-(ex,ex)",LOGLEVEL_OPERATOR);
+ return lh.exadd(rh.exmul(_ex_1()));
}
ex operator*(const ex & lh, const ex & rh)
{
- debugmsg("operator*(ex,ex)",LOGLEVEL_OPERATOR);
- return lh.exmul(rh);
+ debugmsg("operator*(ex,ex)",LOGLEVEL_OPERATOR);
+ return lh.exmul(rh);
}
ex operator/(const ex & lh, const ex & rh)
{
- debugmsg("operator/(ex,ex)",LOGLEVEL_OPERATOR);
- return lh.exmul(power(rh,_ex_1()));
+ debugmsg("operator/(ex,ex)",LOGLEVEL_OPERATOR);
+ return lh.exmul(power(rh,_ex_1()));
}
ex operator%(const ex & lh, const ex & rh)
{
- debugmsg("operator%(ex,ex)",LOGLEVEL_OPERATOR);
- return lh.exncmul(rh);
+ debugmsg("operator%(ex,ex)",LOGLEVEL_OPERATOR);
+ return lh.exncmul(rh);
}
numeric operator+(const numeric & lh, const numeric & rh)
{
- debugmsg("operator+(numeric,numeric)",LOGLEVEL_OPERATOR);
- return lh.add(rh);
+ debugmsg("operator+(numeric,numeric)",LOGLEVEL_OPERATOR);
+ return lh.add(rh);
}
numeric operator-(const numeric & lh, const numeric & rh)
{
- debugmsg("operator-(numeric,numeric)",LOGLEVEL_OPERATOR);
- return lh.sub(rh);
+ debugmsg("operator-(numeric,numeric)",LOGLEVEL_OPERATOR);
+ return lh.sub(rh);
}
numeric operator*(const numeric & lh, const numeric & rh)
{
- debugmsg("operator*(numeric,numeric)",LOGLEVEL_OPERATOR);
- return lh.mul(rh);
+ debugmsg("operator*(numeric,numeric)",LOGLEVEL_OPERATOR);
+ return lh.mul(rh);
}
numeric operator/(const numeric & lh, const numeric & rh)
{
- debugmsg("operator/(numeric,ex)",LOGLEVEL_OPERATOR);
- return lh.div(rh);
+ debugmsg("operator/(numeric,ex)",LOGLEVEL_OPERATOR);
+ return lh.div(rh);
}
const ex & operator+=(ex & lh, const ex & rh)
{
- debugmsg("operator+=(ex,ex)",LOGLEVEL_OPERATOR);
- return (lh=lh+rh);
+ debugmsg("operator+=(ex,ex)",LOGLEVEL_OPERATOR);
+ return (lh=lh+rh);
}
const ex & operator-=(ex & lh, const ex & rh)
{
- debugmsg("operator-=(ex,ex)",LOGLEVEL_OPERATOR);
- return (lh=lh-rh);
+ debugmsg("operator-=(ex,ex)",LOGLEVEL_OPERATOR);
+ return (lh=lh-rh);
}
const ex & operator*=(ex & lh, const ex & rh)
{
- debugmsg("operator*=(ex,ex)",LOGLEVEL_OPERATOR);
- return (lh=lh*rh);
+ debugmsg("operator*=(ex,ex)",LOGLEVEL_OPERATOR);
+ return (lh=lh*rh);
}
const ex & operator/=(ex & lh, const ex & rh)
{
- debugmsg("operator/=(ex,ex)",LOGLEVEL_OPERATOR);
- return (lh=lh/rh);
+ debugmsg("operator/=(ex,ex)",LOGLEVEL_OPERATOR);
+ return (lh=lh/rh);
}
const ex & operator%=(ex & lh, const ex & rh)
{
- debugmsg("operator%=(ex,ex)",LOGLEVEL_OPERATOR);
- return (lh=lh%rh);
+ debugmsg("operator%=(ex,ex)",LOGLEVEL_OPERATOR);
+ return (lh=lh%rh);
}
const numeric & operator+=(numeric & lh, const numeric & rh)
{
- debugmsg("operator+=(numeric,numeric)",LOGLEVEL_OPERATOR);
- return (lh=lh.add(rh));
+ debugmsg("operator+=(numeric,numeric)",LOGLEVEL_OPERATOR);
+ return (lh=lh.add(rh));
}
const numeric & operator-=(numeric & lh, const numeric & rh)
{
- debugmsg("operator-=(numeric,numeric)",LOGLEVEL_OPERATOR);
- return (lh=lh.sub(rh));
+ debugmsg("operator-=(numeric,numeric)",LOGLEVEL_OPERATOR);
+ return (lh=lh.sub(rh));
}
const numeric & operator*=(numeric & lh, const numeric & rh)
{
- debugmsg("operator*=(numeric,numeric)",LOGLEVEL_OPERATOR);
- return (lh=lh.mul(rh));
+ debugmsg("operator*=(numeric,numeric)",LOGLEVEL_OPERATOR);
+ return (lh=lh.mul(rh));
}
const numeric & operator/=(numeric & lh, const numeric & rh)
{
- debugmsg("operator/=(numeric,numeric)",LOGLEVEL_OPERATOR);
- return (lh=lh.div(rh));
+ debugmsg("operator/=(numeric,numeric)",LOGLEVEL_OPERATOR);
+ return (lh=lh.div(rh));
}
// unary operators
ex operator+(const ex & lh)
{
- debugmsg("operator+(ex)",LOGLEVEL_OPERATOR);
- return lh;
+ debugmsg("operator+(ex)",LOGLEVEL_OPERATOR);
+ return lh;
}
ex operator-(const ex & lh)
{
- debugmsg("operator-(ex)",LOGLEVEL_OPERATOR);
- return lh.exmul(_ex_1());
+ debugmsg("operator-(ex)",LOGLEVEL_OPERATOR);
+ return lh.exmul(_ex_1());
}
numeric operator+(const numeric & lh)
{
- debugmsg("operator+(numeric)",LOGLEVEL_OPERATOR);
- return lh;
+ debugmsg("operator+(numeric)",LOGLEVEL_OPERATOR);
+ return lh;
}
numeric operator-(const numeric & lh)
{
- debugmsg("operator-(numeric)",LOGLEVEL_OPERATOR);
- return _num_1()*lh;
+ debugmsg("operator-(numeric)",LOGLEVEL_OPERATOR);
+ return _num_1()*lh;
}
/** Numeric prefix increment. Adds 1 and returns incremented number. */
numeric& operator++(numeric & rh)
{
- debugmsg("operator++(numeric)",LOGLEVEL_OPERATOR);
- rh = rh+_num1();
- return rh;
+ debugmsg("operator++(numeric)",LOGLEVEL_OPERATOR);
+ rh = rh+_num1();
+ return rh;
}
/** Numeric prefix decrement. Subtracts 1 and returns decremented number. */
numeric& operator--(numeric & rh)
{
- debugmsg("operator--(numeric)",LOGLEVEL_OPERATOR);
- rh = rh-_num1();
- return rh;
+ debugmsg("operator--(numeric)",LOGLEVEL_OPERATOR);
+ rh = rh-_num1();
+ return rh;
}
/** Numeric postfix increment. Returns the number and leaves the original
* incremented by 1. */
numeric operator++(numeric & lh, int)
{
- debugmsg("operator++(numeric,int)",LOGLEVEL_OPERATOR);
- numeric tmp = lh;
- lh = lh+_num1();
- return tmp;
+ debugmsg("operator++(numeric,int)",LOGLEVEL_OPERATOR);
+ numeric tmp = lh;
+ lh = lh+_num1();
+ return tmp;
}
/** Numeric Postfix decrement. Returns the number and leaves the original
* decremented by 1. */
numeric operator--(numeric & lh, int)
{
- debugmsg("operator--(numeric,int)",LOGLEVEL_OPERATOR);
- numeric tmp = lh;
- lh = lh-_num1();
- return tmp;
+ debugmsg("operator--(numeric,int)",LOGLEVEL_OPERATOR);
+ numeric tmp = lh;
+ lh = lh-_num1();
+ return tmp;
}
// binary relational operators ex with ex
relational operator==(const ex & lh, const ex & rh)
{
- debugmsg("operator==(ex,ex)",LOGLEVEL_OPERATOR);
- return relational(lh,rh,relational::equal);
+ debugmsg("operator==(ex,ex)",LOGLEVEL_OPERATOR);
+ return relational(lh,rh,relational::equal);
}
relational operator!=(const ex & lh, const ex & rh)
{
- debugmsg("operator!=(ex,ex)",LOGLEVEL_OPERATOR);
- return relational(lh,rh,relational::not_equal);
+ debugmsg("operator!=(ex,ex)",LOGLEVEL_OPERATOR);
+ return relational(lh,rh,relational::not_equal);
}
relational operator<(const ex & lh, const ex & rh)
{
- debugmsg("operator<(ex,ex)",LOGLEVEL_OPERATOR);
- return relational(lh,rh,relational::less);
+ debugmsg("operator<(ex,ex)",LOGLEVEL_OPERATOR);
+ return relational(lh,rh,relational::less);
}
relational operator<=(const ex & lh, const ex & rh)
{
- debugmsg("operator<=(ex,ex)",LOGLEVEL_OPERATOR);
- return relational(lh,rh,relational::less_or_equal);
+ debugmsg("operator<=(ex,ex)",LOGLEVEL_OPERATOR);
+ return relational(lh,rh,relational::less_or_equal);
}
relational operator>(const ex & lh, const ex & rh)
{
- debugmsg("operator>(ex,ex)",LOGLEVEL_OPERATOR);
- return relational(lh,rh,relational::greater);
+ debugmsg("operator>(ex,ex)",LOGLEVEL_OPERATOR);
+ return relational(lh,rh,relational::greater);
}
relational operator>=(const ex & lh, const ex & rh)
{
- debugmsg("operator>=(ex,ex)",LOGLEVEL_OPERATOR);
- return relational(lh,rh,relational::greater_or_equal);
+ debugmsg("operator>=(ex,ex)",LOGLEVEL_OPERATOR);
+ return relational(lh,rh,relational::greater_or_equal);
}
// input/output stream operators
std::ostream & operator<<(std::ostream & os, const ex & e)
{
- e.print(os);
- return os;
+ e.print(os);
+ return os;
}
std::istream & operator>>(std::istream & is, ex & e)
{
- throw (std::logic_error("expression input from streams not implemented"));
+ throw (std::logic_error("expression input from streams not implemented"));
}
#ifndef NO_NAMESPACE_GINAC
power::power() : basic(TINFO_power)
{
- debugmsg("power default constructor",LOGLEVEL_CONSTRUCT);
+ debugmsg("power default constructor",LOGLEVEL_CONSTRUCT);
}
power::~power()
{
- debugmsg("power destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("power destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
power::power(const power & other)
{
- debugmsg("power copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("power copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const power & power::operator=(const power & other)
{
- debugmsg("power operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("power operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void power::copy(const power & other)
{
- inherited::copy(other);
- basis=other.basis;
- exponent=other.exponent;
+ inherited::copy(other);
+ basis=other.basis;
+ exponent=other.exponent;
}
void power::destroy(bool call_parent)
{
- if (call_parent) inherited::destroy(call_parent);
+ if (call_parent) inherited::destroy(call_parent);
}
//////////
power::power(const ex & lh, const ex & rh) : basic(TINFO_power), basis(lh), exponent(rh)
{
- debugmsg("power constructor from ex,ex",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(basis.return_type()==return_types::commutative);
+ debugmsg("power constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(basis.return_type()==return_types::commutative);
}
power::power(const ex & lh, const numeric & rh) : basic(TINFO_power), basis(lh), exponent(rh)
{
- debugmsg("power constructor from ex,numeric",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(basis.return_type()==return_types::commutative);
+ debugmsg("power constructor from ex,numeric",LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(basis.return_type()==return_types::commutative);
}
//////////
/** Construct object from archive_node. */
power::power(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("power constructor from archive_node", LOGLEVEL_CONSTRUCT);
- n.find_ex("basis", basis, sym_lst);
- n.find_ex("exponent", exponent, sym_lst);
+ debugmsg("power constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ n.find_ex("basis", basis, sym_lst);
+ n.find_ex("exponent", exponent, sym_lst);
}
/** Unarchive the object. */
ex power::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new power(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new power(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void power::archive(archive_node &n) const
{
- inherited::archive(n);
- n.add_ex("basis", basis);
- n.add_ex("exponent", exponent);
+ inherited::archive(n);
+ n.add_ex("basis", basis);
+ n.add_ex("exponent", exponent);
}
//////////
basic * power::duplicate() const
{
- debugmsg("power duplicate",LOGLEVEL_DUPLICATE);
- return new power(*this);
+ debugmsg("power duplicate",LOGLEVEL_DUPLICATE);
+ return new power(*this);
}
void power::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("power print",LOGLEVEL_PRINT);
- if (exponent.is_equal(_ex1_2())) {
- os << "sqrt(" << basis << ")";
- } else {
- if (precedence<=upper_precedence) os << "(";
- basis.print(os,precedence);
- os << "^";
- exponent.print(os,precedence);
- if (precedence<=upper_precedence) os << ")";
- }
+ debugmsg("power print",LOGLEVEL_PRINT);
+ if (exponent.is_equal(_ex1_2())) {
+ os << "sqrt(" << basis << ")";
+ } else {
+ if (precedence<=upper_precedence) os << "(";
+ basis.print(os,precedence);
+ os << "^";
+ exponent.print(os,precedence);
+ if (precedence<=upper_precedence) os << ")";
+ }
}
void power::printraw(std::ostream & os) const
{
- debugmsg("power printraw",LOGLEVEL_PRINT);
+ debugmsg("power printraw",LOGLEVEL_PRINT);
- os << "power(";
- basis.printraw(os);
- os << ",";
- exponent.printraw(os);
- os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+ os << "power(";
+ basis.printraw(os);
+ os << ",";
+ exponent.printraw(os);
+ os << ",hash=" << hashvalue << ",flags=" << flags << ")";
}
void power::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("power printtree",LOGLEVEL_PRINT);
+ debugmsg("power printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "power: "
- << "hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
- basis.printtree(os, indent+delta_indent);
- exponent.printtree(os, indent+delta_indent);
+ os << std::string(indent,' ') << "power: "
+ << "hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
+ basis.printtree(os, indent+delta_indent);
+ exponent.printtree(os, indent+delta_indent);
}
static void print_sym_pow(std::ostream & os, unsigned type, const symbol &x, int exp)
{
- // Optimal output of integer powers of symbols to aid compiler CSE
- if (exp == 1) {
- x.printcsrc(os, type, 0);
- } else if (exp == 2) {
- x.printcsrc(os, type, 0);
- os << "*";
- x.printcsrc(os, type, 0);
- } else if (exp & 1) {
- x.printcsrc(os, 0);
- os << "*";
- print_sym_pow(os, type, x, exp-1);
- } else {
- os << "(";
- print_sym_pow(os, type, x, exp >> 1);
- os << ")*(";
- print_sym_pow(os, type, x, exp >> 1);
- os << ")";
- }
+ // Optimal output of integer powers of symbols to aid compiler CSE
+ if (exp == 1) {
+ x.printcsrc(os, type, 0);
+ } else if (exp == 2) {
+ x.printcsrc(os, type, 0);
+ os << "*";
+ x.printcsrc(os, type, 0);
+ } else if (exp & 1) {
+ x.printcsrc(os, 0);
+ os << "*";
+ print_sym_pow(os, type, x, exp-1);
+ } else {
+ os << "(";
+ print_sym_pow(os, type, x, exp >> 1);
+ os << ")*(";
+ print_sym_pow(os, type, x, exp >> 1);
+ os << ")";
+ }
}
void power::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("power print csrc", LOGLEVEL_PRINT);
-
- // Integer powers of symbols are printed in a special, optimized way
- if (exponent.info(info_flags::integer) &&
- (is_ex_exactly_of_type(basis, symbol) ||
- is_ex_exactly_of_type(basis, constant))) {
- int exp = ex_to_numeric(exponent).to_int();
- if (exp > 0)
- os << "(";
- else {
- exp = -exp;
- if (type == csrc_types::ctype_cl_N)
- os << "recip(";
- else
- os << "1.0/(";
- }
- print_sym_pow(os, type, static_cast<const symbol &>(*basis.bp), exp);
- os << ")";
-
- // <expr>^-1 is printed as "1.0/<expr>" or with the recip() function of CLN
- } else if (exponent.compare(_num_1()) == 0) {
- if (type == csrc_types::ctype_cl_N)
- os << "recip(";
- else
- os << "1.0/(";
- basis.bp->printcsrc(os, type, 0);
- os << ")";
-
- // Otherwise, use the pow() or expt() (CLN) functions
- } else {
- if (type == csrc_types::ctype_cl_N)
- os << "expt(";
- else
- os << "pow(";
- basis.bp->printcsrc(os, type, 0);
- os << ",";
- exponent.bp->printcsrc(os, type, 0);
- os << ")";
- }
+ debugmsg("power print csrc", LOGLEVEL_PRINT);
+
+ // Integer powers of symbols are printed in a special, optimized way
+ if (exponent.info(info_flags::integer) &&
+ (is_ex_exactly_of_type(basis, symbol) ||
+ is_ex_exactly_of_type(basis, constant))) {
+ int exp = ex_to_numeric(exponent).to_int();
+ if (exp > 0)
+ os << "(";
+ else {
+ exp = -exp;
+ if (type == csrc_types::ctype_cl_N)
+ os << "recip(";
+ else
+ os << "1.0/(";
+ }
+ print_sym_pow(os, type, static_cast<const symbol &>(*basis.bp), exp);
+ os << ")";
+
+ // <expr>^-1 is printed as "1.0/<expr>" or with the recip() function of CLN
+ } else if (exponent.compare(_num_1()) == 0) {
+ if (type == csrc_types::ctype_cl_N)
+ os << "recip(";
+ else
+ os << "1.0/(";
+ basis.bp->printcsrc(os, type, 0);
+ os << ")";
+
+ // Otherwise, use the pow() or expt() (CLN) functions
+ } else {
+ if (type == csrc_types::ctype_cl_N)
+ os << "expt(";
+ else
+ os << "pow(";
+ basis.bp->printcsrc(os, type, 0);
+ os << ",";
+ exponent.bp->printcsrc(os, type, 0);
+ os << ")";
+ }
}
bool power::info(unsigned inf) const
{
- switch (inf) {
- case info_flags::polynomial:
- case info_flags::integer_polynomial:
- case info_flags::cinteger_polynomial:
- case info_flags::rational_polynomial:
- case info_flags::crational_polynomial:
- return exponent.info(info_flags::nonnegint);
- case info_flags::rational_function:
- return exponent.info(info_flags::integer);
- case info_flags::algebraic:
- return (!exponent.info(info_flags::integer) ||
- basis.info(inf));
- }
- return inherited::info(inf);
+ switch (inf) {
+ case info_flags::polynomial:
+ case info_flags::integer_polynomial:
+ case info_flags::cinteger_polynomial:
+ case info_flags::rational_polynomial:
+ case info_flags::crational_polynomial:
+ return exponent.info(info_flags::nonnegint);
+ case info_flags::rational_function:
+ return exponent.info(info_flags::integer);
+ case info_flags::algebraic:
+ return (!exponent.info(info_flags::integer) ||
+ basis.info(inf));
+ }
+ return inherited::info(inf);
}
unsigned power::nops() const
{
- return 2;
+ return 2;
}
ex & power::let_op(int i)
{
- GINAC_ASSERT(i>=0);
- GINAC_ASSERT(i<2);
+ GINAC_ASSERT(i>=0);
+ GINAC_ASSERT(i<2);
- return i==0 ? basis : exponent;
+ return i==0 ? basis : exponent;
}
int power::degree(const symbol & s) const
{
- if (is_exactly_of_type(*exponent.bp,numeric)) {
- if ((*basis.bp).compare(s)==0)
- return ex_to_numeric(exponent).to_int();
- else
- return basis.degree(s) * ex_to_numeric(exponent).to_int();
- }
- return 0;
+ if (is_exactly_of_type(*exponent.bp,numeric)) {
+ if ((*basis.bp).compare(s)==0)
+ return ex_to_numeric(exponent).to_int();
+ else
+ return basis.degree(s) * ex_to_numeric(exponent).to_int();
+ }
+ return 0;
}
int power::ldegree(const symbol & s) const
{
- if (is_exactly_of_type(*exponent.bp,numeric)) {
- if ((*basis.bp).compare(s)==0)
- return ex_to_numeric(exponent).to_int();
- else
- return basis.ldegree(s) * ex_to_numeric(exponent).to_int();
- }
- return 0;
+ if (is_exactly_of_type(*exponent.bp,numeric)) {
+ if ((*basis.bp).compare(s)==0)
+ return ex_to_numeric(exponent).to_int();
+ else
+ return basis.ldegree(s) * ex_to_numeric(exponent).to_int();
+ }
+ return 0;
}
ex power::coeff(const symbol & s, int n) const
{
- if ((*basis.bp).compare(s)!=0) {
- // basis not equal to s
- if (n==0) {
- return *this;
- } else {
- return _ex0();
- }
- } else if (is_exactly_of_type(*exponent.bp,numeric)&&
- (static_cast<const numeric &>(*exponent.bp).compare(numeric(n))==0)) {
- return _ex1();
- }
+ if ((*basis.bp).compare(s)!=0) {
+ // basis not equal to s
+ if (n==0) {
+ return *this;
+ } else {
+ return _ex0();
+ }
+ } else if (is_exactly_of_type(*exponent.bp,numeric)&&
+ (static_cast<const numeric &>(*exponent.bp).compare(numeric(n))==0)) {
+ return _ex1();
+ }
- return _ex0();
+ return _ex0();
}
ex power::eval(int level) const
{
- // simplifications: ^(x,0) -> 1 (0^0 handled here)
- // ^(x,1) -> x
- // ^(0,c1) -> 0 or exception (depending on real value of c1)
- // ^(1,x) -> 1
- // ^(c1,c2) -> *(c1^n,c1^(c2-n)) (c1, c2 numeric(), 0<(c2-n)<1 except if c1,c2 are rational, but c1^c2 is not)
- // ^(^(x,c1),c2) -> ^(x,c1*c2) (c1, c2 numeric(), c2 integer or -1 < c1 <= 1, case c1=1 should not happen, see below!)
- // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
- // ^(*(x,c1),c2) -> ^(x,c2)*c1^c2 (c1, c2 numeric(), c1>0)
- // ^(*(x,c1),c2) -> ^(-x,c2)*c1^c2 (c1, c2 numeric(), c1<0)
-
- debugmsg("power eval",LOGLEVEL_MEMBER_FUNCTION);
-
- if ((level==1) && (flags & status_flags::evaluated))
- return *this;
- else if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
-
- const ex & ebasis = level==1 ? basis : basis.eval(level-1);
- const ex & eexponent = level==1 ? exponent : exponent.eval(level-1);
-
- bool basis_is_numerical = 0;
- bool exponent_is_numerical = 0;
- numeric * num_basis;
- numeric * num_exponent;
-
- if (is_exactly_of_type(*ebasis.bp,numeric)) {
- basis_is_numerical = 1;
- num_basis = static_cast<numeric *>(ebasis.bp);
- }
- if (is_exactly_of_type(*eexponent.bp,numeric)) {
- exponent_is_numerical = 1;
- num_exponent = static_cast<numeric *>(eexponent.bp);
- }
-
- // ^(x,0) -> 1 (0^0 also handled here)
- if (eexponent.is_zero())
- if (ebasis.is_zero())
- throw (std::domain_error("power::eval(): pow(0,0) is undefined"));
- else
- return _ex1();
-
- // ^(x,1) -> x
- if (eexponent.is_equal(_ex1()))
- return ebasis;
-
- // ^(0,c1) -> 0 or exception (depending on real value of c1)
- if (ebasis.is_zero() && exponent_is_numerical) {
- if ((num_exponent->real()).is_zero())
- throw (std::domain_error("power::eval(): pow(0,I) is undefined"));
- else if ((num_exponent->real()).is_negative())
- throw (pole_error("power::eval(): division by zero",1));
- else
- return _ex0();
- }
-
- // ^(1,x) -> 1
- if (ebasis.is_equal(_ex1()))
- return _ex1();
-
- if (basis_is_numerical && exponent_is_numerical) {
- // ^(c1,c2) -> c1^c2 (c1, c2 numeric(),
- // except if c1,c2 are rational, but c1^c2 is not)
- bool basis_is_crational = num_basis->is_crational();
- bool exponent_is_crational = num_exponent->is_crational();
- numeric res = (*num_basis).power(*num_exponent);
-
- if ((!basis_is_crational || !exponent_is_crational)
- || res.is_crational()) {
- return res;
- }
- GINAC_ASSERT(!num_exponent->is_integer()); // has been handled by now
- // ^(c1,n/m) -> *(c1^q,c1^(n/m-q)), 0<(n/m-h)<1, q integer
- if (basis_is_crational && exponent_is_crational
- && num_exponent->is_real()
- && !num_exponent->is_integer()) {
- numeric n = num_exponent->numer();
- numeric m = num_exponent->denom();
- numeric r;
- numeric q = iquo(n, m, r);
- if (r.is_negative()) {
- r = r.add(m);
- q = q.sub(_num1());
- }
- if (q.is_zero()) // the exponent was in the allowed range 0<(n/m)<1
- return this->hold();
- else {
- epvector res;
- res.push_back(expair(ebasis,r.div(m)));
- return (new mul(res,ex(num_basis->power(q))))->setflag(status_flags::dynallocated | status_flags::evaluated);
- }
- }
- }
-
- // ^(^(x,c1),c2) -> ^(x,c1*c2)
- // (c1, c2 numeric(), c2 integer or -1 < c1 <= 1,
- // case c1==1 should not happen, see below!)
- if (exponent_is_numerical && is_ex_exactly_of_type(ebasis,power)) {
- const power & sub_power = ex_to_power(ebasis);
- const ex & sub_basis = sub_power.basis;
- const ex & sub_exponent = sub_power.exponent;
- if (is_ex_exactly_of_type(sub_exponent,numeric)) {
- const numeric & num_sub_exponent = ex_to_numeric(sub_exponent);
- GINAC_ASSERT(num_sub_exponent!=numeric(1));
- if (num_exponent->is_integer() || abs(num_sub_exponent)<1) {
- return power(sub_basis,num_sub_exponent.mul(*num_exponent));
- }
- }
- }
-
- // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
- if (exponent_is_numerical && num_exponent->is_integer() &&
- is_ex_exactly_of_type(ebasis,mul)) {
- return expand_mul(ex_to_mul(ebasis), *num_exponent);
- }
-
- // ^(*(...,x;c1),c2) -> ^(*(...,x;1),c2)*c1^c2 (c1, c2 numeric(), c1>0)
- // ^(*(...,x,c1),c2) -> ^(*(...,x;-1),c2)*(-c1)^c2 (c1, c2 numeric(), c1<0)
- if (exponent_is_numerical && is_ex_exactly_of_type(ebasis,mul)) {
- GINAC_ASSERT(!num_exponent->is_integer()); // should have been handled above
- const mul & mulref=ex_to_mul(ebasis);
- if (!mulref.overall_coeff.is_equal(_ex1())) {
- const numeric & num_coeff=ex_to_numeric(mulref.overall_coeff);
- if (num_coeff.is_real()) {
- if (num_coeff.is_positive()>0) {
- mul * mulp=new mul(mulref);
- mulp->overall_coeff=_ex1();
- mulp->clearflag(status_flags::evaluated);
- mulp->clearflag(status_flags::hash_calculated);
- return (new mul(power(*mulp,exponent),
- power(num_coeff,*num_exponent)))->
- setflag(status_flags::dynallocated);
- } else {
- GINAC_ASSERT(num_coeff.compare(_num0())<0);
- if (num_coeff.compare(_num_1())!=0) {
- mul * mulp=new mul(mulref);
- mulp->overall_coeff=_ex_1();
- mulp->clearflag(status_flags::evaluated);
- mulp->clearflag(status_flags::hash_calculated);
- return (new mul(power(*mulp,exponent),
- power(abs(num_coeff),*num_exponent)))->
- setflag(status_flags::dynallocated);
- }
- }
- }
- }
- }
-
- if (are_ex_trivially_equal(ebasis,basis) &&
- are_ex_trivially_equal(eexponent,exponent)) {
- return this->hold();
- }
- return (new power(ebasis, eexponent))->setflag(status_flags::dynallocated |
- status_flags::evaluated);
+ // simplifications: ^(x,0) -> 1 (0^0 handled here)
+ // ^(x,1) -> x
+ // ^(0,c1) -> 0 or exception (depending on real value of c1)
+ // ^(1,x) -> 1
+ // ^(c1,c2) -> *(c1^n,c1^(c2-n)) (c1, c2 numeric(), 0<(c2-n)<1 except if c1,c2 are rational, but c1^c2 is not)
+ // ^(^(x,c1),c2) -> ^(x,c1*c2) (c1, c2 numeric(), c2 integer or -1 < c1 <= 1, case c1=1 should not happen, see below!)
+ // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
+ // ^(*(x,c1),c2) -> ^(x,c2)*c1^c2 (c1, c2 numeric(), c1>0)
+ // ^(*(x,c1),c2) -> ^(-x,c2)*c1^c2 (c1, c2 numeric(), c1<0)
+
+ debugmsg("power eval",LOGLEVEL_MEMBER_FUNCTION);
+
+ if ((level==1) && (flags & status_flags::evaluated))
+ return *this;
+ else if (level == -max_recursion_level)
+ throw(std::runtime_error("max recursion level reached"));
+
+ const ex & ebasis = level==1 ? basis : basis.eval(level-1);
+ const ex & eexponent = level==1 ? exponent : exponent.eval(level-1);
+
+ bool basis_is_numerical = 0;
+ bool exponent_is_numerical = 0;
+ numeric * num_basis;
+ numeric * num_exponent;
+
+ if (is_exactly_of_type(*ebasis.bp,numeric)) {
+ basis_is_numerical = 1;
+ num_basis = static_cast<numeric *>(ebasis.bp);
+ }
+ if (is_exactly_of_type(*eexponent.bp,numeric)) {
+ exponent_is_numerical = 1;
+ num_exponent = static_cast<numeric *>(eexponent.bp);
+ }
+
+ // ^(x,0) -> 1 (0^0 also handled here)
+ if (eexponent.is_zero())
+ if (ebasis.is_zero())
+ throw (std::domain_error("power::eval(): pow(0,0) is undefined"));
+ else
+ return _ex1();
+
+ // ^(x,1) -> x
+ if (eexponent.is_equal(_ex1()))
+ return ebasis;
+
+ // ^(0,c1) -> 0 or exception (depending on real value of c1)
+ if (ebasis.is_zero() && exponent_is_numerical) {
+ if ((num_exponent->real()).is_zero())
+ throw (std::domain_error("power::eval(): pow(0,I) is undefined"));
+ else if ((num_exponent->real()).is_negative())
+ throw (pole_error("power::eval(): division by zero",1));
+ else
+ return _ex0();
+ }
+
+ // ^(1,x) -> 1
+ if (ebasis.is_equal(_ex1()))
+ return _ex1();
+
+ if (basis_is_numerical && exponent_is_numerical) {
+ // ^(c1,c2) -> c1^c2 (c1, c2 numeric(),
+ // except if c1,c2 are rational, but c1^c2 is not)
+ bool basis_is_crational = num_basis->is_crational();
+ bool exponent_is_crational = num_exponent->is_crational();
+ numeric res = (*num_basis).power(*num_exponent);
+
+ if ((!basis_is_crational || !exponent_is_crational)
+ || res.is_crational()) {
+ return res;
+ }
+ GINAC_ASSERT(!num_exponent->is_integer()); // has been handled by now
+ // ^(c1,n/m) -> *(c1^q,c1^(n/m-q)), 0<(n/m-h)<1, q integer
+ if (basis_is_crational && exponent_is_crational
+ && num_exponent->is_real()
+ && !num_exponent->is_integer()) {
+ numeric n = num_exponent->numer();
+ numeric m = num_exponent->denom();
+ numeric r;
+ numeric q = iquo(n, m, r);
+ if (r.is_negative()) {
+ r = r.add(m);
+ q = q.sub(_num1());
+ }
+ if (q.is_zero()) // the exponent was in the allowed range 0<(n/m)<1
+ return this->hold();
+ else {
+ epvector res;
+ res.push_back(expair(ebasis,r.div(m)));
+ return (new mul(res,ex(num_basis->power(q))))->setflag(status_flags::dynallocated | status_flags::evaluated);
+ }
+ }
+ }
+
+ // ^(^(x,c1),c2) -> ^(x,c1*c2)
+ // (c1, c2 numeric(), c2 integer or -1 < c1 <= 1,
+ // case c1==1 should not happen, see below!)
+ if (exponent_is_numerical && is_ex_exactly_of_type(ebasis,power)) {
+ const power & sub_power = ex_to_power(ebasis);
+ const ex & sub_basis = sub_power.basis;
+ const ex & sub_exponent = sub_power.exponent;
+ if (is_ex_exactly_of_type(sub_exponent,numeric)) {
+ const numeric & num_sub_exponent = ex_to_numeric(sub_exponent);
+ GINAC_ASSERT(num_sub_exponent!=numeric(1));
+ if (num_exponent->is_integer() || abs(num_sub_exponent)<1) {
+ return power(sub_basis,num_sub_exponent.mul(*num_exponent));
+ }
+ }
+ }
+
+ // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
+ if (exponent_is_numerical && num_exponent->is_integer() &&
+ is_ex_exactly_of_type(ebasis,mul)) {
+ return expand_mul(ex_to_mul(ebasis), *num_exponent);
+ }
+
+ // ^(*(...,x;c1),c2) -> ^(*(...,x;1),c2)*c1^c2 (c1, c2 numeric(), c1>0)
+ // ^(*(...,x,c1),c2) -> ^(*(...,x;-1),c2)*(-c1)^c2 (c1, c2 numeric(), c1<0)
+ if (exponent_is_numerical && is_ex_exactly_of_type(ebasis,mul)) {
+ GINAC_ASSERT(!num_exponent->is_integer()); // should have been handled above
+ const mul & mulref=ex_to_mul(ebasis);
+ if (!mulref.overall_coeff.is_equal(_ex1())) {
+ const numeric & num_coeff=ex_to_numeric(mulref.overall_coeff);
+ if (num_coeff.is_real()) {
+ if (num_coeff.is_positive()>0) {
+ mul * mulp=new mul(mulref);
+ mulp->overall_coeff=_ex1();
+ mulp->clearflag(status_flags::evaluated);
+ mulp->clearflag(status_flags::hash_calculated);
+ return (new mul(power(*mulp,exponent),
+ power(num_coeff,*num_exponent)))->
+ setflag(status_flags::dynallocated);
+ } else {
+ GINAC_ASSERT(num_coeff.compare(_num0())<0);
+ if (num_coeff.compare(_num_1())!=0) {
+ mul * mulp=new mul(mulref);
+ mulp->overall_coeff=_ex_1();
+ mulp->clearflag(status_flags::evaluated);
+ mulp->clearflag(status_flags::hash_calculated);
+ return (new mul(power(*mulp,exponent),
+ power(abs(num_coeff),*num_exponent)))->
+ setflag(status_flags::dynallocated);
+ }
+ }
+ }
+ }
+ }
+
+ if (are_ex_trivially_equal(ebasis,basis) &&
+ are_ex_trivially_equal(eexponent,exponent)) {
+ return this->hold();
+ }
+ return (new power(ebasis, eexponent))->setflag(status_flags::dynallocated |
+ status_flags::evaluated);
}
ex power::evalf(int level) const
{
- debugmsg("power evalf",LOGLEVEL_MEMBER_FUNCTION);
+ debugmsg("power evalf",LOGLEVEL_MEMBER_FUNCTION);
- ex ebasis;
- ex eexponent;
-
- if (level==1) {
- ebasis = basis;
- eexponent = exponent;
- } else if (level == -max_recursion_level) {
- throw(std::runtime_error("max recursion level reached"));
- } else {
- ebasis = basis.evalf(level-1);
- if (!is_ex_exactly_of_type(eexponent,numeric))
- eexponent = exponent.evalf(level-1);
- else
- eexponent = exponent;
- }
+ ex ebasis;
+ ex eexponent;
+
+ if (level==1) {
+ ebasis = basis;
+ eexponent = exponent;
+ } else if (level == -max_recursion_level) {
+ throw(std::runtime_error("max recursion level reached"));
+ } else {
+ ebasis = basis.evalf(level-1);
+ if (!is_ex_exactly_of_type(eexponent,numeric))
+ eexponent = exponent.evalf(level-1);
+ else
+ eexponent = exponent;
+ }
- return power(ebasis,eexponent);
+ return power(ebasis,eexponent);
}
ex power::subs(const lst & ls, const lst & lr) const
{
- const ex & subsed_basis=basis.subs(ls,lr);
- const ex & subsed_exponent=exponent.subs(ls,lr);
+ const ex & subsed_basis=basis.subs(ls,lr);
+ const ex & subsed_exponent=exponent.subs(ls,lr);
- if (are_ex_trivially_equal(basis,subsed_basis)&&
- are_ex_trivially_equal(exponent,subsed_exponent)) {
- return *this;
- }
-
- return power(subsed_basis, subsed_exponent);
+ if (are_ex_trivially_equal(basis,subsed_basis)&&
+ are_ex_trivially_equal(exponent,subsed_exponent)) {
+ return *this;
+ }
+
+ return power(subsed_basis, subsed_exponent);
}
ex power::simplify_ncmul(const exvector & v) const
{
- return inherited::simplify_ncmul(v);
+ return inherited::simplify_ncmul(v);
}
// protected
* @see ex::diff */
ex power::derivative(const symbol & s) const
{
- if (exponent.info(info_flags::real)) {
- // D(b^r) = r * b^(r-1) * D(b) (faster than the formula below)
- epvector newseq;
- newseq.reserve(2);
- newseq.push_back(expair(basis, exponent - _ex1()));
- newseq.push_back(expair(basis.diff(s), _ex1()));
- return mul(newseq, exponent);
- } else {
- // D(b^e) = b^e * (D(e)*ln(b) + e*D(b)/b)
- return mul(power(basis, exponent),
- add(mul(exponent.diff(s), log(basis)),
- mul(mul(exponent, basis.diff(s)), power(basis, -1))));
- }
+ if (exponent.info(info_flags::real)) {
+ // D(b^r) = r * b^(r-1) * D(b) (faster than the formula below)
+ epvector newseq;
+ newseq.reserve(2);
+ newseq.push_back(expair(basis, exponent - _ex1()));
+ newseq.push_back(expair(basis.diff(s), _ex1()));
+ return mul(newseq, exponent);
+ } else {
+ // D(b^e) = b^e * (D(e)*ln(b) + e*D(b)/b)
+ return mul(power(basis, exponent),
+ add(mul(exponent.diff(s), log(basis)),
+ mul(mul(exponent, basis.diff(s)), power(basis, -1))));
+ }
}
int power::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_exactly_of_type(other, power));
- const power & o=static_cast<const power &>(const_cast<basic &>(other));
+ GINAC_ASSERT(is_exactly_of_type(other, power));
+ const power & o=static_cast<const power &>(const_cast<basic &>(other));
- int cmpval;
- cmpval=basis.compare(o.basis);
- if (cmpval==0) {
- return exponent.compare(o.exponent);
- }
- return cmpval;
+ int cmpval;
+ cmpval=basis.compare(o.basis);
+ if (cmpval==0) {
+ return exponent.compare(o.exponent);
+ }
+ return cmpval;
}
unsigned power::return_type(void) const
{
- return basis.return_type();
+ return basis.return_type();
}
unsigned power::return_type_tinfo(void) const
{
- return basis.return_type_tinfo();
+ return basis.return_type_tinfo();
}
ex power::expand(unsigned options) const
{
- if (flags & status_flags::expanded)
- return *this;
-
- ex expanded_basis = basis.expand(options);
-
- if (!is_ex_exactly_of_type(exponent,numeric) ||
- !ex_to_numeric(exponent).is_integer()) {
- if (are_ex_trivially_equal(basis,expanded_basis)) {
- return this->hold();
- } else {
- return (new power(expanded_basis,exponent))->
- setflag(status_flags::dynallocated |
- status_flags::expanded);
- }
- }
-
- // integer numeric exponent
- const numeric & num_exponent = ex_to_numeric(exponent);
- int int_exponent = num_exponent.to_int();
-
- if (int_exponent > 0 && is_ex_exactly_of_type(expanded_basis,add)) {
- return expand_add(ex_to_add(expanded_basis), int_exponent);
- }
-
- if (is_ex_exactly_of_type(expanded_basis,mul)) {
- return expand_mul(ex_to_mul(expanded_basis), num_exponent);
- }
-
- // cannot expand further
- if (are_ex_trivially_equal(basis,expanded_basis)) {
- return this->hold();
- } else {
- return (new power(expanded_basis,exponent))->
- setflag(status_flags::dynallocated |
- status_flags::expanded);
- }
+ if (flags & status_flags::expanded)
+ return *this;
+
+ ex expanded_basis = basis.expand(options);
+
+ if (!is_ex_exactly_of_type(exponent,numeric) ||
+ !ex_to_numeric(exponent).is_integer()) {
+ if (are_ex_trivially_equal(basis,expanded_basis)) {
+ return this->hold();
+ } else {
+ return (new power(expanded_basis,exponent))->
+ setflag(status_flags::dynallocated |
+ status_flags::expanded);
+ }
+ }
+
+ // integer numeric exponent
+ const numeric & num_exponent = ex_to_numeric(exponent);
+ int int_exponent = num_exponent.to_int();
+
+ if (int_exponent > 0 && is_ex_exactly_of_type(expanded_basis,add)) {
+ return expand_add(ex_to_add(expanded_basis), int_exponent);
+ }
+
+ if (is_ex_exactly_of_type(expanded_basis,mul)) {
+ return expand_mul(ex_to_mul(expanded_basis), num_exponent);
+ }
+
+ // cannot expand further
+ if (are_ex_trivially_equal(basis,expanded_basis)) {
+ return this->hold();
+ } else {
+ return (new power(expanded_basis,exponent))->
+ setflag(status_flags::dynallocated |
+ status_flags::expanded);
+ }
}
//////////
* @see power::expand */
ex power::expand_add(const add & a, int n) const
{
- if (n==2)
- return expand_add_2(a);
-
- int m = a.nops();
- exvector sum;
- sum.reserve((n+1)*(m-1));
- intvector k(m-1);
- intvector k_cum(m-1); // k_cum[l]:=sum(i=0,l,k[l]);
- intvector upper_limit(m-1);
- int l;
-
- for (int l=0; l<m-1; l++) {
- k[l] = 0;
- k_cum[l] = 0;
- upper_limit[l] = n;
- }
-
- while (1) {
- exvector term;
- term.reserve(m+1);
- for (l=0; l<m-1; l++) {
- const ex & b = a.op(l);
- GINAC_ASSERT(!is_ex_exactly_of_type(b,add));
- GINAC_ASSERT(!is_ex_exactly_of_type(b,power)||
- !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
- !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer()||
- !is_ex_exactly_of_type(ex_to_power(b).basis,add)||
- !is_ex_exactly_of_type(ex_to_power(b).basis,mul)||
- !is_ex_exactly_of_type(ex_to_power(b).basis,power));
- if (is_ex_exactly_of_type(b,mul)) {
- term.push_back(expand_mul(ex_to_mul(b),numeric(k[l])));
- } else {
- term.push_back(power(b,k[l]));
- }
- }
-
- const ex & b = a.op(l);
- GINAC_ASSERT(!is_ex_exactly_of_type(b,add));
- GINAC_ASSERT(!is_ex_exactly_of_type(b,power)||
- !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
- !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer()||
- !is_ex_exactly_of_type(ex_to_power(b).basis,add)||
- !is_ex_exactly_of_type(ex_to_power(b).basis,mul)||
- !is_ex_exactly_of_type(ex_to_power(b).basis,power));
- if (is_ex_exactly_of_type(b,mul)) {
- term.push_back(expand_mul(ex_to_mul(b),numeric(n-k_cum[m-2])));
- } else {
- term.push_back(power(b,n-k_cum[m-2]));
- }
-
- numeric f = binomial(numeric(n),numeric(k[0]));
- for (l=1; l<m-1; l++) {
- f=f*binomial(numeric(n-k_cum[l-1]),numeric(k[l]));
- }
- term.push_back(f);
-
- /*
- cout << "begin term" << endl;
- for (int i=0; i<m-1; i++) {
- cout << "k[" << i << "]=" << k[i] << endl;
- cout << "k_cum[" << i << "]=" << k_cum[i] << endl;
- cout << "upper_limit[" << i << "]=" << upper_limit[i] << endl;
- }
- for (exvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
- cout << *cit << endl;
- }
- cout << "end term" << endl;
- */
-
- // TODO: optimize this
- sum.push_back((new mul(term))->setflag(status_flags::dynallocated));
-
- // increment k[]
- l=m-2;
- while ((l>=0)&&((++k[l])>upper_limit[l])) {
- k[l]=0;
- l--;
- }
- if (l<0) break;
-
- // recalc k_cum[] and upper_limit[]
- if (l==0) {
- k_cum[0]=k[0];
- } else {
- k_cum[l]=k_cum[l-1]+k[l];
- }
- for (int i=l+1; i<m-1; i++) {
- k_cum[i]=k_cum[i-1]+k[i];
- }
-
- for (int i=l+1; i<m-1; i++) {
- upper_limit[i]=n-k_cum[i-1];
- }
- }
- return (new add(sum))->setflag(status_flags::dynallocated |
- status_flags::expanded );
+ if (n==2)
+ return expand_add_2(a);
+
+ int m = a.nops();
+ exvector sum;
+ sum.reserve((n+1)*(m-1));
+ intvector k(m-1);
+ intvector k_cum(m-1); // k_cum[l]:=sum(i=0,l,k[l]);
+ intvector upper_limit(m-1);
+ int l;
+
+ for (int l=0; l<m-1; l++) {
+ k[l] = 0;
+ k_cum[l] = 0;
+ upper_limit[l] = n;
+ }
+
+ while (1) {
+ exvector term;
+ term.reserve(m+1);
+ for (l=0; l<m-1; l++) {
+ const ex & b = a.op(l);
+ GINAC_ASSERT(!is_ex_exactly_of_type(b,add));
+ GINAC_ASSERT(!is_ex_exactly_of_type(b,power)||
+ !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
+ !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer()||
+ !is_ex_exactly_of_type(ex_to_power(b).basis,add)||
+ !is_ex_exactly_of_type(ex_to_power(b).basis,mul)||
+ !is_ex_exactly_of_type(ex_to_power(b).basis,power));
+ if (is_ex_exactly_of_type(b,mul)) {
+ term.push_back(expand_mul(ex_to_mul(b),numeric(k[l])));
+ } else {
+ term.push_back(power(b,k[l]));
+ }
+ }
+
+ const ex & b = a.op(l);
+ GINAC_ASSERT(!is_ex_exactly_of_type(b,add));
+ GINAC_ASSERT(!is_ex_exactly_of_type(b,power)||
+ !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
+ !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer()||
+ !is_ex_exactly_of_type(ex_to_power(b).basis,add)||
+ !is_ex_exactly_of_type(ex_to_power(b).basis,mul)||
+ !is_ex_exactly_of_type(ex_to_power(b).basis,power));
+ if (is_ex_exactly_of_type(b,mul)) {
+ term.push_back(expand_mul(ex_to_mul(b),numeric(n-k_cum[m-2])));
+ } else {
+ term.push_back(power(b,n-k_cum[m-2]));
+ }
+
+ numeric f = binomial(numeric(n),numeric(k[0]));
+ for (l=1; l<m-1; l++) {
+ f=f*binomial(numeric(n-k_cum[l-1]),numeric(k[l]));
+ }
+ term.push_back(f);
+
+ /*
+ cout << "begin term" << endl;
+ for (int i=0; i<m-1; i++) {
+ cout << "k[" << i << "]=" << k[i] << endl;
+ cout << "k_cum[" << i << "]=" << k_cum[i] << endl;
+ cout << "upper_limit[" << i << "]=" << upper_limit[i] << endl;
+ }
+ for (exvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
+ cout << *cit << endl;
+ }
+ cout << "end term" << endl;
+ */
+
+ // TODO: optimize this
+ sum.push_back((new mul(term))->setflag(status_flags::dynallocated));
+
+ // increment k[]
+ l=m-2;
+ while ((l>=0)&&((++k[l])>upper_limit[l])) {
+ k[l]=0;
+ l--;
+ }
+ if (l<0) break;
+
+ // recalc k_cum[] and upper_limit[]
+ if (l==0) {
+ k_cum[0]=k[0];
+ } else {
+ k_cum[l]=k_cum[l-1]+k[l];
+ }
+ for (int i=l+1; i<m-1; i++) {
+ k_cum[i]=k_cum[i-1]+k[i];
+ }
+
+ for (int i=l+1; i<m-1; i++) {
+ upper_limit[i]=n-k_cum[i-1];
+ }
+ }
+ return (new add(sum))->setflag(status_flags::dynallocated |
+ status_flags::expanded );
}
* @see power::expand_add */
ex power::expand_add_2(const add & a) const
{
- epvector sum;
- unsigned a_nops=a.nops();
- sum.reserve((a_nops*(a_nops+1))/2);
- epvector::const_iterator last=a.seq.end();
-
- // power(+(x,...,z;c),2)=power(+(x,...,z;0),2)+2*c*+(x,...,z;0)+c*c
- // first part: ignore overall_coeff and expand other terms
- for (epvector::const_iterator cit0=a.seq.begin(); cit0!=last; ++cit0) {
- const ex & r=(*cit0).rest;
- const ex & c=(*cit0).coeff;
-
- GINAC_ASSERT(!is_ex_exactly_of_type(r,add));
- GINAC_ASSERT(!is_ex_exactly_of_type(r,power)||
- !is_ex_exactly_of_type(ex_to_power(r).exponent,numeric)||
- !ex_to_numeric(ex_to_power(r).exponent).is_pos_integer()||
- !is_ex_exactly_of_type(ex_to_power(r).basis,add)||
- !is_ex_exactly_of_type(ex_to_power(r).basis,mul)||
- !is_ex_exactly_of_type(ex_to_power(r).basis,power));
-
- if (are_ex_trivially_equal(c,_ex1())) {
- if (is_ex_exactly_of_type(r,mul)) {
- sum.push_back(expair(expand_mul(ex_to_mul(r),_num2()),_ex1()));
- } else {
- sum.push_back(expair((new power(r,_ex2()))->setflag(status_flags::dynallocated),
- _ex1()));
- }
- } else {
- if (is_ex_exactly_of_type(r,mul)) {
- sum.push_back(expair(expand_mul(ex_to_mul(r),_num2()),
- ex_to_numeric(c).power_dyn(_num2())));
- } else {
- sum.push_back(expair((new power(r,_ex2()))->setflag(status_flags::dynallocated),
- ex_to_numeric(c).power_dyn(_num2())));
- }
- }
-
- for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) {
- const ex & r1=(*cit1).rest;
- const ex & c1=(*cit1).coeff;
- sum.push_back(a.combine_ex_with_coeff_to_pair((new mul(r,r1))->setflag(status_flags::dynallocated),
- _num2().mul(ex_to_numeric(c)).mul_dyn(ex_to_numeric(c1))));
- }
- }
-
- GINAC_ASSERT(sum.size()==(a.seq.size()*(a.seq.size()+1))/2);
-
- // second part: add terms coming from overall_factor (if != 0)
- if (!a.overall_coeff.is_equal(_ex0())) {
- for (epvector::const_iterator cit=a.seq.begin(); cit!=a.seq.end(); ++cit) {
- sum.push_back(a.combine_pair_with_coeff_to_pair(*cit,ex_to_numeric(a.overall_coeff).mul_dyn(_num2())));
- }
- sum.push_back(expair(ex_to_numeric(a.overall_coeff).power_dyn(_num2()),_ex1()));
- }
-
- GINAC_ASSERT(sum.size()==(a_nops*(a_nops+1))/2);
-
- return (new add(sum))->setflag(status_flags::dynallocated |
- status_flags::expanded );
+ epvector sum;
+ unsigned a_nops=a.nops();
+ sum.reserve((a_nops*(a_nops+1))/2);
+ epvector::const_iterator last=a.seq.end();
+
+ // power(+(x,...,z;c),2)=power(+(x,...,z;0),2)+2*c*+(x,...,z;0)+c*c
+ // first part: ignore overall_coeff and expand other terms
+ for (epvector::const_iterator cit0=a.seq.begin(); cit0!=last; ++cit0) {
+ const ex & r=(*cit0).rest;
+ const ex & c=(*cit0).coeff;
+
+ GINAC_ASSERT(!is_ex_exactly_of_type(r,add));
+ GINAC_ASSERT(!is_ex_exactly_of_type(r,power)||
+ !is_ex_exactly_of_type(ex_to_power(r).exponent,numeric)||
+ !ex_to_numeric(ex_to_power(r).exponent).is_pos_integer()||
+ !is_ex_exactly_of_type(ex_to_power(r).basis,add)||
+ !is_ex_exactly_of_type(ex_to_power(r).basis,mul)||
+ !is_ex_exactly_of_type(ex_to_power(r).basis,power));
+
+ if (are_ex_trivially_equal(c,_ex1())) {
+ if (is_ex_exactly_of_type(r,mul)) {
+ sum.push_back(expair(expand_mul(ex_to_mul(r),_num2()),_ex1()));
+ } else {
+ sum.push_back(expair((new power(r,_ex2()))->setflag(status_flags::dynallocated),
+ _ex1()));
+ }
+ } else {
+ if (is_ex_exactly_of_type(r,mul)) {
+ sum.push_back(expair(expand_mul(ex_to_mul(r),_num2()),
+ ex_to_numeric(c).power_dyn(_num2())));
+ } else {
+ sum.push_back(expair((new power(r,_ex2()))->setflag(status_flags::dynallocated),
+ ex_to_numeric(c).power_dyn(_num2())));
+ }
+ }
+
+ for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) {
+ const ex & r1=(*cit1).rest;
+ const ex & c1=(*cit1).coeff;
+ sum.push_back(a.combine_ex_with_coeff_to_pair((new mul(r,r1))->setflag(status_flags::dynallocated),
+ _num2().mul(ex_to_numeric(c)).mul_dyn(ex_to_numeric(c1))));
+ }
+ }
+
+ GINAC_ASSERT(sum.size()==(a.seq.size()*(a.seq.size()+1))/2);
+
+ // second part: add terms coming from overall_factor (if != 0)
+ if (!a.overall_coeff.is_equal(_ex0())) {
+ for (epvector::const_iterator cit=a.seq.begin(); cit!=a.seq.end(); ++cit) {
+ sum.push_back(a.combine_pair_with_coeff_to_pair(*cit,ex_to_numeric(a.overall_coeff).mul_dyn(_num2())));
+ }
+ sum.push_back(expair(ex_to_numeric(a.overall_coeff).power_dyn(_num2()),_ex1()));
+ }
+
+ GINAC_ASSERT(sum.size()==(a_nops*(a_nops+1))/2);
+
+ return (new add(sum))->setflag(status_flags::dynallocated |
+ status_flags::expanded );
}
/** Expand factors of m in m^n where m is a mul and n is and integer
* @see power::expand */
ex power::expand_mul(const mul & m, const numeric & n) const
{
- if (n.is_equal(_num0()))
- return _ex1();
-
- epvector distrseq;
- distrseq.reserve(m.seq.size());
- epvector::const_iterator last = m.seq.end();
- epvector::const_iterator cit = m.seq.begin();
- while (cit!=last) {
- if (is_ex_exactly_of_type((*cit).rest,numeric)) {
- distrseq.push_back(m.combine_pair_with_coeff_to_pair(*cit,n));
- } else {
- // it is safe not to call mul::combine_pair_with_coeff_to_pair()
- // since n is an integer
- distrseq.push_back(expair((*cit).rest,
- ex_to_numeric((*cit).coeff).mul(n)));
- }
- ++cit;
- }
- return (new mul(distrseq,ex_to_numeric(m.overall_coeff).power_dyn(n)))
- ->setflag(status_flags::dynallocated);
+ if (n.is_equal(_num0()))
+ return _ex1();
+
+ epvector distrseq;
+ distrseq.reserve(m.seq.size());
+ epvector::const_iterator last = m.seq.end();
+ epvector::const_iterator cit = m.seq.begin();
+ while (cit!=last) {
+ if (is_ex_exactly_of_type((*cit).rest,numeric)) {
+ distrseq.push_back(m.combine_pair_with_coeff_to_pair(*cit,n));
+ } else {
+ // it is safe not to call mul::combine_pair_with_coeff_to_pair()
+ // since n is an integer
+ distrseq.push_back(expair((*cit).rest,
+ ex_to_numeric((*cit).coeff).mul(n)));
+ }
+ ++cit;
+ }
+ return (new mul(distrseq,ex_to_numeric(m.overall_coeff).power_dyn(n)))
+ ->setflag(status_flags::dynallocated);
}
/*
ex power::expand_commutative_3(const ex & basis, const numeric & exponent,
- unsigned options) const
+ unsigned options) const
{
- // obsolete
+ // obsolete
- exvector distrseq;
- epvector splitseq;
+ exvector distrseq;
+ epvector splitseq;
- const add & addref=static_cast<const add &>(*basis.bp);
+ const add & addref=static_cast<const add &>(*basis.bp);
- splitseq=addref.seq;
- splitseq.pop_back();
- ex first_operands=add(splitseq);
- ex last_operand=addref.recombine_pair_to_ex(*(addref.seq.end()-1));
-
- int n=exponent.to_int();
- for (int k=0; k<=n; k++) {
- distrseq.push_back(binomial(n,k)*power(first_operands,numeric(k))*
- power(last_operand,numeric(n-k)));
- }
- return ex((new add(distrseq))->setflag(status_flags::expanded |
- status_flags::dynallocated )).
- expand(options);
+ splitseq=addref.seq;
+ splitseq.pop_back();
+ ex first_operands=add(splitseq);
+ ex last_operand=addref.recombine_pair_to_ex(*(addref.seq.end()-1));
+
+ int n=exponent.to_int();
+ for (int k=0; k<=n; k++) {
+ distrseq.push_back(binomial(n,k)*power(first_operands,numeric(k))*
+ power(last_operand,numeric(n-k)));
+ }
+ return ex((new add(distrseq))->setflag(status_flags::expanded |
+ status_flags::dynallocated )).
+ expand(options);
}
*/
/*
ex power::expand_noncommutative(const ex & basis, const numeric & exponent,
- unsigned options) const
+ unsigned options) const
{
- ex rest_power=ex(power(basis,exponent.add(_num_1()))).
- expand(options | expand_options::internal_do_not_expand_power_operands);
+ ex rest_power=ex(power(basis,exponent.add(_num_1()))).
+ expand(options | expand_options::internal_do_not_expand_power_operands);
- return ex(mul(rest_power,basis),0).
- expand(options | expand_options::internal_do_not_expand_mul_operands);
+ return ex(mul(rest_power,basis),0).
+ expand(options | expand_options::internal_do_not_expand_mul_operands);
}
*/
ex sqrt(const ex & a)
{
- return power(a,_ex1_2());
+ return power(a,_ex1_2());
}
#ifndef NO_NAMESPACE_GINAC
* representing exponentiation. */
class power : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(power, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(power, basic)
- friend class mul;
+ friend class mul;
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- power();
- ~power();
- power(const power & other);
- const power & operator=(const power & other);
+ power();
+ ~power();
+ power(const power & other);
+ const power & operator=(const power & other);
protected:
- void copy(const power & other);
- void destroy(bool call_parent);
+ void copy(const power & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- power(const ex & lh, const ex & rh);
- power(const ex & lh, const numeric & rh);
+ power(const ex & lh, const ex & rh);
+ power(const ex & lh, const numeric & rh);
- // functions overriding virtual functions from bases classes
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence = 0) const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence = 0) const;
- bool info(unsigned inf) const;
- unsigned nops() const;
- ex & let_op(int i);
- int degree(const symbol & s) const;
- int ldegree(const symbol & s) const;
- ex coeff(const symbol & s, int n = 1) const;
- ex eval(int level=0) const;
- ex evalf(int level=0) const;
- ex series(const relational & s, int order, unsigned options = 0) const;
- ex subs(const lst & ls, const lst & lr) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
- ex to_rational(lst &repl_lst) const;
- ex simplify_ncmul(const exvector & v) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence = 0) const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence = 0) const;
+ bool info(unsigned inf) const;
+ unsigned nops() const;
+ ex & let_op(int i);
+ int degree(const symbol & s) const;
+ int ldegree(const symbol & s) const;
+ ex coeff(const symbol & s, int n = 1) const;
+ ex eval(int level=0) const;
+ ex evalf(int level=0) const;
+ ex series(const relational & s, int order, unsigned options = 0) const;
+ ex subs(const lst & ls, const lst & lr) const;
+ ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
+ ex to_rational(lst &repl_lst) const;
+ ex simplify_ncmul(const exvector & v) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- ex expand(unsigned options = 0) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+ ex expand(unsigned options = 0) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
protected:
- ex expand_add(const add & a, int n) const;
- ex expand_add_2(const add & a) const;
- ex expand_mul(const mul & m, const numeric & n) const;
- //ex expand_commutative_3(const ex & basis, const numeric & exponent,
- // unsigned options) const;
- // ex expand_noncommutative(const ex & basis, const numeric & exponent, unsigned options) const;
+ ex expand_add(const add & a, int n) const;
+ ex expand_add_2(const add & a) const;
+ ex expand_mul(const mul & m, const numeric & n) const;
+ //ex expand_commutative_3(const ex & basis, const numeric & exponent,
+ // unsigned options) const;
+ // ex expand_noncommutative(const ex & basis, const numeric & exponent, unsigned options) const;
// member variables
protected:
- ex basis;
- ex exponent;
- static unsigned precedence;
+ ex basis;
+ ex exponent;
+ static unsigned precedence;
};
// global constants
pseries::pseries() : basic(TINFO_pseries)
{
- debugmsg("pseries default constructor", LOGLEVEL_CONSTRUCT);
+ debugmsg("pseries default constructor", LOGLEVEL_CONSTRUCT);
}
pseries::~pseries()
{
- debugmsg("pseries destructor", LOGLEVEL_DESTRUCT);
- destroy(false);
+ debugmsg("pseries destructor", LOGLEVEL_DESTRUCT);
+ destroy(false);
}
pseries::pseries(const pseries &other)
{
- debugmsg("pseries copy constructor", LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("pseries copy constructor", LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const pseries &pseries::operator=(const pseries & other)
{
- debugmsg("pseries operator=", LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(true);
- copy(other);
- }
- return *this;
+ debugmsg("pseries operator=", LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(true);
+ copy(other);
+ }
+ return *this;
}
void pseries::copy(const pseries &other)
{
- inherited::copy(other);
- seq = other.seq;
- var = other.var;
- point = other.point;
+ inherited::copy(other);
+ seq = other.seq;
+ var = other.var;
+ point = other.point;
}
void pseries::destroy(bool call_parent)
{
- if (call_parent)
- inherited::destroy(call_parent);
+ if (call_parent)
+ inherited::destroy(call_parent);
}
* @param ops_ vector of {coefficient, power} pairs (coefficient must not be zero)
* @return newly constructed pseries */
pseries::pseries(const ex &rel_, const epvector &ops_)
- : basic(TINFO_pseries), seq(ops_)
+ : basic(TINFO_pseries), seq(ops_)
{
- debugmsg("pseries constructor from ex,epvector", LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(is_ex_exactly_of_type(rel_, relational));
- GINAC_ASSERT(is_ex_exactly_of_type(rel_.lhs(),symbol));
- point = rel_.rhs();
- var = *static_cast<symbol *>(rel_.lhs().bp);
+ debugmsg("pseries constructor from ex,epvector", LOGLEVEL_CONSTRUCT);
+ GINAC_ASSERT(is_ex_exactly_of_type(rel_, relational));
+ GINAC_ASSERT(is_ex_exactly_of_type(rel_.lhs(),symbol));
+ point = rel_.rhs();
+ var = *static_cast<symbol *>(rel_.lhs().bp);
}
/** Construct object from archive_node. */
pseries::pseries(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("pseries constructor from archive_node", LOGLEVEL_CONSTRUCT);
- for (unsigned int i=0; true; ++i) {
- ex rest;
- ex coeff;
- if (n.find_ex("coeff", rest, sym_lst, i) && n.find_ex("power", coeff, sym_lst, i))
- seq.push_back(expair(rest, coeff));
- else
- break;
- }
- n.find_ex("var", var, sym_lst);
- n.find_ex("point", point, sym_lst);
+ debugmsg("pseries constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ for (unsigned int i=0; true; ++i) {
+ ex rest;
+ ex coeff;
+ if (n.find_ex("coeff", rest, sym_lst, i) && n.find_ex("power", coeff, sym_lst, i))
+ seq.push_back(expair(rest, coeff));
+ else
+ break;
+ }
+ n.find_ex("var", var, sym_lst);
+ n.find_ex("point", point, sym_lst);
}
/** Unarchive the object. */
ex pseries::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new pseries(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new pseries(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void pseries::archive(archive_node &n) const
{
- inherited::archive(n);
- epvector::const_iterator i = seq.begin(), iend = seq.end();
- while (i != iend) {
- n.add_ex("coeff", i->rest);
- n.add_ex("power", i->coeff);
- ++i;
- }
- n.add_ex("var", var);
- n.add_ex("point", point);
+ inherited::archive(n);
+ epvector::const_iterator i = seq.begin(), iend = seq.end();
+ while (i != iend) {
+ n.add_ex("coeff", i->rest);
+ n.add_ex("power", i->coeff);
+ ++i;
+ }
+ n.add_ex("var", var);
+ n.add_ex("point", point);
}
//////////
basic *pseries::duplicate() const
{
- debugmsg("pseries duplicate", LOGLEVEL_DUPLICATE);
- return new pseries(*this);
+ debugmsg("pseries duplicate", LOGLEVEL_DUPLICATE);
+ return new pseries(*this);
}
void pseries::print(std::ostream &os, unsigned upper_precedence) const
{
- debugmsg("pseries print", LOGLEVEL_PRINT);
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
- // omit zero terms
- if (i->rest.is_zero())
- continue;
- // print a sign, if needed
- if (i!=seq.begin())
- os << '+';
- if (!is_order_function(i->rest)) {
- // print 'rest', i.e. the expansion coefficient
- if (i->rest.info(info_flags::numeric) &&
- i->rest.info(info_flags::positive)) {
- os << i->rest;
- } else
- os << "(" << i->rest << ')';
- // print 'coeff', something like (x-1)^42
- if (!i->coeff.is_zero()) {
- os << '*';
- if (!point.is_zero())
- os << '(' << var-point << ')';
- else
- os << var;
- if (i->coeff.compare(_ex1())) {
- os << '^';
- if (i->coeff.info(info_flags::negative))
- os << '(' << i->coeff << ')';
- else
- os << i->coeff;
- }
- }
- } else {
- os << Order(power(var-point,i->coeff));
- }
- }
+ debugmsg("pseries print", LOGLEVEL_PRINT);
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+ // omit zero terms
+ if (i->rest.is_zero())
+ continue;
+ // print a sign, if needed
+ if (i!=seq.begin())
+ os << '+';
+ if (!is_order_function(i->rest)) {
+ // print 'rest', i.e. the expansion coefficient
+ if (i->rest.info(info_flags::numeric) &&
+ i->rest.info(info_flags::positive)) {
+ os << i->rest;
+ } else
+ os << "(" << i->rest << ')';
+ // print 'coeff', something like (x-1)^42
+ if (!i->coeff.is_zero()) {
+ os << '*';
+ if (!point.is_zero())
+ os << '(' << var-point << ')';
+ else
+ os << var;
+ if (i->coeff.compare(_ex1())) {
+ os << '^';
+ if (i->coeff.info(info_flags::negative))
+ os << '(' << i->coeff << ')';
+ else
+ os << i->coeff;
+ }
+ }
+ } else {
+ os << Order(power(var-point,i->coeff));
+ }
+ }
}
void pseries::printraw(std::ostream &os) const
{
- debugmsg("pseries printraw", LOGLEVEL_PRINT);
- os << "pseries(" << var << ";" << point << ";";
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
- os << "(" << (*i).rest << "," << (*i).coeff << "),";
- }
- os << ")";
+ debugmsg("pseries printraw", LOGLEVEL_PRINT);
+ os << "pseries(" << var << ";" << point << ";";
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+ os << "(" << (*i).rest << "," << (*i).coeff << "),";
+ }
+ os << ")";
}
void pseries::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("pseries printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "pseries "
- << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::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 << std::string(indent+delta_indent,' ') << "-----" << std::endl;
- }
- var.printtree(os, indent+delta_indent);
- point.printtree(os, indent+delta_indent);
+ debugmsg("pseries printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << "pseries "
+ << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::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 << std::string(indent+delta_indent,' ') << "-----" << std::endl;
+ }
+ var.printtree(os, indent+delta_indent);
+ point.printtree(os, indent+delta_indent);
}
/** Return the number of operands including a possible order term. */
unsigned pseries::nops(void) const
{
- return seq.size();
+ return seq.size();
}
/** Return the ith term in the series when represented as a sum. */
ex pseries::op(int i) const
{
- if (i < 0 || unsigned(i) >= seq.size())
- throw (std::out_of_range("op() out of range"));
- return seq[i].rest * power(var - point, seq[i].coeff);
+ if (i < 0 || unsigned(i) >= seq.size())
+ throw (std::out_of_range("op() out of range"));
+ return seq[i].rest * power(var - point, seq[i].coeff);
}
ex &pseries::let_op(int i)
{
- throw (std::logic_error("let_op not defined for pseries"));
+ throw (std::logic_error("let_op not defined for pseries"));
}
* series is examined termwise. */
int pseries::degree(const symbol &s) const
{
- if (var.is_equal(s)) {
- // Return last exponent
- if (seq.size())
- return ex_to_numeric((*(seq.end() - 1)).coeff).to_int();
- else
- return 0;
- } else {
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- if (it == itend)
- return 0;
- int max_pow = INT_MIN;
- while (it != itend) {
- int pow = it->rest.degree(s);
- if (pow > max_pow)
- max_pow = pow;
- ++it;
- }
- return max_pow;
- }
+ if (var.is_equal(s)) {
+ // Return last exponent
+ if (seq.size())
+ return ex_to_numeric((*(seq.end() - 1)).coeff).to_int();
+ else
+ return 0;
+ } else {
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ if (it == itend)
+ return 0;
+ int max_pow = INT_MIN;
+ while (it != itend) {
+ int pow = it->rest.degree(s);
+ if (pow > max_pow)
+ max_pow = pow;
+ ++it;
+ }
+ return max_pow;
+ }
}
/** Return degree of lowest power of the series. This is usually the exponent
* I.e.: (1-x) + (1-x)^2 + Order((1-x)^3) has ldegree(x) 1, not 0. */
int pseries::ldegree(const symbol &s) const
{
- if (var.is_equal(s)) {
- // Return first exponent
- if (seq.size())
- return ex_to_numeric((*(seq.begin())).coeff).to_int();
- else
- return 0;
- } else {
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- if (it == itend)
- return 0;
- int min_pow = INT_MAX;
- while (it != itend) {
- int pow = it->rest.ldegree(s);
- if (pow < min_pow)
- min_pow = pow;
- ++it;
- }
- return min_pow;
- }
+ if (var.is_equal(s)) {
+ // Return first exponent
+ if (seq.size())
+ return ex_to_numeric((*(seq.begin())).coeff).to_int();
+ else
+ return 0;
+ } else {
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ if (it == itend)
+ return 0;
+ int min_pow = INT_MAX;
+ while (it != itend) {
+ int pow = it->rest.ldegree(s);
+ if (pow < min_pow)
+ min_pow = pow;
+ ++it;
+ }
+ return min_pow;
+ }
}
ex pseries::coeff(const symbol &s, int n) const
{
- if (var.is_equal(s)) {
- if (seq.size() == 0)
- return _ex0();
-
- // Binary search in sequence for given power
- numeric looking_for = numeric(n);
- int lo = 0, hi = seq.size() - 1;
- while (lo <= hi) {
- int mid = (lo + hi) / 2;
- GINAC_ASSERT(is_ex_exactly_of_type(seq[mid].coeff, numeric));
- int cmp = ex_to_numeric(seq[mid].coeff).compare(looking_for);
- switch (cmp) {
- case -1:
- lo = mid + 1;
- break;
- case 0:
- return seq[mid].rest;
- case 1:
- hi = mid - 1;
- break;
- default:
- throw(std::logic_error("pseries::coeff: compare() didn't return -1, 0 or 1"));
- }
- }
- return _ex0();
- } else
- return convert_to_poly().coeff(s, n);
+ if (var.is_equal(s)) {
+ if (seq.size() == 0)
+ return _ex0();
+
+ // Binary search in sequence for given power
+ numeric looking_for = numeric(n);
+ int lo = 0, hi = seq.size() - 1;
+ while (lo <= hi) {
+ int mid = (lo + hi) / 2;
+ GINAC_ASSERT(is_ex_exactly_of_type(seq[mid].coeff, numeric));
+ int cmp = ex_to_numeric(seq[mid].coeff).compare(looking_for);
+ switch (cmp) {
+ case -1:
+ lo = mid + 1;
+ break;
+ case 0:
+ return seq[mid].rest;
+ case 1:
+ hi = mid - 1;
+ break;
+ default:
+ throw(std::logic_error("pseries::coeff: compare() didn't return -1, 0 or 1"));
+ }
+ }
+ return _ex0();
+ } else
+ return convert_to_poly().coeff(s, n);
}
ex pseries::collect(const symbol &s) const
{
- return *this;
+ return *this;
}
/** Evaluate coefficients. */
ex pseries::eval(int level) const
{
- if (level == 1)
- return this->hold();
-
- if (level == -max_recursion_level)
- throw (std::runtime_error("pseries::eval(): recursion limit exceeded"));
-
- // Construct a new series with evaluated coefficients
- epvector new_seq;
- new_seq.reserve(seq.size());
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
- new_seq.push_back(expair(it->rest.eval(level-1), it->coeff));
- ++it;
- }
- return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
+ if (level == 1)
+ return this->hold();
+
+ if (level == -max_recursion_level)
+ throw (std::runtime_error("pseries::eval(): recursion limit exceeded"));
+
+ // Construct a new series with evaluated coefficients
+ epvector new_seq;
+ new_seq.reserve(seq.size());
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ new_seq.push_back(expair(it->rest.eval(level-1), it->coeff));
+ ++it;
+ }
+ return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
}
/** Evaluate coefficients numerically. */
ex pseries::evalf(int level) const
{
- if (level == 1)
- return *this;
-
- if (level == -max_recursion_level)
- throw (std::runtime_error("pseries::evalf(): recursion limit exceeded"));
-
- // Construct a new series with evaluated coefficients
- epvector new_seq;
- new_seq.reserve(seq.size());
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
- new_seq.push_back(expair(it->rest.evalf(level-1), it->coeff));
- ++it;
- }
- return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
+ if (level == 1)
+ return *this;
+
+ if (level == -max_recursion_level)
+ throw (std::runtime_error("pseries::evalf(): recursion limit exceeded"));
+
+ // Construct a new series with evaluated coefficients
+ epvector new_seq;
+ new_seq.reserve(seq.size());
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ new_seq.push_back(expair(it->rest.evalf(level-1), it->coeff));
+ ++it;
+ }
+ return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
}
ex pseries::subs(const lst & ls, const lst & lr) const
{
- // If expansion variable is being substituted, convert the series to a
- // polynomial and do the substitution there because the result might
- // no longer be a power series
- if (ls.has(var))
- return convert_to_poly(true).subs(ls, lr);
-
- // Otherwise construct a new series with substituted coefficients and
- // expansion point
- epvector newseq;
- newseq.reserve(seq.size());
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
- newseq.push_back(expair(it->rest.subs(ls, lr), it->coeff));
- ++it;
- }
- return (new pseries(relational(var,point.subs(ls, lr)), newseq))->setflag(status_flags::dynallocated);
+ // If expansion variable is being substituted, convert the series to a
+ // polynomial and do the substitution there because the result might
+ // no longer be a power series
+ if (ls.has(var))
+ return convert_to_poly(true).subs(ls, lr);
+
+ // Otherwise construct a new series with substituted coefficients and
+ // expansion point
+ epvector newseq;
+ newseq.reserve(seq.size());
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ newseq.push_back(expair(it->rest.subs(ls, lr), it->coeff));
+ ++it;
+ }
+ return (new pseries(relational(var,point.subs(ls, lr)), newseq))->setflag(status_flags::dynallocated);
}
* @see ex::diff */
ex pseries::expand(unsigned options) const
{
- epvector newseq;
- newseq.reserve(seq.size());
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
- newseq.push_back(expair(i->rest.expand(), i->coeff));
- return (new pseries(relational(var,point), newseq))
- ->setflag(status_flags::dynallocated |
- status_flags::expanded);
+ epvector newseq;
+ newseq.reserve(seq.size());
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
+ newseq.push_back(expair(i->rest.expand(), i->coeff));
+ return (new pseries(relational(var,point), newseq))
+ ->setflag(status_flags::dynallocated |
+ status_flags::expanded);
}
* @see ex::diff */
ex pseries::derivative(const symbol & s) const
{
- if (s == var) {
- epvector new_seq;
- epvector::const_iterator it = seq.begin(), itend = seq.end();
-
- // FIXME: coeff might depend on var
- while (it != itend) {
- if (is_order_function(it->rest)) {
- new_seq.push_back(expair(it->rest, it->coeff - 1));
- } else {
- ex c = it->rest * it->coeff;
- if (!c.is_zero())
- new_seq.push_back(expair(c, it->coeff - 1));
- }
- ++it;
- }
- return pseries(relational(var,point), new_seq);
- } else {
- return *this;
- }
+ if (s == var) {
+ epvector new_seq;
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+
+ // FIXME: coeff might depend on var
+ while (it != itend) {
+ if (is_order_function(it->rest)) {
+ new_seq.push_back(expair(it->rest, it->coeff - 1));
+ } else {
+ ex c = it->rest * it->coeff;
+ if (!c.is_zero())
+ new_seq.push_back(expair(c, it->coeff - 1));
+ }
+ ++it;
+ }
+ return pseries(relational(var,point), new_seq);
+ } else {
+ return *this;
+ }
}
* @param no_order flag: discard higher order terms */
ex pseries::convert_to_poly(bool no_order) const
{
- ex e;
- epvector::const_iterator it = seq.begin(), itend = seq.end();
-
- while (it != itend) {
- if (is_order_function(it->rest)) {
- if (!no_order)
- e += Order(power(var - point, it->coeff));
- } else
- e += it->rest * power(var - point, it->coeff);
- ++it;
- }
- return e;
+ ex e;
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+
+ while (it != itend) {
+ if (is_order_function(it->rest)) {
+ if (!no_order)
+ e += Order(power(var - point, it->coeff));
+ } else
+ e += it->rest * power(var - point, it->coeff);
+ ++it;
+ }
+ return e;
}
/** Returns true if there is no order term, i.e. the series terminates and
* false otherwise. */
bool pseries::is_terminating(void) const
{
- return !is_order_function((seq.end()-1)->rest);
+ return !is_order_function((seq.end()-1)->rest);
}
* @see ex::series */
ex basic::series(const relational & r, int order, unsigned options) const
{
- epvector seq;
- numeric fac(1);
- ex deriv = *this;
- ex coeff = deriv.subs(r);
- const symbol *s = static_cast<symbol *>(r.lhs().bp);
-
- if (!coeff.is_zero())
- seq.push_back(expair(coeff, numeric(0)));
-
- int n;
- for (n=1; n<order; ++n) {
- fac = fac.mul(numeric(n));
- deriv = deriv.diff(*s).expand();
- if (deriv.is_zero()) {
- // Series terminates
- return pseries(r, seq);
- }
- coeff = deriv.subs(r);
- if (!coeff.is_zero())
- seq.push_back(expair(fac.inverse() * coeff, numeric(n)));
- }
-
- // Higher-order terms, if present
- deriv = deriv.diff(*s);
- if (!deriv.expand().is_zero())
- seq.push_back(expair(Order(_ex1()), numeric(n)));
- return pseries(r, seq);
+ epvector seq;
+ numeric fac(1);
+ ex deriv = *this;
+ ex coeff = deriv.subs(r);
+ const symbol *s = static_cast<symbol *>(r.lhs().bp);
+
+ if (!coeff.is_zero())
+ seq.push_back(expair(coeff, numeric(0)));
+
+ int n;
+ for (n=1; n<order; ++n) {
+ fac = fac.mul(numeric(n));
+ deriv = deriv.diff(*s).expand();
+ if (deriv.is_zero()) {
+ // Series terminates
+ return pseries(r, seq);
+ }
+ coeff = deriv.subs(r);
+ if (!coeff.is_zero())
+ seq.push_back(expair(fac.inverse() * coeff, numeric(n)));
+ }
+
+ // Higher-order terms, if present
+ deriv = deriv.diff(*s);
+ if (!deriv.expand().is_zero())
+ seq.push_back(expair(Order(_ex1()), numeric(n)));
+ return pseries(r, seq);
}
* @see ex::series */
ex symbol::series(const relational & r, int order, unsigned options) const
{
- epvector seq;
- const ex point = r.rhs();
- GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
- const symbol *s = static_cast<symbol *>(r.lhs().bp);
-
- if (this->is_equal(*s)) {
- if (order > 0 && !point.is_zero())
- seq.push_back(expair(point, _ex0()));
- if (order > 1)
- seq.push_back(expair(_ex1(), _ex1()));
- else
- seq.push_back(expair(Order(_ex1()), numeric(order)));
- } else
- seq.push_back(expair(*this, _ex0()));
- return pseries(r, seq);
+ epvector seq;
+ const ex point = r.rhs();
+ GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
+ const symbol *s = static_cast<symbol *>(r.lhs().bp);
+
+ if (this->is_equal(*s)) {
+ if (order > 0 && !point.is_zero())
+ seq.push_back(expair(point, _ex0()));
+ if (order > 1)
+ seq.push_back(expair(_ex1(), _ex1()));
+ else
+ seq.push_back(expair(Order(_ex1()), numeric(order)));
+ } else
+ seq.push_back(expair(*this, _ex0()));
+ return pseries(r, seq);
}
* @return the sum as a pseries */
ex pseries::add_series(const pseries &other) const
{
- // Adding two series with different variables or expansion points
- // results in an empty (constant) series
- if (!is_compatible_to(other)) {
- epvector nul;
- nul.push_back(expair(Order(_ex1()), _ex0()));
- return pseries(relational(var,point), nul);
- }
-
- // Series addition
- epvector new_seq;
- epvector::const_iterator a = seq.begin();
- epvector::const_iterator b = other.seq.begin();
- epvector::const_iterator a_end = seq.end();
- epvector::const_iterator b_end = other.seq.end();
- int pow_a = INT_MAX, pow_b = INT_MAX;
- for (;;) {
- // If a is empty, fill up with elements from b and stop
- if (a == a_end) {
- while (b != b_end) {
- new_seq.push_back(*b);
- ++b;
- }
- break;
- } else
- pow_a = ex_to_numeric((*a).coeff).to_int();
-
- // If b is empty, fill up with elements from a and stop
- if (b == b_end) {
- while (a != a_end) {
- new_seq.push_back(*a);
- ++a;
- }
- break;
- } else
- pow_b = ex_to_numeric((*b).coeff).to_int();
-
- // a and b are non-empty, compare powers
- if (pow_a < pow_b) {
- // a has lesser power, get coefficient from a
- new_seq.push_back(*a);
- if (is_order_function((*a).rest))
- break;
- ++a;
- } else if (pow_b < pow_a) {
- // b has lesser power, get coefficient from b
- new_seq.push_back(*b);
- if (is_order_function((*b).rest))
- break;
- ++b;
- } else {
- // Add coefficient of a and b
- if (is_order_function((*a).rest) || is_order_function((*b).rest)) {
- new_seq.push_back(expair(Order(_ex1()), (*a).coeff));
- break; // Order term ends the sequence
- } else {
- ex sum = (*a).rest + (*b).rest;
- if (!(sum.is_zero()))
- new_seq.push_back(expair(sum, numeric(pow_a)));
- ++a;
- ++b;
- }
- }
- }
- return pseries(relational(var,point), new_seq);
+ // Adding two series with different variables or expansion points
+ // results in an empty (constant) series
+ if (!is_compatible_to(other)) {
+ epvector nul;
+ nul.push_back(expair(Order(_ex1()), _ex0()));
+ return pseries(relational(var,point), nul);
+ }
+
+ // Series addition
+ epvector new_seq;
+ epvector::const_iterator a = seq.begin();
+ epvector::const_iterator b = other.seq.begin();
+ epvector::const_iterator a_end = seq.end();
+ epvector::const_iterator b_end = other.seq.end();
+ int pow_a = INT_MAX, pow_b = INT_MAX;
+ for (;;) {
+ // If a is empty, fill up with elements from b and stop
+ if (a == a_end) {
+ while (b != b_end) {
+ new_seq.push_back(*b);
+ ++b;
+ }
+ break;
+ } else
+ pow_a = ex_to_numeric((*a).coeff).to_int();
+
+ // If b is empty, fill up with elements from a and stop
+ if (b == b_end) {
+ while (a != a_end) {
+ new_seq.push_back(*a);
+ ++a;
+ }
+ break;
+ } else
+ pow_b = ex_to_numeric((*b).coeff).to_int();
+
+ // a and b are non-empty, compare powers
+ if (pow_a < pow_b) {
+ // a has lesser power, get coefficient from a
+ new_seq.push_back(*a);
+ if (is_order_function((*a).rest))
+ break;
+ ++a;
+ } else if (pow_b < pow_a) {
+ // b has lesser power, get coefficient from b
+ new_seq.push_back(*b);
+ if (is_order_function((*b).rest))
+ break;
+ ++b;
+ } else {
+ // Add coefficient of a and b
+ if (is_order_function((*a).rest) || is_order_function((*b).rest)) {
+ new_seq.push_back(expair(Order(_ex1()), (*a).coeff));
+ break; // Order term ends the sequence
+ } else {
+ ex sum = (*a).rest + (*b).rest;
+ if (!(sum.is_zero()))
+ new_seq.push_back(expair(sum, numeric(pow_a)));
+ ++a;
+ ++b;
+ }
+ }
+ }
+ return pseries(relational(var,point), new_seq);
}
* @see ex::series */
ex add::series(const relational & r, int order, unsigned options) const
{
- ex acc; // Series accumulator
-
- // Get first term from overall_coeff
- acc = overall_coeff.series(r, order, options);
-
- // Add remaining terms
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- for (; it!=itend; ++it) {
- ex op;
- if (is_ex_exactly_of_type(it->rest, pseries))
- op = it->rest;
- else
- op = it->rest.series(r, order, options);
- if (!it->coeff.is_equal(_ex1()))
- op = ex_to_pseries(op).mul_const(ex_to_numeric(it->coeff));
-
- // Series addition
- acc = ex_to_pseries(acc).add_series(ex_to_pseries(op));
- }
- return acc;
+ ex acc; // Series accumulator
+
+ // Get first term from overall_coeff
+ acc = overall_coeff.series(r, order, options);
+
+ // Add remaining terms
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ for (; it!=itend; ++it) {
+ ex op;
+ if (is_ex_exactly_of_type(it->rest, pseries))
+ op = it->rest;
+ else
+ op = it->rest.series(r, order, options);
+ if (!it->coeff.is_equal(_ex1()))
+ op = ex_to_pseries(op).mul_const(ex_to_numeric(it->coeff));
+
+ // Series addition
+ acc = ex_to_pseries(acc).add_series(ex_to_pseries(op));
+ }
+ return acc;
}
* @return the product as a pseries */
ex pseries::mul_const(const numeric &other) const
{
- epvector new_seq;
- new_seq.reserve(seq.size());
-
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
- if (!is_order_function(it->rest))
- new_seq.push_back(expair(it->rest * other, it->coeff));
- else
- new_seq.push_back(*it);
- ++it;
- }
- return pseries(relational(var,point), new_seq);
+ epvector new_seq;
+ new_seq.reserve(seq.size());
+
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ if (!is_order_function(it->rest))
+ new_seq.push_back(expair(it->rest * other, it->coeff));
+ else
+ new_seq.push_back(*it);
+ ++it;
+ }
+ return pseries(relational(var,point), new_seq);
}
* @return the product as a pseries */
ex pseries::mul_series(const pseries &other) const
{
- // Multiplying two series with different variables or expansion points
- // results in an empty (constant) series
- if (!is_compatible_to(other)) {
- epvector nul;
- nul.push_back(expair(Order(_ex1()), _ex0()));
- return pseries(relational(var,point), nul);
- }
-
- // Series multiplication
- epvector new_seq;
-
- const symbol *s = static_cast<symbol *>(var.bp);
- int a_max = degree(*s);
- int b_max = other.degree(*s);
- int a_min = ldegree(*s);
- int b_min = other.ldegree(*s);
- int cdeg_min = a_min + b_min;
- int cdeg_max = a_max + b_max;
-
- int higher_order_a = INT_MAX;
- int higher_order_b = INT_MAX;
- if (is_order_function(coeff(*s, a_max)))
- higher_order_a = a_max + b_min;
- if (is_order_function(other.coeff(*s, b_max)))
- higher_order_b = b_max + a_min;
- int higher_order_c = std::min(higher_order_a, higher_order_b);
- if (cdeg_max >= higher_order_c)
- cdeg_max = higher_order_c - 1;
-
- for (int cdeg=cdeg_min; cdeg<=cdeg_max; ++cdeg) {
- ex co = _ex0();
- // c(i)=a(0)b(i)+...+a(i)b(0)
- for (int i=a_min; cdeg-i>=b_min; ++i) {
- ex a_coeff = coeff(*s, i);
- ex b_coeff = other.coeff(*s, cdeg-i);
- if (!is_order_function(a_coeff) && !is_order_function(b_coeff))
- co += a_coeff * b_coeff;
- }
- if (!co.is_zero())
- new_seq.push_back(expair(co, numeric(cdeg)));
- }
- if (higher_order_c < INT_MAX)
- new_seq.push_back(expair(Order(_ex1()), numeric(higher_order_c)));
- return pseries(relational(var,point), new_seq);
+ // Multiplying two series with different variables or expansion points
+ // results in an empty (constant) series
+ if (!is_compatible_to(other)) {
+ epvector nul;
+ nul.push_back(expair(Order(_ex1()), _ex0()));
+ return pseries(relational(var,point), nul);
+ }
+
+ // Series multiplication
+ epvector new_seq;
+
+ const symbol *s = static_cast<symbol *>(var.bp);
+ int a_max = degree(*s);
+ int b_max = other.degree(*s);
+ int a_min = ldegree(*s);
+ int b_min = other.ldegree(*s);
+ int cdeg_min = a_min + b_min;
+ int cdeg_max = a_max + b_max;
+
+ int higher_order_a = INT_MAX;
+ int higher_order_b = INT_MAX;
+ if (is_order_function(coeff(*s, a_max)))
+ higher_order_a = a_max + b_min;
+ if (is_order_function(other.coeff(*s, b_max)))
+ higher_order_b = b_max + a_min;
+ int higher_order_c = std::min(higher_order_a, higher_order_b);
+ if (cdeg_max >= higher_order_c)
+ cdeg_max = higher_order_c - 1;
+
+ for (int cdeg=cdeg_min; cdeg<=cdeg_max; ++cdeg) {
+ ex co = _ex0();
+ // c(i)=a(0)b(i)+...+a(i)b(0)
+ for (int i=a_min; cdeg-i>=b_min; ++i) {
+ ex a_coeff = coeff(*s, i);
+ ex b_coeff = other.coeff(*s, cdeg-i);
+ if (!is_order_function(a_coeff) && !is_order_function(b_coeff))
+ co += a_coeff * b_coeff;
+ }
+ if (!co.is_zero())
+ new_seq.push_back(expair(co, numeric(cdeg)));
+ }
+ if (higher_order_c < INT_MAX)
+ new_seq.push_back(expair(Order(_ex1()), numeric(higher_order_c)));
+ return pseries(relational(var,point), new_seq);
}
* @see ex::series */
ex mul::series(const relational & r, int order, unsigned options) const
{
- ex acc; // Series accumulator
-
- // Get first term from overall_coeff
- acc = overall_coeff.series(r, order, options);
-
- // Multiply with remaining terms
- epvector::const_iterator it = seq.begin();
- epvector::const_iterator itend = seq.end();
- for (; it!=itend; ++it) {
- ex op = it->rest;
- if (op.info(info_flags::numeric)) {
- // series * const (special case, faster)
- ex f = power(op, it->coeff);
- acc = ex_to_pseries(acc).mul_const(ex_to_numeric(f));
- continue;
- } else if (!is_ex_exactly_of_type(op, pseries))
- op = op.series(r, order, options);
- if (!it->coeff.is_equal(_ex1()))
- op = ex_to_pseries(op).power_const(ex_to_numeric(it->coeff), order);
-
- // Series multiplication
- acc = ex_to_pseries(acc).mul_series(ex_to_pseries(op));
- }
- return acc;
+ ex acc; // Series accumulator
+
+ // Get first term from overall_coeff
+ acc = overall_coeff.series(r, order, options);
+
+ // Multiply with remaining terms
+ epvector::const_iterator it = seq.begin();
+ epvector::const_iterator itend = seq.end();
+ for (; it!=itend; ++it) {
+ ex op = it->rest;
+ if (op.info(info_flags::numeric)) {
+ // series * const (special case, faster)
+ ex f = power(op, it->coeff);
+ acc = ex_to_pseries(acc).mul_const(ex_to_numeric(f));
+ continue;
+ } else if (!is_ex_exactly_of_type(op, pseries))
+ op = op.series(r, order, options);
+ if (!it->coeff.is_equal(_ex1()))
+ op = ex_to_pseries(op).power_const(ex_to_numeric(it->coeff), order);
+
+ // Series multiplication
+ acc = ex_to_pseries(acc).mul_series(ex_to_pseries(op));
+ }
+ return acc;
}
* @param deg truncation order of series calculation */
ex pseries::power_const(const numeric &p, int deg) const
{
- int i;
- const symbol *s = static_cast<symbol *>(var.bp);
- int ldeg = ldegree(*s);
-
- // Calculate coefficients of powered series
- exvector co;
- co.reserve(deg);
- ex co0;
- co.push_back(co0 = power(coeff(*s, ldeg), p));
- bool all_sums_zero = true;
- for (i=1; i<deg; ++i) {
- ex sum = _ex0();
- for (int j=1; j<=i; ++j) {
- ex c = coeff(*s, j + ldeg);
- if (is_order_function(c)) {
- co.push_back(Order(_ex1()));
- break;
- } else
- sum += (p * j - (i - j)) * co[i - j] * c;
- }
- if (!sum.is_zero())
- all_sums_zero = false;
- co.push_back(co0 * sum / numeric(i));
- }
-
- // Construct new series (of non-zero coefficients)
- epvector new_seq;
- bool higher_order = false;
- for (i=0; i<deg; ++i) {
- if (!co[i].is_zero())
- new_seq.push_back(expair(co[i], numeric(i) + p * ldeg));
- if (is_order_function(co[i])) {
- higher_order = true;
- break;
- }
- }
- if (!higher_order && !all_sums_zero)
- new_seq.push_back(expair(Order(_ex1()), numeric(deg) + p * ldeg));
- return pseries(relational(var,point), new_seq);
+ int i;
+ const symbol *s = static_cast<symbol *>(var.bp);
+ int ldeg = ldegree(*s);
+
+ // Calculate coefficients of powered series
+ exvector co;
+ co.reserve(deg);
+ ex co0;
+ co.push_back(co0 = power(coeff(*s, ldeg), p));
+ bool all_sums_zero = true;
+ for (i=1; i<deg; ++i) {
+ ex sum = _ex0();
+ for (int j=1; j<=i; ++j) {
+ ex c = coeff(*s, j + ldeg);
+ if (is_order_function(c)) {
+ co.push_back(Order(_ex1()));
+ break;
+ } else
+ sum += (p * j - (i - j)) * co[i - j] * c;
+ }
+ if (!sum.is_zero())
+ all_sums_zero = false;
+ co.push_back(co0 * sum / numeric(i));
+ }
+
+ // Construct new series (of non-zero coefficients)
+ epvector new_seq;
+ bool higher_order = false;
+ for (i=0; i<deg; ++i) {
+ if (!co[i].is_zero())
+ new_seq.push_back(expair(co[i], numeric(i) + p * ldeg));
+ if (is_order_function(co[i])) {
+ higher_order = true;
+ break;
+ }
+ }
+ if (!higher_order && !all_sums_zero)
+ new_seq.push_back(expair(Order(_ex1()), numeric(deg) + p * ldeg));
+ return pseries(relational(var,point), new_seq);
}
/** Return a new pseries object with the powers shifted by deg. */
pseries pseries::shift_exponents(int deg) const
{
- epvector newseq(seq);
- for (epvector::iterator i=newseq.begin(); i!=newseq.end(); ++i)
- i->coeff = i->coeff + deg;
- return pseries(relational(var, point), newseq);
+ epvector newseq(seq);
+ for (epvector::iterator i=newseq.begin(); i!=newseq.end(); ++i)
+ i->coeff = i->coeff + deg;
+ return pseries(relational(var, point), newseq);
}
* @see ex::series */
ex power::series(const relational & r, int order, unsigned options) const
{
- ex e;
- if (!is_ex_exactly_of_type(basis, pseries)) {
- // Basis is not a series, may there be a singulary?
- if (!exponent.info(info_flags::negint))
- return basic::series(r, order, options);
-
- // Expression is of type something^(-int), check for singularity
- if (!basis.subs(r).is_zero())
- return basic::series(r, order, options);
-
- // Singularity encountered, expand basis into series
- e = basis.series(r, order, options);
- } else {
- // Basis is a series
- e = basis;
- }
-
- // Power e
- return ex_to_pseries(e).power_const(ex_to_numeric(exponent), order);
+ ex e;
+ if (!is_ex_exactly_of_type(basis, pseries)) {
+ // Basis is not a series, may there be a singulary?
+ if (!exponent.info(info_flags::negint))
+ return basic::series(r, order, options);
+
+ // Expression is of type something^(-int), check for singularity
+ if (!basis.subs(r).is_zero())
+ return basic::series(r, order, options);
+
+ // Singularity encountered, expand basis into series
+ e = basis.series(r, order, options);
+ } else {
+ // Basis is a series
+ e = basis;
+ }
+
+ // Power e
+ return ex_to_pseries(e).power_const(ex_to_numeric(exponent), order);
}
/** Re-expansion of a pseries object. */
ex pseries::series(const relational & r, int order, unsigned options) const
{
- const ex p = r.rhs();
- GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
- const symbol *s = static_cast<symbol *>(r.lhs().bp);
-
- if (var.is_equal(*s) && point.is_equal(p)) {
- if (order > degree(*s))
- return *this;
- else {
- epvector new_seq;
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
- int o = ex_to_numeric(it->coeff).to_int();
- if (o >= order) {
- new_seq.push_back(expair(Order(_ex1()), o));
- break;
- }
- new_seq.push_back(*it);
- ++it;
- }
- return pseries(r, new_seq);
- }
- } else
- return convert_to_poly().series(r, order, options);
+ const ex p = r.rhs();
+ GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
+ const symbol *s = static_cast<symbol *>(r.lhs().bp);
+
+ if (var.is_equal(*s) && point.is_equal(p)) {
+ if (order > degree(*s))
+ return *this;
+ else {
+ epvector new_seq;
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ int o = ex_to_numeric(it->coeff).to_int();
+ if (o >= order) {
+ new_seq.push_back(expair(Order(_ex1()), o));
+ break;
+ }
+ new_seq.push_back(*it);
+ ++it;
+ }
+ return pseries(r, new_seq);
+ }
+ } else
+ return convert_to_poly().series(r, order, options);
}
* @return an expression holding a pseries object */
ex ex::series(const ex & r, int order, unsigned options) const
{
- GINAC_ASSERT(bp!=0);
- ex e;
- relational rel_;
-
- if (is_ex_exactly_of_type(r,relational))
- rel_ = ex_to_relational(r);
- else if (is_ex_exactly_of_type(r,symbol))
- rel_ = relational(r,_ex0());
- else
- throw (std::logic_error("ex::series(): expansion point has unknown type"));
-
- try {
- e = bp->series(rel_, order, options);
- } catch (std::exception &x) {
- throw (std::logic_error(std::string("unable to compute series (") + x.what() + ")"));
- }
- return e;
+ GINAC_ASSERT(bp!=0);
+ ex e;
+ relational rel_;
+
+ if (is_ex_exactly_of_type(r,relational))
+ rel_ = ex_to_relational(r);
+ else if (is_ex_exactly_of_type(r,symbol))
+ rel_ = relational(r,_ex0());
+ else
+ throw (std::logic_error("ex::series(): expansion point has unknown type"));
+
+ try {
+ e = bp->series(rel_, order, options);
+ } catch (std::exception &x) {
+ throw (std::logic_error(std::string("unable to compute series (") + x.what() + ")"));
+ }
+ return e;
}
* Other classes must provide members to convert into this type. */
class pseries : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(pseries, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(pseries, basic)
- // default constructor, destructor, copy constructor, assignment operator and helpers
+ // default constructor, destructor, copy constructor, assignment operator and helpers
public:
- pseries();
- ~pseries();
- pseries(const pseries &other);
- const pseries &operator=(const pseries &other);
+ pseries();
+ ~pseries();
+ pseries(const pseries &other);
+ const pseries &operator=(const pseries &other);
protected:
- void copy(const pseries &other);
- void destroy(bool call_parent);
+ void copy(const pseries &other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- pseries(const ex &rel_, const epvector &ops_);
+ pseries(const ex &rel_, const epvector &ops_);
- // functions overriding virtual functions from base classes
+ // functions overriding virtual functions from base classes
public:
- basic *duplicate() const;
- void print(std::ostream &os, unsigned upper_precedence = 0) const;
- void printraw(std::ostream &os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- unsigned nops(void) const;
- ex op(int i) const;
- ex &let_op(int i);
- int degree(const symbol &s) const;
- int ldegree(const symbol &s) const;
- ex coeff(const symbol &s, int n = 1) const;
- ex collect(const symbol &s) const;
- ex eval(int level=0) const;
- ex evalf(int level=0) const;
- ex series(const relational & r, int order, unsigned options = 0) const;
- ex subs(const lst & ls, const lst & lr) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
- ex expand(unsigned options = 0) const;
+ basic *duplicate() const;
+ void print(std::ostream &os, unsigned upper_precedence = 0) const;
+ void printraw(std::ostream &os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ unsigned nops(void) const;
+ ex op(int i) const;
+ ex &let_op(int i);
+ int degree(const symbol &s) const;
+ int ldegree(const symbol &s) const;
+ ex coeff(const symbol &s, int n = 1) const;
+ ex collect(const symbol &s) const;
+ ex eval(int level=0) const;
+ ex evalf(int level=0) const;
+ ex series(const relational & r, int order, unsigned options = 0) const;
+ ex subs(const lst & ls, const lst & lr) const;
+ ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
+ ex expand(unsigned options = 0) const;
protected:
- ex derivative(const symbol & s) const;
+ ex derivative(const symbol & s) const;
- // non-virtual functions in this class
+ // non-virtual functions in this class
public:
- ex convert_to_poly(bool no_order = false) const;
- bool is_compatible_to(const pseries &other) const {return var.compare(other.var) == 0 && point.compare(other.point) == 0;}
- bool is_zero(void) const {return seq.size() == 0;}
- bool is_terminating(void) const;
- ex add_series(const pseries &other) const;
- ex mul_const(const numeric &other) const;
- ex mul_series(const pseries &other) const;
- ex power_const(const numeric &p, int deg) const;
- pseries shift_exponents(int deg) const;
+ ex convert_to_poly(bool no_order = false) const;
+ bool is_compatible_to(const pseries &other) const {return var.compare(other.var) == 0 && point.compare(other.point) == 0;}
+ bool is_zero(void) const {return seq.size() == 0;}
+ bool is_terminating(void) const;
+ ex add_series(const pseries &other) const;
+ ex mul_const(const numeric &other) const;
+ ex mul_series(const pseries &other) const;
+ ex power_const(const numeric &p, int deg) const;
+ pseries shift_exponents(int deg) const;
protected:
- /** Vector of {coefficient, power} pairs */
- epvector seq;
+ /** Vector of {coefficient, power} pairs */
+ epvector seq;
- /** Series variable (holds a symbol) */
- ex var;
+ /** Series variable (holds a symbol) */
+ ex var;
- /** Expansion point */
- ex point;
+ /** Expansion point */
+ ex point;
};
// global constants
* @see is_ex_of_type */
inline const pseries &ex_to_pseries(const ex &e)
{
- return static_cast<const pseries &>(*e.bp);
+ return static_cast<const pseries &>(*e.bp);
}
/** Convert the pseries object embedded in an expression to an ordinary
* @see pseries::convert_to_poly */
inline ex series_to_poly(const ex &e)
{
- return (static_cast<const pseries &>(*e.bp).convert_to_poly(true));
+ return (static_cast<const pseries &>(*e.bp).convert_to_poly(true));
}
inline bool is_terminating(const pseries & s)
{
- return s.is_terminating();
+ return s.is_terminating();
}
#ifndef NO_NAMESPACE_GINAC
/** This structure stores information about a registered GiNaC class. */
struct registered_class_info {
- registered_class_info(const char *n, const char *s, unsigned int k, unarch_func f)
- : name(n), super(s), tinfo_key(k), unarchive(f)
- {
- // Add structure to list
- next = first_registered_class;
- first_registered_class = this;
- }
-
- registered_class_info *next; /**< Pointer to next registered_class_info in list. */
- const char *name; /**< Class name. */
- const char *super; /**< Name of superclass. */
- unsigned int tinfo_key; /**< TINFO_* key. */
- unarch_func unarchive; /**< Pointer to unarchiving function. */
+ registered_class_info(const char *n, const char *s, unsigned int k, unarch_func f)
+ : name(n), super(s), tinfo_key(k), unarchive(f)
+ {
+ // Add structure to list
+ next = first_registered_class;
+ first_registered_class = this;
+ }
+
+ registered_class_info *next; /**< Pointer to next registered_class_info in list. */
+ const char *name; /**< Class name. */
+ const char *super; /**< Name of superclass. */
+ unsigned int tinfo_key; /**< TINFO_* key. */
+ unarch_func unarchive; /**< Pointer to unarchiving function. */
};
/** Macro for inclusion in the declaration of each registered class. */
#define GINAC_DECLARE_REGISTERED_CLASS(classname, supername) \
public: \
- typedef supername inherited; \
- static registered_class_info reg_info; \
- virtual const char *class_name(void) const; \
- classname(const archive_node &n, const lst &sym_lst); \
- virtual void archive(archive_node &n) const; \
- static ex unarchive(const archive_node &n, const lst &sym_lst); \
+ typedef supername inherited; \
+ static registered_class_info reg_info; \
+ virtual const char *class_name(void) const; \
+ classname(const archive_node &n, const lst &sym_lst); \
+ virtual void archive(archive_node &n) const; \
+ static ex unarchive(const archive_node &n, const lst &sym_lst); \
private:
/** Macro for inclusion in the implementation of each registered class. */
#define GINAC_IMPLEMENT_REGISTERED_CLASS(classname, supername) \
- registered_class_info classname::reg_info(#classname, #supername, TINFO_##classname, &classname::unarchive); \
- const char *classname::class_name(void) const {return reg_info.name;}
+ registered_class_info classname::reg_info(#classname, #supername, TINFO_##classname, &classname::unarchive); \
+ const char *classname::class_name(void) const {return reg_info.name;}
/** Find TINFO_* key by class name. */
relational::relational() : basic(TINFO_relational)
{
- debugmsg("relational default constructor",LOGLEVEL_CONSTRUCT);
+ debugmsg("relational default constructor",LOGLEVEL_CONSTRUCT);
}
relational::~relational()
{
- debugmsg("relational destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("relational destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
relational::relational(const relational & other)
{
- debugmsg("relational copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("relational copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const relational & relational::operator=(const relational & other)
{
- debugmsg("relational operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("relational operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void relational::copy(const relational & other)
{
- basic::copy(other);
- lh=other.lh;
- rh=other.rh;
- o=other.o;
+ basic::copy(other);
+ lh=other.lh;
+ rh=other.rh;
+ o=other.o;
}
void relational::destroy(bool call_parent)
{
- if (call_parent) basic::destroy(call_parent);
+ if (call_parent) basic::destroy(call_parent);
}
//////////
relational::relational(const ex & lhs, const ex & rhs, operators oper) : basic(TINFO_relational)
{
- debugmsg("relational constructor ex,ex,operator",LOGLEVEL_CONSTRUCT);
- lh=lhs;
- rh=rhs;
- o=oper;
+ debugmsg("relational constructor ex,ex,operator",LOGLEVEL_CONSTRUCT);
+ lh=lhs;
+ rh=rhs;
+ o=oper;
}
//////////
/** Construct object from archive_node. */
relational::relational(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("relational constructor from archive_node", LOGLEVEL_CONSTRUCT);
- unsigned int opi;
- if (!(n.find_unsigned("op", opi)))
- throw (std::runtime_error("unknown relational operator in archive"));
- o = (operators)opi;
- n.find_ex("lh", lh, sym_lst);
- n.find_ex("rh", rh, sym_lst);
+ debugmsg("relational constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ unsigned int opi;
+ if (!(n.find_unsigned("op", opi)))
+ throw (std::runtime_error("unknown relational operator in archive"));
+ o = (operators)opi;
+ n.find_ex("lh", lh, sym_lst);
+ n.find_ex("rh", rh, sym_lst);
}
/** Unarchive the object. */
ex relational::unarchive(const archive_node &n, const lst &sym_lst)
{
- return (new relational(n, sym_lst))->setflag(status_flags::dynallocated);
+ return (new relational(n, sym_lst))->setflag(status_flags::dynallocated);
}
/** Archive the object. */
void relational::archive(archive_node &n) const
{
- inherited::archive(n);
- n.add_ex("lh", lh);
- n.add_ex("rh", rh);
- n.add_unsigned("op", o);
+ inherited::archive(n);
+ n.add_ex("lh", lh);
+ n.add_ex("rh", rh);
+ n.add_unsigned("op", o);
}
//////////
basic * relational::duplicate() const
{
- debugmsg("relational duplicate",LOGLEVEL_DUPLICATE);
- return new relational(*this);
+ debugmsg("relational duplicate",LOGLEVEL_DUPLICATE);
+ return new relational(*this);
}
void relational::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("relational print",LOGLEVEL_PRINT);
- if (precedence<=upper_precedence) os << "(";
- lh.print(os,precedence);
- switch (o) {
- case equal:
- os << "==";
- break;
- case not_equal:
- os << "!=";
- break;
- case less:
- os << "<";
- break;
- case less_or_equal:
- os << "<=";
- break;
- case greater:
- os << ">";
- break;
- case greater_or_equal:
- os << ">=";
- break;
- default:
- os << "(INVALID RELATIONAL OPERATOR)";
- }
- rh.print(os,precedence);
- if (precedence<=upper_precedence) os << ")";
+ debugmsg("relational print",LOGLEVEL_PRINT);
+ if (precedence<=upper_precedence) os << "(";
+ lh.print(os,precedence);
+ switch (o) {
+ case equal:
+ os << "==";
+ break;
+ case not_equal:
+ os << "!=";
+ break;
+ case less:
+ os << "<";
+ break;
+ case less_or_equal:
+ os << "<=";
+ break;
+ case greater:
+ os << ">";
+ break;
+ case greater_or_equal:
+ os << ">=";
+ break;
+ default:
+ os << "(INVALID RELATIONAL OPERATOR)";
+ }
+ rh.print(os,precedence);
+ if (precedence<=upper_precedence) os << ")";
}
void relational::printraw(std::ostream & os) const
{
- debugmsg("relational printraw",LOGLEVEL_PRINT);
- os << "RELATIONAL(";
- lh.printraw(os);
- os << ",";
- rh.printraw(os);
- os << ",";
- switch (o) {
- case equal:
- os << "==";
- break;
- case not_equal:
- os << "!=";
- break;
- case less:
- os << "<";
- break;
- case less_or_equal:
- os << "<=";
- break;
- case greater:
- os << ">";
- break;
- case greater_or_equal:
- os << ">=";
- break;
- default:
- os << "(INVALID RELATIONAL OPERATOR)";
- }
- os << ")";
+ debugmsg("relational printraw",LOGLEVEL_PRINT);
+ os << "RELATIONAL(";
+ lh.printraw(os);
+ os << ",";
+ rh.printraw(os);
+ os << ",";
+ switch (o) {
+ case equal:
+ os << "==";
+ break;
+ case not_equal:
+ os << "!=";
+ break;
+ case less:
+ os << "<";
+ break;
+ case less_or_equal:
+ os << "<=";
+ break;
+ case greater:
+ os << ">";
+ break;
+ case greater_or_equal:
+ os << ">=";
+ break;
+ default:
+ os << "(INVALID RELATIONAL OPERATOR)";
+ }
+ os << ")";
}
void relational::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("relational print csrc", LOGLEVEL_PRINT);
- if (precedence<=upper_precedence)
- os << "(";
-
- // Print left-hand expression
- lh.bp->printcsrc(os, type, precedence);
-
- // Print relational operator
- switch (o) {
- case equal:
- os << "==";
- break;
- case not_equal:
- os << "!=";
- break;
- case less:
- os << "<";
- break;
- case less_or_equal:
- os << "<=";
- break;
- case greater:
- os << ">";
- break;
- case greater_or_equal:
- os << ">=";
- break;
- default:
- os << "(INVALID RELATIONAL OPERATOR)";
- break;
- }
-
- // Print right-hand operator
- rh.bp->printcsrc(os, type, precedence);
-
- if (precedence <= upper_precedence)
- os << ")";
+ debugmsg("relational print csrc", LOGLEVEL_PRINT);
+ if (precedence<=upper_precedence)
+ os << "(";
+
+ // Print left-hand expression
+ lh.bp->printcsrc(os, type, precedence);
+
+ // Print relational operator
+ switch (o) {
+ case equal:
+ os << "==";
+ break;
+ case not_equal:
+ os << "!=";
+ break;
+ case less:
+ os << "<";
+ break;
+ case less_or_equal:
+ os << "<=";
+ break;
+ case greater:
+ os << ">";
+ break;
+ case greater_or_equal:
+ os << ">=";
+ break;
+ default:
+ os << "(INVALID RELATIONAL OPERATOR)";
+ break;
+ }
+
+ // Print right-hand operator
+ rh.bp->printcsrc(os, type, precedence);
+
+ if (precedence <= upper_precedence)
+ os << ")";
}
bool relational::info(unsigned inf) const
{
- switch (inf) {
- case info_flags::relation:
- return 1;
- case info_flags::relation_equal:
- return o==equal;
- case info_flags::relation_not_equal:
- return o==not_equal;
- case info_flags::relation_less:
- return o==less;
- case info_flags::relation_less_or_equal:
- return o==less_or_equal;
- case info_flags::relation_greater:
- return o==greater;
- case info_flags::relation_greater_or_equal:
- return o==greater_or_equal;
- }
- return 0;
+ switch (inf) {
+ case info_flags::relation:
+ return 1;
+ case info_flags::relation_equal:
+ return o==equal;
+ case info_flags::relation_not_equal:
+ return o==not_equal;
+ case info_flags::relation_less:
+ return o==less;
+ case info_flags::relation_less_or_equal:
+ return o==less_or_equal;
+ case info_flags::relation_greater:
+ return o==greater;
+ case info_flags::relation_greater_or_equal:
+ return o==greater_or_equal;
+ }
+ return 0;
}
unsigned relational::nops() const
{
- return 2;
+ return 2;
}
ex & relational::let_op(int i)
{
- GINAC_ASSERT(i>=0);
- GINAC_ASSERT(i<2);
+ GINAC_ASSERT(i>=0);
+ GINAC_ASSERT(i<2);
- return i==0 ? lh : rh;
+ return i==0 ? lh : rh;
}
-
+
ex relational::eval(int level) const
{
- if (level==1) {
- return this->hold();
- }
- if (level == -max_recursion_level) {
- throw(std::runtime_error("max recursion level reached"));
- }
- return (new relational(lh.eval(level-1),rh.eval(level-1),o))->
- setflag(status_flags::dynallocated |
- status_flags::evaluated );
+ if (level==1) {
+ return this->hold();
+ }
+ if (level == -max_recursion_level) {
+ throw(std::runtime_error("max recursion level reached"));
+ }
+ return (new relational(lh.eval(level-1),rh.eval(level-1),o))->
+ setflag(status_flags::dynallocated |
+ status_flags::evaluated );
}
ex relational::evalf(int level) const
{
- if (level==1) {
- return *this;
- }
- if (level == -max_recursion_level) {
- throw(std::runtime_error("max recursion level reached"));
- }
- return (new relational(lh.eval(level-1),rh.eval(level-1),o))->
- setflag(status_flags::dynallocated);
+ if (level==1) {
+ return *this;
+ }
+ if (level == -max_recursion_level) {
+ throw(std::runtime_error("max recursion level reached"));
+ }
+ return (new relational(lh.eval(level-1),rh.eval(level-1),o))->
+ setflag(status_flags::dynallocated);
}
ex relational::simplify_ncmul(const exvector & v) const
{
- return lh.simplify_ncmul(v);
+ return lh.simplify_ncmul(v);
}
// protected
int relational::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_exactly_of_type(other, relational));
- const relational & oth=static_cast<const relational &>(const_cast<basic &>(other));
-
- int cmpval;
-
- if (o == oth.o) {
- cmpval=lh.compare(oth.lh);
- if (cmpval==0) {
- return rh.compare(oth.rh);
- } else {
- return cmpval;
- }
- }
- if (o<oth.o) {
- return -1;
- } else {
- return 1;
- }
+ GINAC_ASSERT(is_exactly_of_type(other, relational));
+ const relational & oth=static_cast<const relational &>(const_cast<basic &>(other));
+
+ int cmpval;
+
+ if (o == oth.o) {
+ cmpval=lh.compare(oth.lh);
+ if (cmpval==0) {
+ return rh.compare(oth.rh);
+ } else {
+ return cmpval;
+ }
+ }
+ if (o<oth.o) {
+ return -1;
+ } else {
+ return 1;
+ }
}
unsigned relational::return_type(void) const
{
- GINAC_ASSERT(lh.return_type()==rh.return_type());
- return lh.return_type();
+ GINAC_ASSERT(lh.return_type()==rh.return_type());
+ return lh.return_type();
}
unsigned relational::return_type_tinfo(void) const
{
- GINAC_ASSERT(lh.return_type_tinfo()==rh.return_type_tinfo());
- return lh.return_type_tinfo();
+ GINAC_ASSERT(lh.return_type_tinfo()==rh.return_type_tinfo());
+ return lh.return_type_tinfo();
}
//////////
/** Left hand side of relational. */
ex relational::lhs(void) const
{
- return lh;
+ return lh;
}
/** Right hand side of relational. */
ex relational::rhs(void) const
{
- return rh;
+ return rh;
}
//////////
relational::operator bool() const
{
- // please note that (a<b) == false does not imply (a>=b) == true
- // a false result means the comparison is either false or undecidable
- // (except for !=, where true means unequal or undecidable)
- ex df=lh-rh;
- if (!is_ex_exactly_of_type(df,numeric)) {
- return o==not_equal ? true : false; // cannot decide on non-numerical results
- }
- int cmpval=ex_to_numeric(df).compare(_num0());
- switch (o) {
- case equal:
- return cmpval==0;
- break;
- case not_equal:
- return cmpval!=0;
- break;
- case less:
- return cmpval<0;
- break;
- case less_or_equal:
- return cmpval<=0;
- break;
- case greater:
- return cmpval>0;
- break;
- case greater_or_equal:
- return cmpval>=0;
- break;
- default:
- throw(std::logic_error("invalid relational operator"));
- }
- return 0;
+ // please note that (a<b) == false does not imply (a>=b) == true
+ // a false result means the comparison is either false or undecidable
+ // (except for !=, where true means unequal or undecidable)
+ ex df=lh-rh;
+ if (!is_ex_exactly_of_type(df,numeric)) {
+ return o==not_equal ? true : false; // cannot decide on non-numerical results
+ }
+ int cmpval=ex_to_numeric(df).compare(_num0());
+ switch (o) {
+ case equal:
+ return cmpval==0;
+ break;
+ case not_equal:
+ return cmpval!=0;
+ break;
+ case less:
+ return cmpval<0;
+ break;
+ case less_or_equal:
+ return cmpval<=0;
+ break;
+ case greater:
+ return cmpval>0;
+ break;
+ case greater_or_equal:
+ return cmpval>=0;
+ break;
+ default:
+ throw(std::logic_error("invalid relational operator"));
+ }
+ return 0;
}
//////////
* relation between them. */
class relational : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(relational, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(relational, basic)
// types
public:
- enum operators { equal,
- not_equal,
- less,
- less_or_equal,
- greater,
- greater_or_equal
- };
-
+ enum operators { equal,
+ not_equal,
+ less,
+ less_or_equal,
+ greater,
+ greater_or_equal
+ };
+
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- relational();
- ~relational();
- relational(const relational & other);
- const relational & operator=(const relational & other);
+ relational();
+ ~relational();
+ relational(const relational & other);
+ const relational & operator=(const relational & other);
protected:
- void copy(const relational & other);
- void destroy(bool call_parent);
+ void copy(const relational & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- relational(const ex & lhs, const ex & rhs, operators oper=equal);
-
- // functions overriding virtual functions from bases classes
+ relational(const ex & lhs, const ex & rhs, operators oper=equal);
+
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printraw(std::ostream & os) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
- unsigned nops() const;
- ex & let_op(int i);
- ex eval(int level=0) const;
- ex evalf(int level=0) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
- ex simplify_ncmul(const exvector & v) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printraw(std::ostream & os) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
+ unsigned nops() const;
+ ex & let_op(int i);
+ ex eval(int level=0) const;
+ ex evalf(int level=0) const;
+ ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+ ex simplify_ncmul(const exvector & v) const;
protected:
- int compare_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
+ int compare_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
- // new virtual functions which can be overridden by derived classes
+ // new virtual functions which can be overridden by derived classes
public:
- virtual ex lhs(void) const;
- virtual ex rhs(void) const;
+ virtual ex lhs(void) const;
+ virtual ex rhs(void) const;
- // non-virtual functions in this class
+ // non-virtual functions in this class
public:
- operator bool(void) const;
-
+ operator bool(void) const;
+
// member variables
-
+
protected:
- ex lh;
- ex rh;
- operators o;
- static unsigned precedence;
+ ex lh;
+ ex rh;
+ operators o;
+ static unsigned precedence;
};
// global constants
//////////
remember_table_entry::remember_table_entry(function const & f, ex const & r) :
- hashvalue(f.gethash()), seq(f.seq), result(r)
+ hashvalue(f.gethash()), seq(f.seq), result(r)
{
- ++last_access=access_counter;
- successful_hits=0;
+ ++last_access=access_counter;
+ successful_hits=0;
}
bool remember_table_entry::is_equal(function const & f) const
{
- GINAC_ASSERT(f.seq.size()==seq.size());
- if (f.gethash()!=hashvalue) return false;
- for (unsigned i=0; i<seq.size(); ++i) {
- if (!seq[i].is_equal(f.seq[i])) return false;
- }
- ++last_access=access_counter;
- ++successful_hits;
- return true;
+ GINAC_ASSERT(f.seq.size()==seq.size());
+ if (f.gethash()!=hashvalue) return false;
+ for (unsigned i=0; i<seq.size(); ++i) {
+ if (!seq[i].is_equal(f.seq[i])) return false;
+ }
+ ++last_access=access_counter;
+ ++successful_hits;
+ return true;
}
unsigned long remember_table_entry::access_counter=0;
remember_table_list::remember_table_list(unsigned as, unsigned strat)
{
- max_assoc_size=as;
- remember_strategy=strat;
+ max_assoc_size=as;
+ remember_strategy=strat;
}
void remember_table_list::add_entry(function const & f, ex const & result)
{
- if ((max_assoc_size!=0)&&
- (remember_strategy!=remember_strategies::delete_never)&&
- (size()>=max_assoc_size)) {
- // table is full, we must delete an older entry
- GINAC_ASSERT(size()>0); // there must be at least one entry
+ if ((max_assoc_size!=0)&&
+ (remember_strategy!=remember_strategies::delete_never)&&
+ (size()>=max_assoc_size)) {
+ // table is full, we must delete an older entry
+ GINAC_ASSERT(size()>0); // there must be at least one entry
- switch (remember_strategy) {
- case remember_strategies::delete_cyclic:
- // delete oldest entry (first in list)
- erase(begin());
- break;
- case remember_strategies::delete_lru:
- {
- // delete least recently used entry
- iterator it=begin();
- iterator lowest_access_it=it;
- unsigned long lowest_access=it->get_last_access();
- ++it;
- while (it!=end()) {
- if (it->get_last_access()<lowest_access) {
- lowest_access=it->get_last_access();
- lowest_access_it=it;
- }
- ++it;
- }
- erase(lowest_access_it);
- }
- break;
- case remember_strategies::delete_lfu:
- {
- // delete least frequently used entry
- iterator it=begin();
- iterator lowest_hits_it=it;
- unsigned lowest_hits=it->get_successful_hits();
- ++it;
- while (it!=end()) {
- if (it->get_successful_hits()<lowest_hits) {
- lowest_hits=it->get_successful_hits();
- lowest_hits_it=it;
- }
- ++it;
- }
- erase(lowest_hits_it);
- }
- break;
- default:
- throw(std::logic_error("remember_table_list::add_entry(): invalid remember_strategy"));
- }
- GINAC_ASSERT(size()==max_assoc_size-1);
- }
- push_back(remember_table_entry(f,result));
+ switch (remember_strategy) {
+ case remember_strategies::delete_cyclic:
+ // delete oldest entry (first in list)
+ erase(begin());
+ break;
+ case remember_strategies::delete_lru:
+ {
+ // delete least recently used entry
+ iterator it=begin();
+ iterator lowest_access_it=it;
+ unsigned long lowest_access=it->get_last_access();
+ ++it;
+ while (it!=end()) {
+ if (it->get_last_access()<lowest_access) {
+ lowest_access=it->get_last_access();
+ lowest_access_it=it;
+ }
+ ++it;
+ }
+ erase(lowest_access_it);
+ }
+ break;
+ case remember_strategies::delete_lfu:
+ {
+ // delete least frequently used entry
+ iterator it=begin();
+ iterator lowest_hits_it=it;
+ unsigned lowest_hits=it->get_successful_hits();
+ ++it;
+ while (it!=end()) {
+ if (it->get_successful_hits()<lowest_hits) {
+ lowest_hits=it->get_successful_hits();
+ lowest_hits_it=it;
+ }
+ ++it;
+ }
+ erase(lowest_hits_it);
+ }
+ break;
+ default:
+ throw(std::logic_error("remember_table_list::add_entry(): invalid remember_strategy"));
+ }
+ GINAC_ASSERT(size()==max_assoc_size-1);
+ }
+ push_back(remember_table_entry(f,result));
}
bool remember_table_list::lookup_entry(function const & f, ex & result) const
{
- for (const_iterator cit=begin(); cit!=end(); ++cit) {
- if (cit->is_equal(f)) {
- result=cit->get_result();
- return true;
- }
- }
- return false;
+ for (const_iterator cit=begin(); cit!=end(); ++cit) {
+ if (cit->is_equal(f)) {
+ result=cit->get_result();
+ return true;
+ }
+ }
+ return false;
}
//////////
remember_table::remember_table()
{
- table_size=0;
- max_assoc_size=0;
- remember_strategy=remember_strategies::delete_never;
+ table_size=0;
+ max_assoc_size=0;
+ remember_strategy=remember_strategies::delete_never;
}
remember_table::remember_table(unsigned s, unsigned as, unsigned strat) :
- max_assoc_size(as), remember_strategy(strat)
+ max_assoc_size(as), remember_strategy(strat)
{
- // we keep max_assoc_size and remember_strategy if we need to clear
- // all entries
+ // we keep max_assoc_size and remember_strategy if we need to clear
+ // all entries
- // use some power of 2 next to s
- table_size=1 << log2(s);
- init_table();
+ // use some power of 2 next to s
+ table_size=1 << log2(s);
+ init_table();
}
bool remember_table::lookup_entry(function const & f, ex & result) const
{
- unsigned entry=f.gethash() & (table_size-1);
- GINAC_ASSERT(entry<size());
- return operator[](entry).lookup_entry(f,result);
+ unsigned entry=f.gethash() & (table_size-1);
+ GINAC_ASSERT(entry<size());
+ return operator[](entry).lookup_entry(f,result);
}
void remember_table::add_entry(function const & f, ex const & result)
{
- unsigned entry=f.gethash() & (table_size-1);
- GINAC_ASSERT(entry<size());
- operator[](entry).add_entry(f,result);
+ unsigned entry=f.gethash() & (table_size-1);
+ GINAC_ASSERT(entry<size());
+ operator[](entry).add_entry(f,result);
}
void remember_table::clear_all_entries(void)
{
- clear();
- init_table();
+ clear();
+ init_table();
}
void remember_table::init_table(void)
{
- reserve(table_size);
- for (unsigned i=0; i<table_size; ++i) {
- push_back(remember_table_list(max_assoc_size,remember_strategy));
- }
+ reserve(table_size);
+ for (unsigned i=0; i<table_size; ++i) {
+ push_back(remember_table_list(max_assoc_size,remember_strategy));
+ }
}
std::vector<remember_table> & remember_table::remember_tables(void)
{
- static std::vector<remember_table> * rt = new std::vector<remember_table>;
- return *rt;
+ static std::vector<remember_table> * rt = new std::vector<remember_table>;
+ return *rt;
}
#ifndef NO_NAMESPACE_GINAC
class function;
class ex;
-
+
/** A single entry in the remember table of a function.
- Needs to be a friend of class function to access 'seq'.
- 'last_access' and 'successful_hits' are updated at each successful
- 'is_equal'. */
+ Needs to be a friend of class function to access 'seq'.
+ 'last_access' and 'successful_hits' are updated at each successful
+ 'is_equal'. */
class remember_table_entry {
public:
- remember_table_entry(function const & f, ex const & r);
- bool is_equal(function const & f) const;
- ex get_result(void) const { return result; }
- unsigned long get_last_access(void) const { return last_access; }
- unsigned long get_successful_hits(void) const { return successful_hits; };
+ remember_table_entry(function const & f, ex const & r);
+ bool is_equal(function const & f) const;
+ ex get_result(void) const { return result; }
+ unsigned long get_last_access(void) const { return last_access; }
+ unsigned long get_successful_hits(void) const { return successful_hits; };
protected:
- unsigned hashvalue;
- exvector seq;
- ex result;
- mutable unsigned long last_access;
- mutable unsigned successful_hits;
- static unsigned long access_counter;
+ unsigned hashvalue;
+ exvector seq;
+ ex result;
+ mutable unsigned long last_access;
+ mutable unsigned successful_hits;
+ static unsigned long access_counter;
};
/** A list of entries in the remember table having some least
- significant bits of the hashvalue in common. */
+ significant bits of the hashvalue in common. */
class remember_table_list : public std::list<remember_table_entry> {
public:
- remember_table_list(unsigned as, unsigned strat);
- void add_entry(function const & f, ex const & result);
- bool lookup_entry(function const & f, ex & result) const;
+ remember_table_list(unsigned as, unsigned strat);
+ void add_entry(function const & f, ex const & result);
+ bool lookup_entry(function const & f, ex & result) const;
protected:
- unsigned max_assoc_size;
- unsigned remember_strategy;
+ unsigned max_assoc_size;
+ unsigned remember_strategy;
};
/** The remember table is organized like an n-fold associative cache
- in a microprocessor. The table has a width of 's' (which is rounded
- to table_size, some power of 2 near 's', internally) and a depth of 'as'
- (unless you choose that entries are never discarded). The place where
- an entry is stored depends on the hashvalue of the parameters of the
- function (this corresponds to the address of byte to be cached).
- The 'log_2(table_size)' least significant bits of this hashvalue
- give the slot in which the entry will be stored or looked up.
- Each slot can take up to 'as' entries. If a slot is full, an older
- entry is removed by one of the following strategies:
- - oldest entry (the first one in the list)
- - least recently used (the one with the lowest 'last_access')
- - least frequently used (the one with the lowest 'successful_hits')
- or all entries are kept which means that the table grows indefinitely. */
+ in a microprocessor. The table has a width of 's' (which is rounded
+ to table_size, some power of 2 near 's', internally) and a depth of 'as'
+ (unless you choose that entries are never discarded). The place where
+ an entry is stored depends on the hashvalue of the parameters of the
+ function (this corresponds to the address of byte to be cached).
+ The 'log_2(table_size)' least significant bits of this hashvalue
+ give the slot in which the entry will be stored or looked up.
+ Each slot can take up to 'as' entries. If a slot is full, an older
+ entry is removed by one of the following strategies:
+ - oldest entry (the first one in the list)
+ - least recently used (the one with the lowest 'last_access')
+ - least frequently used (the one with the lowest 'successful_hits')
+ or all entries are kept which means that the table grows indefinitely. */
class remember_table : public std::vector<remember_table_list> {
public:
- remember_table();
- remember_table(unsigned s, unsigned as, unsigned strat);
- bool lookup_entry(function const & f, ex & result) const;
- void add_entry(function const & f, ex const & result);
- void clear_all_entries(void);
- void show_statistics(std::ostream & os, unsigned level) const;
- static std::vector<remember_table> & remember_tables(void);
+ remember_table();
+ remember_table(unsigned s, unsigned as, unsigned strat);
+ bool lookup_entry(function const & f, ex & result) const;
+ void add_entry(function const & f, ex const & result);
+ void clear_all_entries(void);
+ void show_statistics(std::ostream & os, unsigned level) const;
+ static std::vector<remember_table> & remember_tables(void);
protected:
- void init_table(void);
- unsigned table_size;
- unsigned max_assoc_size;
- unsigned remember_strategy;
+ void init_table(void);
+ unsigned table_size;
+ unsigned max_assoc_size;
+ unsigned remember_strategy;
};
#ifndef NO_NAMESPACE_GINAC
simp_lor::simp_lor() : type(invalid)
{
- debugmsg("simp_lor default constructor",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_simp_lor;
+ debugmsg("simp_lor default constructor",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_simp_lor;
}
simp_lor::~simp_lor()
{
- debugmsg("simp_lor destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("simp_lor destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
simp_lor::simp_lor(const simp_lor & other)
{
- debugmsg("simp_lor copy constructor",LOGLEVEL_CONSTRUCT);
- copy (other);
+ debugmsg("simp_lor copy constructor",LOGLEVEL_CONSTRUCT);
+ copy (other);
}
const simp_lor & simp_lor::operator=(const simp_lor & other)
{
- debugmsg("simp_lor operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("simp_lor operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void simp_lor::copy(const simp_lor & other)
{
- indexed::copy(other);
- type=other.type;
- name=other.name;
+ indexed::copy(other);
+ type=other.type;
+ name=other.name;
}
void simp_lor::destroy(bool call_parent)
{
- if (call_parent) {
- indexed::destroy(call_parent);
- }
+ if (call_parent) {
+ indexed::destroy(call_parent);
+ }
}
//////////
simp_lor::simp_lor(simp_lor_types const t) : type(t)
{
- debugmsg("simp_lor constructor from simp_lor_types",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_simp_lor;
+ debugmsg("simp_lor constructor from simp_lor_types",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_simp_lor;
}
simp_lor::simp_lor(simp_lor_types const t, const ex & i1, const ex & i2) :
- indexed(i1,i2), type(t)
+ indexed(i1,i2), type(t)
{
- debugmsg("simp_lor constructor from simp_lor_types,ex,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_simp_lor;
- GINAC_ASSERT(all_of_type_lorentzidx());
+ debugmsg("simp_lor constructor from simp_lor_types,ex,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_simp_lor;
+ GINAC_ASSERT(all_of_type_lorentzidx());
}
simp_lor::simp_lor(simp_lor_types const t, const std::string & n, const ex & i1) :
- indexed(i1), type(t), name(n)
+ indexed(i1), type(t), name(n)
{
- debugmsg("simp_lor constructor from simp_lor_types,string,ex",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_simp_lor;
- GINAC_ASSERT(all_of_type_lorentzidx());
+ debugmsg("simp_lor constructor from simp_lor_types,string,ex",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_simp_lor;
+ GINAC_ASSERT(all_of_type_lorentzidx());
}
simp_lor::simp_lor(simp_lor_types const t, const std::string & n, const exvector & iv) :
- indexed(iv), type(t), name(n)
+ indexed(iv), type(t), name(n)
{
- debugmsg("simp_lor constructor from simp_lor_types,string,exvector",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_simp_lor;
- GINAC_ASSERT(all_of_type_lorentzidx());
+ debugmsg("simp_lor constructor from simp_lor_types,string,exvector",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_simp_lor;
+ GINAC_ASSERT(all_of_type_lorentzidx());
}
simp_lor::simp_lor(simp_lor_types const t, const std::string & n, exvector * ivp) :
- indexed(ivp), type(t), name(n)
+ indexed(ivp), type(t), name(n)
{
- debugmsg("simp_lor constructor from simp_lor_types,string,exvector*",LOGLEVEL_CONSTRUCT);
- tinfo_key=TINFO_simp_lor;
- GINAC_ASSERT(all_of_type_lorentzidx());
+ debugmsg("simp_lor constructor from simp_lor_types,string,exvector*",LOGLEVEL_CONSTRUCT);
+ tinfo_key=TINFO_simp_lor;
+ GINAC_ASSERT(all_of_type_lorentzidx());
}
//////////
basic * simp_lor::duplicate() const
{
- debugmsg("simp_lor duplicate",LOGLEVEL_DUPLICATE);
- return new simp_lor(*this);
+ debugmsg("simp_lor duplicate",LOGLEVEL_DUPLICATE);
+ return new simp_lor(*this);
}
void simp_lor::printraw(std::ostream & os) const
{
- debugmsg("simp_lor printraw",LOGLEVEL_PRINT);
- os << "simp_lor(type=" << (unsigned)type
- << ",name=" << name << ",indices=";
- printrawindices(os);
- os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+ debugmsg("simp_lor printraw",LOGLEVEL_PRINT);
+ os << "simp_lor(type=" << (unsigned)type
+ << ",name=" << name << ",indices=";
+ printrawindices(os);
+ os << ",hash=" << hashvalue << ",flags=" << flags << ")";
}
void simp_lor::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("simp_lor printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "simp_lor object: "
- << "type=" << (unsigned)type
- << ", name=" << name << ", ";
- os << seq.size() << " indices" << std::endl;
- printtreeindices(os,indent);
- os << std::string(indent,' ') << "hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("simp_lor printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << "simp_lor object: "
+ << "type=" << (unsigned)type
+ << ", name=" << name << ", ";
+ os << seq.size() << " indices" << std::endl;
+ printtreeindices(os,indent);
+ os << std::string(indent,' ') << "hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void simp_lor::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("simp_lor print",LOGLEVEL_PRINT);
- switch (type) {
- case simp_lor_g:
- os << "g";
- break;
- case simp_lor_vec:
- os << name;
- break;
- case invalid:
- default:
- os << "INVALID_SIMP_LOR_OBJECT";
- break;
- }
- printindices(os);
+ debugmsg("simp_lor print",LOGLEVEL_PRINT);
+ switch (type) {
+ case simp_lor_g:
+ os << "g";
+ break;
+ case simp_lor_vec:
+ os << name;
+ break;
+ case invalid:
+ default:
+ os << "INVALID_SIMP_LOR_OBJECT";
+ break;
+ }
+ printindices(os);
}
void simp_lor::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("simp_lor print csrc",LOGLEVEL_PRINT);
- print(os,upper_precedence);
+ debugmsg("simp_lor print csrc",LOGLEVEL_PRINT);
+ print(os,upper_precedence);
}
bool simp_lor::info(unsigned inf) const
{
- return indexed::info(inf);
+ return indexed::info(inf);
}
ex simp_lor::eval(int level) const
{
- if (type==simp_lor_g) {
- // canonicalize indices
- exvector iv=seq;
- int sig=canonicalize_indices(iv,false); // symmetric
- if (sig!=INT_MAX) {
- // something has changed while sorting indices, more evaluations later
- if (sig==0) return _ex0();
- return ex(sig)*simp_lor(type,name,iv);
- }
- const lorentzidx & idx1=ex_to_lorentzidx(seq[0]);
- const lorentzidx & idx2=ex_to_lorentzidx(seq[1]);
- if ((!idx1.is_symbolic())&&(!idx2.is_symbolic())) {
- // both indices are numeric
- if ((idx1.get_value()==idx2.get_value())) {
- // both on diagonal
- if (idx1.get_value()==0) {
- // (0,0)
- return _ex1();
- } else {
- if (idx1.is_covariant()!=idx2.is_covariant()) {
- // (_i,~i) or (~i,_i), i=1..3
- return _ex1();
- } else {
- // (_i,_i) or (~i,~i), i=1..3
- return _ex_1();
- }
- }
- } else {
- // at least one off-diagonal
- return _ex0();
- }
- } else if (idx1.is_symbolic() &&
- idx1.is_co_contra_pair(idx2)) {
- return Dim()-idx1.get_dim_parallel_space();
- }
- }
-
- return this->hold();
-}
-
+ if (type==simp_lor_g) {
+ // canonicalize indices
+ exvector iv=seq;
+ int sig=canonicalize_indices(iv,false); // symmetric
+ if (sig!=INT_MAX) {
+ // something has changed while sorting indices, more evaluations later
+ if (sig==0) return _ex0();
+ return ex(sig)*simp_lor(type,name,iv);
+ }
+ const lorentzidx & idx1=ex_to_lorentzidx(seq[0]);
+ const lorentzidx & idx2=ex_to_lorentzidx(seq[1]);
+ if ((!idx1.is_symbolic())&&(!idx2.is_symbolic())) {
+ // both indices are numeric
+ if ((idx1.get_value()==idx2.get_value())) {
+ // both on diagonal
+ if (idx1.get_value()==0) {
+ // (0,0)
+ return _ex1();
+ } else {
+ if (idx1.is_covariant()!=idx2.is_covariant()) {
+ // (_i,~i) or (~i,_i), i=1..3
+ return _ex1();
+ } else {
+ // (_i,_i) or (~i,~i), i=1..3
+ return _ex_1();
+ }
+ }
+ } else {
+ // at least one off-diagonal
+ return _ex0();
+ }
+ } else if (idx1.is_symbolic() &&
+ idx1.is_co_contra_pair(idx2)) {
+ return Dim()-idx1.get_dim_parallel_space();
+ }
+ }
+
+ return this->hold();
+}
+
// protected
int simp_lor::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(other.tinfo() == TINFO_simp_lor);
- const simp_lor *o = static_cast<const simp_lor *>(&other);
- if (type==o->type) {
- if (name==o->name) {
- return indexed::compare_same_type(other);
- }
- return name.compare(o->name);
- }
- return type < o->type ? -1 : 1;
+ GINAC_ASSERT(other.tinfo() == TINFO_simp_lor);
+ const simp_lor *o = static_cast<const simp_lor *>(&other);
+ if (type==o->type) {
+ if (name==o->name) {
+ return indexed::compare_same_type(other);
+ }
+ return name.compare(o->name);
+ }
+ return type < o->type ? -1 : 1;
}
bool simp_lor::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(other.tinfo() == TINFO_simp_lor);
- const simp_lor *o = static_cast<const simp_lor *>(&other);
- if (type!=o->type) return false;
- if (name!=o->name) return false;
- return indexed::is_equal_same_type(other);
+ GINAC_ASSERT(other.tinfo() == TINFO_simp_lor);
+ const simp_lor *o = static_cast<const simp_lor *>(&other);
+ if (type!=o->type) return false;
+ if (name!=o->name) return false;
+ return indexed::is_equal_same_type(other);
}
unsigned simp_lor::return_type(void) const
{
- return return_types::commutative;
+ return return_types::commutative;
}
unsigned simp_lor::return_type_tinfo(void) const
{
- return tinfo_key;
+ return tinfo_key;
}
ex simp_lor::thisexprseq(const exvector & v) const
{
- return simp_lor(type,name,v);
+ return simp_lor(type,name,v);
}
ex simp_lor::thisexprseq(exvector * vp) const
{
- return simp_lor(type,name,vp);
+ return simp_lor(type,name,vp);
}
//////////
bool simp_lor::all_of_type_lorentzidx(void) const
{
- // used only inside of ASSERTs
- for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- if (!is_ex_of_type(*cit,lorentzidx)) return false;
- }
- return true;
+ // used only inside of ASSERTs
+ for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+ if (!is_ex_of_type(*cit,lorentzidx)) return false;
+ }
+ return true;
}
//////////
simp_lor lor_g(const ex & mu, const ex & nu)
{
- return simp_lor(simp_lor::simp_lor_g,mu,nu);
+ return simp_lor(simp_lor::simp_lor_g,mu,nu);
}
simp_lor lor_vec(const std::string & n, const ex & mu)
{
- return simp_lor(simp_lor::simp_lor_vec,n,mu);
+ return simp_lor(simp_lor::simp_lor_vec,n,mu);
}
ex simplify_simp_lor_mul(const ex & m, const scalar_products & sp)
{
- GINAC_ASSERT(is_ex_exactly_of_type(m,mul));
- exvector v_contracted;
-
- // collect factors in an exvector, store squares twice
- unsigned n=m.nops();
- v_contracted.reserve(2*n);
- for (unsigned i=0; i<n; ++i) {
- ex f=m.op(i);
- if (is_ex_exactly_of_type(f,power)&&f.op(1).is_equal(_ex2())) {
- v_contracted.push_back(f.op(0));
- v_contracted.push_back(f.op(0));
- } else {
- v_contracted.push_back(f);
- }
- }
-
- unsigned replacements;
- bool something_changed=false;
-
- exvector::iterator it=v_contracted.begin();
- while (it!=v_contracted.end()) {
- // process only lor_g objects
- if (is_ex_exactly_of_type(*it,simp_lor) &&
- (ex_to_simp_lor(*it).type==simp_lor::simp_lor_g)) {
- const simp_lor & g=ex_to_simp_lor(*it);
- GINAC_ASSERT(g.seq.size()==2);
- const idx & first_idx=ex_to_lorentzidx(g.seq[0]);
- const idx & second_idx=ex_to_lorentzidx(g.seq[1]);
- // g_{mu,mu} should have been contracted in simp_lor::eval()
- GINAC_ASSERT(!first_idx.is_equal(second_idx));
- ex saved_g=*it; // save to restore it later
-
- // try to contract first index
- replacements=0;
- if (first_idx.is_symbolic()) {
- replacements = subs_index_in_exvector(v_contracted,
- first_idx.toggle_covariant(),second_idx);
- if (replacements==0) {
- // not contracted, restore g object
- *it=saved_g;
- } else {
- // a contracted index should occur exactly once
- GINAC_ASSERT(replacements==1);
- *it=_ex1();
- something_changed=true;
- }
- }
-
- // try second index only if first was not contracted
- if ((replacements==0)&&(second_idx.is_symbolic())) {
- // first index not contracted, *it is again the original g object
- replacements = subs_index_in_exvector(v_contracted,
- second_idx.toggle_covariant(),first_idx);
- if (replacements==0) {
- // not contracted except in itself, restore g object
- *it=saved_g;
- } else {
- // a contracted index should occur exactly once
- GINAC_ASSERT(replacements==1);
- *it=_ex1();
- something_changed=true;
- }
- }
- }
- ++it;
- }
-
- // process only lor_vec objects
- bool jump_to_next=false;
- exvector::iterator it1=v_contracted.begin();
- while (it1!=v_contracted.end()-1) {
- if (is_ex_exactly_of_type(*it1,simp_lor) &&
- (ex_to_simp_lor(*it1).type==simp_lor::simp_lor_vec)) {
- exvector::iterator it2=it1+1;
- while ((it2!=v_contracted.end())&&!jump_to_next) {
- if (is_ex_exactly_of_type(*it2,simp_lor) &&
- (ex_to_simp_lor(*it2).type==simp_lor::simp_lor_vec)) {
- const simp_lor & vec1=ex_to_simp_lor(*it1);
- const simp_lor & vec2=ex_to_simp_lor(*it2);
- GINAC_ASSERT(vec1.seq.size()==1);
- GINAC_ASSERT(vec2.seq.size()==1);
- const lorentzidx & idx1=ex_to_lorentzidx(vec1.seq[0]);
- const lorentzidx & idx2=ex_to_lorentzidx(vec2.seq[0]);
- if (idx1.is_symbolic() &&
- idx1.is_co_contra_pair(idx2) &&
- sp.is_defined(vec1,vec2)) {
- *it1=sp.evaluate(vec1,vec2);
- *it2=_ex1();
- something_changed=true;
- jump_to_next=true;
- }
- }
- ++it2;
- }
- jump_to_next=false;
- }
- ++it1;
- }
- if (something_changed) {
- return mul(v_contracted);
- }
- return m;
+ GINAC_ASSERT(is_ex_exactly_of_type(m,mul));
+ exvector v_contracted;
+
+ // collect factors in an exvector, store squares twice
+ unsigned n=m.nops();
+ v_contracted.reserve(2*n);
+ for (unsigned i=0; i<n; ++i) {
+ ex f=m.op(i);
+ if (is_ex_exactly_of_type(f,power)&&f.op(1).is_equal(_ex2())) {
+ v_contracted.push_back(f.op(0));
+ v_contracted.push_back(f.op(0));
+ } else {
+ v_contracted.push_back(f);
+ }
+ }
+
+ unsigned replacements;
+ bool something_changed=false;
+
+ exvector::iterator it=v_contracted.begin();
+ while (it!=v_contracted.end()) {
+ // process only lor_g objects
+ if (is_ex_exactly_of_type(*it,simp_lor) &&
+ (ex_to_simp_lor(*it).type==simp_lor::simp_lor_g)) {
+ const simp_lor & g=ex_to_simp_lor(*it);
+ GINAC_ASSERT(g.seq.size()==2);
+ const idx & first_idx=ex_to_lorentzidx(g.seq[0]);
+ const idx & second_idx=ex_to_lorentzidx(g.seq[1]);
+ // g_{mu,mu} should have been contracted in simp_lor::eval()
+ GINAC_ASSERT(!first_idx.is_equal(second_idx));
+ ex saved_g=*it; // save to restore it later
+
+ // try to contract first index
+ replacements=0;
+ if (first_idx.is_symbolic()) {
+ replacements = subs_index_in_exvector(v_contracted,
+ first_idx.toggle_covariant(),second_idx);
+ if (replacements==0) {
+ // not contracted, restore g object
+ *it=saved_g;
+ } else {
+ // a contracted index should occur exactly once
+ GINAC_ASSERT(replacements==1);
+ *it=_ex1();
+ something_changed=true;
+ }
+ }
+
+ // try second index only if first was not contracted
+ if ((replacements==0)&&(second_idx.is_symbolic())) {
+ // first index not contracted, *it is again the original g object
+ replacements = subs_index_in_exvector(v_contracted,
+ second_idx.toggle_covariant(),first_idx);
+ if (replacements==0) {
+ // not contracted except in itself, restore g object
+ *it=saved_g;
+ } else {
+ // a contracted index should occur exactly once
+ GINAC_ASSERT(replacements==1);
+ *it=_ex1();
+ something_changed=true;
+ }
+ }
+ }
+ ++it;
+ }
+
+ // process only lor_vec objects
+ bool jump_to_next=false;
+ exvector::iterator it1=v_contracted.begin();
+ while (it1!=v_contracted.end()-1) {
+ if (is_ex_exactly_of_type(*it1,simp_lor) &&
+ (ex_to_simp_lor(*it1).type==simp_lor::simp_lor_vec)) {
+ exvector::iterator it2=it1+1;
+ while ((it2!=v_contracted.end())&&!jump_to_next) {
+ if (is_ex_exactly_of_type(*it2,simp_lor) &&
+ (ex_to_simp_lor(*it2).type==simp_lor::simp_lor_vec)) {
+ const simp_lor & vec1=ex_to_simp_lor(*it1);
+ const simp_lor & vec2=ex_to_simp_lor(*it2);
+ GINAC_ASSERT(vec1.seq.size()==1);
+ GINAC_ASSERT(vec2.seq.size()==1);
+ const lorentzidx & idx1=ex_to_lorentzidx(vec1.seq[0]);
+ const lorentzidx & idx2=ex_to_lorentzidx(vec2.seq[0]);
+ if (idx1.is_symbolic() &&
+ idx1.is_co_contra_pair(idx2) &&
+ sp.is_defined(vec1,vec2)) {
+ *it1=sp.evaluate(vec1,vec2);
+ *it2=_ex1();
+ something_changed=true;
+ jump_to_next=true;
+ }
+ }
+ ++it2;
+ }
+ jump_to_next=false;
+ }
+ ++it1;
+ }
+ if (something_changed) {
+ return mul(v_contracted);
+ }
+ return m;
}
ex simplify_simp_lor(const ex & e, const scalar_products & sp)
{
- // all simplification is done on expanded objects
- ex e_expanded=e.expand();
+ // all simplification is done on expanded objects
+ ex e_expanded=e.expand();
- // simplification of sum=sum of simplifications
- if (is_ex_exactly_of_type(e_expanded,add)) {
- ex sum=_ex0();
- for (unsigned i=0; i<e_expanded.nops(); ++i)
- sum += simplify_simp_lor(e_expanded.op(i),sp);
-
- return sum;
- }
+ // simplification of sum=sum of simplifications
+ if (is_ex_exactly_of_type(e_expanded,add)) {
+ ex sum=_ex0();
+ for (unsigned i=0; i<e_expanded.nops(); ++i)
+ sum += simplify_simp_lor(e_expanded.op(i),sp);
+
+ return sum;
+ }
- // simplification of commutative product=commutative product of simplifications
- if (is_ex_exactly_of_type(e_expanded,mul)) {
- return simplify_simp_lor_mul(e,sp);
- }
+ // simplification of commutative product=commutative product of simplifications
+ if (is_ex_exactly_of_type(e_expanded,mul)) {
+ return simplify_simp_lor_mul(e,sp);
+ }
- // cannot do anything
- return e_expanded;
+ // cannot do anything
+ return e_expanded;
}
//ex Dim(void) // FIXME: what's going on here?
//////////
void scalar_products::reg(const simp_lor & v1, const simp_lor & v2,
- const ex & sp)
+ const ex & sp)
{
- if (v1.compare_same_type(v2)>0) {
- reg(v2,v1,sp);
- return;
- }
- spm[make_key(v1,v2)]=sp;
+ if (v1.compare_same_type(v2)>0) {
+ reg(v2,v1,sp);
+ return;
+ }
+ spm[make_key(v1,v2)]=sp;
}
bool scalar_products::is_defined(const simp_lor & v1, const simp_lor & v2) const
{
- if (v1.compare_same_type(v2)>0) {
- return is_defined(v2,v1);
- }
- return spm.find(make_key(v1,v2))!=spm.end();
+ if (v1.compare_same_type(v2)>0) {
+ return is_defined(v2,v1);
+ }
+ return spm.find(make_key(v1,v2))!=spm.end();
}
ex scalar_products::evaluate(const simp_lor & v1, const simp_lor & v2) const
{
- if (v1.compare_same_type(v2)>0) {
- return evaluate(v2,v1);
- }
- return spm.find(make_key(v1,v2))->second;
+ if (v1.compare_same_type(v2)>0) {
+ return evaluate(v2,v1);
+ }
+ return spm.find(make_key(v1,v2))->second;
}
void scalar_products::debugprint(void) const
{
- std::cerr << "map size=" << spm.size() << std::endl;
- for (spmap::const_iterator cit=spm.begin(); cit!=spm.end(); ++cit) {
- const spmapkey & k=(*cit).first;
- std::cerr << "item key=((" << k.first.first
- << "," << k.first.second << "),";
- k.second.printraw(cerr);
- cerr << ") value=" << (*cit).second << std::endl;
- }
+ std::cerr << "map size=" << spm.size() << std::endl;
+ for (spmap::const_iterator cit=spm.begin(); cit!=spm.end(); ++cit) {
+ const spmapkey & k=(*cit).first;
+ std::cerr << "item key=((" << k.first.first
+ << "," << k.first.second << "),";
+ k.second.printraw(cerr);
+ cerr << ") value=" << (*cit).second << std::endl;
+ }
}
spmapkey scalar_products::make_key(const simp_lor & v1, const simp_lor & v2)
{
- GINAC_ASSERT(v1.type==simp_lor::simp_lor_vec);
- GINAC_ASSERT(v2.type==simp_lor::simp_lor_vec);
- lorentzidx anon=ex_to_lorentzidx(v1.seq[0]).create_anonymous_representative();
- GINAC_ASSERT(anon.is_equal_same_type(ex_to_lorentzidx(v2.seq[0]).create_anonymous_representative()));
- return spmapkey(strstrpair(v1.name,v2.name),anon);
+ GINAC_ASSERT(v1.type==simp_lor::simp_lor_vec);
+ GINAC_ASSERT(v2.type==simp_lor::simp_lor_vec);
+ lorentzidx anon=ex_to_lorentzidx(v1.seq[0]).create_anonymous_representative();
+ GINAC_ASSERT(anon.is_equal_same_type(ex_to_lorentzidx(v2.seq[0]).create_anonymous_representative()));
+ return spmapkey(strstrpair(v1.name,v2.name),anon);
}
#ifndef NO_NAMESPACE_GINAC
class spmapkey_is_less
{
public:
- bool operator()(const spmapkey & lh, const spmapkey & rh) const
- {
- /*
- cerr << "spmapkey_is_less" << endl;
- cerr << "lh=((" << lh.first.first
- << "," << lh.first.second << "),";
- lh.second.printraw(cerr);
- cerr << ")" << endl;
-
- cerr << "rh=((" << rh.first.first
- << "," << rh.first.second << "),";
- rh.second.printraw(cerr);
- cerr << ")" << endl;
- */
- bool res=lh.first<rh.first ||
- (!(rh.first<lh.first) && lh.second.compare(rh.second)<0 );
- // cout << "result=" << res << endl;
- return res;
- }
+ bool operator()(const spmapkey & lh, const spmapkey & rh) const
+ {
+ /*
+ cerr << "spmapkey_is_less" << endl;
+ cerr << "lh=((" << lh.first.first
+ << "," << lh.first.second << "),";
+ lh.second.printraw(cerr);
+ cerr << ")" << endl;
+
+ cerr << "rh=((" << rh.first.first
+ << "," << rh.first.second << "),";
+ rh.second.printraw(cerr);
+ cerr << ")" << endl;
+ */
+ bool res=lh.first<rh.first ||
+ (!(rh.first<lh.first) && lh.second.compare(rh.second)<0 );
+ // cout << "result=" << res << endl;
+ return res;
+ }
};
typedef map<spmapkey,ex,spmapkey_is_less> spmap;
class scalar_products
{
public:
- void reg(const simp_lor & v1, const simp_lor & v2, const ex & sp);
- bool is_defined(const simp_lor & v1, const simp_lor & v2) const;
- ex evaluate(const simp_lor & v1, const simp_lor & v2) const;
- void debugprint(void) const;
+ void reg(const simp_lor & v1, const simp_lor & v2, const ex & sp);
+ bool is_defined(const simp_lor & v1, const simp_lor & v2) const;
+ ex evaluate(const simp_lor & v1, const simp_lor & v2) const;
+ void debugprint(void) const;
protected:
- static spmapkey make_key(const simp_lor & v1, const simp_lor & v2);
+ static spmapkey make_key(const simp_lor & v1, const simp_lor & v2);
protected:
- spmap spm;
+ spmap spm;
};
/** Base class for simp_lor object */
{
// friends
- friend class scalar_products;
- friend simp_lor lor_g(const ex & mu, const ex & nu);
- friend simp_lor lor_vec(const std::string & n, const ex & mu);
- friend ex simplify_simp_lor_mul(const ex & m, const scalar_products & sp);
- friend ex simplify_simp_lor(const ex & e, const scalar_products & sp);
-
+ friend class scalar_products;
+ friend simp_lor lor_g(const ex & mu, const ex & nu);
+ friend simp_lor lor_vec(const std::string & n, const ex & mu);
+ friend ex simplify_simp_lor_mul(const ex & m, const scalar_products & sp);
+ friend ex simplify_simp_lor(const ex & e, const scalar_products & sp);
+
// types
public:
- typedef enum { invalid, // not properly constructed by one of the friend functions
- simp_lor_g,
- simp_lor_vec
- } simp_lor_types;
-
+ typedef enum { invalid, // not properly constructed by one of the friend functions
+ simp_lor_g,
+ simp_lor_vec
+ } simp_lor_types;
+
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- simp_lor();
- ~simp_lor();
- simp_lor(const simp_lor & other);
- const simp_lor & operator=(const simp_lor & other);
+ simp_lor();
+ ~simp_lor();
+ simp_lor(const simp_lor & other);
+ const simp_lor & operator=(const simp_lor & other);
protected:
- void copy(const simp_lor & other);
- void destroy(bool call_parent);
+ void copy(const simp_lor & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
protected:
- simp_lor(simp_lor_types const t);
- simp_lor(simp_lor_types const t, const ex & i1, const ex & i2);
- simp_lor(simp_lor_types const t, const std::string & n, const ex & i1);
- simp_lor(simp_lor_types const t, const std::string & n, const exvector & iv);
- simp_lor(simp_lor_types const t, const std::string & n, exvector * ivp);
-
- // functions overriding virtual functions from base classes
+ simp_lor(simp_lor_types const t);
+ simp_lor(simp_lor_types const t, const ex & i1, const ex & i2);
+ simp_lor(simp_lor_types const t, const std::string & n, const ex & i1);
+ simp_lor(simp_lor_types const t, const std::string & n, const exvector & iv);
+ simp_lor(simp_lor_types const t, const std::string & n, exvector * ivp);
+
+ // functions overriding virtual functions from base classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
- bool info(unsigned inf) const;
- ex eval(int level=0) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ bool info(unsigned inf) const;
+ ex eval(int level=0) const;
protected:
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+ ex thisexprseq(const exvector & v) const;
+ ex thisexprseq(exvector * vp) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
protected:
- bool all_of_type_lorentzidx(void) const;
-
+ bool all_of_type_lorentzidx(void) const;
+
// member variables
protected:
- simp_lor_types type;
- std::string name;
+ simp_lor_types type;
+ std::string name;
};
// global constants
structure::structure()
{
- debugmsg("structure default constructor",LOGLEVEL_CONSTRUCT);
- tinfo_key = TINFO_structure;
+ debugmsg("structure default constructor",LOGLEVEL_CONSTRUCT);
+ tinfo_key = TINFO_structure;
}
structure::~structure()
{
- debugmsg("structure destructor",LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("structure destructor",LOGLEVEL_DESTRUCT);
+ destroy(0);
}
structure::structure(const structure & other)
{
- debugmsg("structure copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("structure copy constructor",LOGLEVEL_CONSTRUCT);
+ copy(other);
}
const structure & structure::operator=(const structure & other)
{
- debugmsg("structure operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(1);
- copy(other);
- }
- return *this;
+ debugmsg("structure operator=",LOGLEVEL_ASSIGNMENT);
+ if (this != &other) {
+ destroy(1);
+ copy(other);
+ }
+ return *this;
}
// protected
void structure::copy(const structure & other)
{
- basic::copy(other);
+ basic::copy(other);
}
void structure::destroy(bool call_parent)
{
- if (call_parent) basic::destroy(call_parent);
+ if (call_parent) basic::destroy(call_parent);
}
//////////
basic * structure::duplicate() const
{
- debugmsg("structure duplicate",LOGLEVEL_DUPLICATE);
- return new structure(*this);
+ debugmsg("structure duplicate",LOGLEVEL_DUPLICATE);
+ return new structure(*this);
}
void structure::printraw(std::ostream & os) const
{
- debugmsg("structure printraw",LOGLEVEL_PRINT);
+ debugmsg("structure printraw",LOGLEVEL_PRINT);
- os << "structure(hash=" << hashvalue << ",flags=" << flags << ")";
+ os << "structure(hash=" << hashvalue << ",flags=" << flags << ")";
}
void structure::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("structure print",LOGLEVEL_PRINT);
+ debugmsg("structure print",LOGLEVEL_PRINT);
- os << "structure()";
+ os << "structure()";
}
void structure::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("structure printtree",LOGLEVEL_PRINT);
+ debugmsg("structure printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << "structure "
- << "hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ os << std::string(indent,' ') << "structure "
+ << "hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void structure::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("structure print csrc",LOGLEVEL_PRINT);
+ debugmsg("structure print csrc",LOGLEVEL_PRINT);
- os << "structure()";
+ os << "structure()";
}
// protected
int structure::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other, structure));
- return 0; // all structures are the same
+ GINAC_ASSERT(is_of_type(other, structure));
+ return 0; // all structures are the same
}
bool structure::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other, structure));
- return true; // all structures are the same
+ GINAC_ASSERT(is_of_type(other, structure));
+ return true; // all structures are the same
}
//////////
std::vector<registered_structure_info> & structure::registered_structures(void)
{
- static std::vector<registered_structure_info> * rs = new std::vector<registered_structure_info>;
- return *rs;
+ static std::vector<registered_structure_info> * rs = new std::vector<registered_structure_info>;
+ return *rs;
}
// public
unsigned structure::register_new(const char * nm)
{
- registered_structure_info rsi={nm};
- registered_structures().push_back(rsi);
- return registered_structures().size()-1;
+ registered_structure_info rsi={nm};
+ registered_structures().push_back(rsi);
+ return registered_structures().size()-1;
}
//////////
#endif // ndef NO_NAMESPACE_GINAC
struct registered_structure_info {
- const char * name;
+ const char * name;
};
/** The class structure is used to implement user defined classes
- with named members which behave similar to ordinary C structs.
- structure is an 'abstract' base class (it is possible but not
- meaningful to make instances), the user defined structures
- will be create by the perl script structure.pl */
+ with named members which behave similar to ordinary C structs.
+ structure is an 'abstract' base class (it is possible but not
+ meaningful to make instances), the user defined structures
+ will be create by the perl script structure.pl */
class structure : public basic
{
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- structure();
- ~structure();
- structure(const structure & other);
- const structure & operator=(const structure & other);
+ structure();
+ ~structure();
+ structure(const structure & other);
+ const structure & operator=(const structure & other);
protected:
- void copy(const structure & other);
- void destroy(bool call_parent);
+ void copy(const structure & other);
+ void destroy(bool call_parent);
- // other constructors
- // none
+ // other constructors
+ // none
- // functions overriding virtual functions from bases classes
+ // functions overriding virtual functions from bases classes
public:
- basic * duplicate() const;
- void printraw(std::ostream & os) const;
- void print(std::ostream & os, unsigned upper_precedence=0) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
+ basic * duplicate() const;
+ void printraw(std::ostream & os) const;
+ void print(std::ostream & os, unsigned upper_precedence=0) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence=0) const;
protected:
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+
+ // new virtual functions which can be overridden by derived classes
+ // none
+
+ // non-virtual functions in this class
protected:
- static std::vector<registered_structure_info> & registered_structures(void);
+ static std::vector<registered_structure_info> & registered_structures(void);
public:
- static unsigned register_new(const char * nm);
+ static unsigned register_new(const char * nm);
// member variables
// none
symbol::symbol() : inherited(TINFO_symbol)
{
- debugmsg("symbol default constructor", LOGLEVEL_CONSTRUCT);
- serial = next_serial++;
- name = autoname_prefix()+ToString(serial);
- asexinfop = new assigned_ex_info;
- setflag(status_flags::evaluated);
+ debugmsg("symbol default constructor", LOGLEVEL_CONSTRUCT);
+ serial = next_serial++;
+ name = autoname_prefix()+ToString(serial);
+ asexinfop = new assigned_ex_info;
+ setflag(status_flags::evaluated);
}
symbol::~symbol()
{
- debugmsg("symbol destructor", LOGLEVEL_DESTRUCT);
- destroy(0);
+ debugmsg("symbol destructor", LOGLEVEL_DESTRUCT);
+ destroy(0);
}
symbol::symbol(const symbol & other)
{
- debugmsg("symbol copy constructor", LOGLEVEL_CONSTRUCT);
- copy(other);
+ debugmsg("symbol copy constructor", LOGLEVEL_CONSTRUCT);
+ copy(other);
}
void symbol::copy(const symbol & other)
{
- inherited::copy(other);
- name = other.name;
- serial = other.serial;
- asexinfop = other.asexinfop;
- ++asexinfop->refcount;
+ inherited::copy(other);
+ name = other.name;
+ serial = other.serial;
+ asexinfop = other.asexinfop;
+ ++asexinfop->refcount;
}
void symbol::destroy(bool call_parent)
{
- if (--asexinfop->refcount == 0) {
- delete asexinfop;
- }
- if (call_parent) {
- inherited::destroy(call_parent);
- }
+ if (--asexinfop->refcount == 0) {
+ delete asexinfop;
+ }
+ if (call_parent) {
+ inherited::destroy(call_parent);
+ }
}
// how should the following be interpreted?
symbol::symbol(const std::string & initname) : inherited(TINFO_symbol)
{
- debugmsg("symbol constructor from string", LOGLEVEL_CONSTRUCT);
- name = initname;
- serial = next_serial++;
- asexinfop = new assigned_ex_info;
- setflag(status_flags::evaluated);
+ debugmsg("symbol constructor from string", LOGLEVEL_CONSTRUCT);
+ name = initname;
+ serial = next_serial++;
+ asexinfop = new assigned_ex_info;
+ setflag(status_flags::evaluated);
}
//////////
/** Construct object from archive_node. */
symbol::symbol(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("symbol constructor from archive_node", LOGLEVEL_CONSTRUCT);
- serial = next_serial++;
- if (!(n.find_string("name", name)))
- name = autoname_prefix() + ToString(serial);
- asexinfop = new assigned_ex_info;
- setflag(status_flags::evaluated);
+ debugmsg("symbol constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ serial = next_serial++;
+ if (!(n.find_string("name", name)))
+ name = autoname_prefix() + ToString(serial);
+ asexinfop = new assigned_ex_info;
+ setflag(status_flags::evaluated);
}
/** Unarchive the object. */
ex symbol::unarchive(const archive_node &n, const lst &sym_lst)
{
- ex s = (new symbol(n, sym_lst))->setflag(status_flags::dynallocated);
+ ex s = (new symbol(n, sym_lst))->setflag(status_flags::dynallocated);
- // If symbol is in sym_lst, return the existing symbol
- for (unsigned i=0; i<sym_lst.nops(); i++) {
- if (is_ex_of_type(sym_lst.op(i), symbol) && (ex_to_symbol(sym_lst.op(i)).name == ex_to_symbol(s).name))
- return sym_lst.op(i);
- }
- return s;
+ // If symbol is in sym_lst, return the existing symbol
+ for (unsigned i=0; i<sym_lst.nops(); i++) {
+ if (is_ex_of_type(sym_lst.op(i), symbol) && (ex_to_symbol(sym_lst.op(i)).name == ex_to_symbol(s).name))
+ return sym_lst.op(i);
+ }
+ return s;
}
/** Archive the object. */
void symbol::archive(archive_node &n) const
{
- inherited::archive(n);
- n.add_string("name", name);
+ inherited::archive(n);
+ n.add_string("name", name);
}
//////////
basic *symbol::duplicate() const
{
- debugmsg("symbol duplicate", LOGLEVEL_DUPLICATE);
- return new symbol(*this);
+ debugmsg("symbol duplicate", LOGLEVEL_DUPLICATE);
+ return new symbol(*this);
}
void symbol::print(std::ostream & os, unsigned upper_precedence) const
{
- debugmsg("symbol print",LOGLEVEL_PRINT);
- os << name;
+ debugmsg("symbol print",LOGLEVEL_PRINT);
+ os << name;
}
void symbol::printraw(std::ostream & os) const
{
- debugmsg("symbol printraw",LOGLEVEL_PRINT);
- os << "symbol(" << "name=" << name << ",serial=" << serial
- << ",hash=" << hashvalue << ",flags=" << flags << ")";
+ debugmsg("symbol printraw",LOGLEVEL_PRINT);
+ os << "symbol(" << "name=" << name << ",serial=" << serial
+ << ",hash=" << hashvalue << ",flags=" << flags << ")";
}
void symbol::printtree(std::ostream & os, unsigned indent) const
{
- debugmsg("symbol printtree",LOGLEVEL_PRINT);
- os << std::string(indent,' ') << name << " (symbol): "
- << "serial=" << serial
- << ", hash=" << hashvalue
- << " (0x" << std::hex << hashvalue << std::dec << ")"
- << ", flags=" << flags << std::endl;
+ debugmsg("symbol printtree",LOGLEVEL_PRINT);
+ os << std::string(indent,' ') << name << " (symbol): "
+ << "serial=" << serial
+ << ", hash=" << hashvalue
+ << " (0x" << std::hex << hashvalue << std::dec << ")"
+ << ", flags=" << flags << std::endl;
}
void symbol::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
{
- debugmsg("symbol print csrc", LOGLEVEL_PRINT);
- os << name;
+ debugmsg("symbol print csrc", LOGLEVEL_PRINT);
+ os << name;
}
bool symbol::info(unsigned inf) const
{
- if (inf==info_flags::symbol) return true;
- if (inf==info_flags::polynomial ||
- inf==info_flags::integer_polynomial ||
- inf==info_flags::cinteger_polynomial ||
- inf==info_flags::rational_polynomial ||
- inf==info_flags::crational_polynomial ||
- inf==info_flags::rational_function) {
- return true;
- } else {
- return inherited::info(inf);
- }
+ if (inf==info_flags::symbol) return true;
+ if (inf==info_flags::polynomial ||
+ inf==info_flags::integer_polynomial ||
+ inf==info_flags::cinteger_polynomial ||
+ inf==info_flags::rational_polynomial ||
+ inf==info_flags::crational_polynomial ||
+ inf==info_flags::rational_function) {
+ return true;
+ } else {
+ return inherited::info(inf);
+ }
}
ex symbol::expand(unsigned options) const
{
- return this->hold();
+ return this->hold();
}
bool symbol::has(const ex & other) const
{
- if (is_equal(*other.bp)) return true;
- return false;
+ if (is_equal(*other.bp)) return true;
+ return false;
}
int symbol::degree(const symbol & s) const
{
- return compare_same_type(s)==0 ? 1 : 0;
+ return compare_same_type(s)==0 ? 1 : 0;
}
int symbol::ldegree(const symbol & s) const
{
- return compare_same_type(s)==0 ? 1 : 0;
+ return compare_same_type(s)==0 ? 1 : 0;
}
ex symbol::coeff(const symbol & s, int n) const
{
- if (compare_same_type(s)==0) {
- return n==1 ? _ex1() : _ex0();
- } else {
- return n==0 ? *this : _ex0();
- }
+ if (compare_same_type(s)==0) {
+ return n==1 ? _ex1() : _ex0();
+ } else {
+ return n==0 ? *this : _ex0();
+ }
}
ex symbol::eval(int level) const
{
- if (level == -max_recursion_level) {
- throw(std::runtime_error("max recursion level reached"));
- }
-
- if (asexinfop->is_assigned) {
- setflag(status_flags::evaluated);
- if (level==1) {
- return (asexinfop->assigned_expression);
- } else {
- return (asexinfop->assigned_expression).eval(level);
- }
- } else {
- return this->hold();
- }
+ if (level == -max_recursion_level) {
+ throw(std::runtime_error("max recursion level reached"));
+ }
+
+ if (asexinfop->is_assigned) {
+ setflag(status_flags::evaluated);
+ if (level==1) {
+ return (asexinfop->assigned_expression);
+ } else {
+ return (asexinfop->assigned_expression).eval(level);
+ }
+ } else {
+ return this->hold();
+ }
}
ex symbol::subs(const lst & ls, const lst & lr) const
{
- GINAC_ASSERT(ls.nops()==lr.nops());
+ GINAC_ASSERT(ls.nops()==lr.nops());
#ifdef DO_GINAC_ASSERT
- for (unsigned i=0; i<ls.nops(); i++) {
- GINAC_ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
- is_ex_of_type(ls.op(i),idx));
- }
+ for (unsigned i=0; i<ls.nops(); i++) {
+ GINAC_ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
+ is_ex_of_type(ls.op(i),idx));
+ }
#endif // def DO_GINAC_ASSERT
- for (unsigned i=0; i<ls.nops(); i++) {
- if (is_ex_exactly_of_type(ls.op(i),symbol)) {
- if (compare_same_type(ex_to_symbol(ls.op(i)))==0) return lr.op(i);
- }
- }
- return *this;
+ for (unsigned i=0; i<ls.nops(); i++) {
+ if (is_ex_exactly_of_type(ls.op(i),symbol)) {
+ if (compare_same_type(ex_to_symbol(ls.op(i)))==0) return lr.op(i);
+ }
+ }
+ return *this;
}
// protected
* @see ex::diff */
ex symbol::derivative(const symbol & s) const
{
- if (compare_same_type(s)) {
- return _ex0();
- } else {
- return _ex1();
- }
+ if (compare_same_type(s)) {
+ return _ex0();
+ } else {
+ return _ex1();
+ }
}
int symbol::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other,symbol));
- const symbol *o = static_cast<const symbol *>(&other);
- if (serial==o->serial) return 0;
- return serial < o->serial ? -1 : 1;
+ GINAC_ASSERT(is_of_type(other,symbol));
+ const symbol *o = static_cast<const symbol *>(&other);
+ if (serial==o->serial) return 0;
+ return serial < o->serial ? -1 : 1;
}
bool symbol::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other,symbol));
- const symbol *o = static_cast<const symbol *>(&other);
- return serial==o->serial;
+ GINAC_ASSERT(is_of_type(other,symbol));
+ const symbol *o = static_cast<const symbol *>(&other);
+ return serial==o->serial;
}
unsigned symbol::return_type(void) const
{
- return return_types::commutative;
+ return return_types::commutative;
}
unsigned symbol::return_type_tinfo(void) const
{
- return tinfo_key;
+ return tinfo_key;
}
unsigned symbol::calchash(void) const
{
- // return golden_ratio_hash(tinfo()) ^ serial;
- hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555555U ^ serial));
- setflag(status_flags::hash_calculated);
- return hashvalue;
+ // return golden_ratio_hash(tinfo()) ^ serial;
+ hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555555U ^ serial));
+ setflag(status_flags::hash_calculated);
+ return hashvalue;
}
//////////
void symbol::assign(const ex & value)
{
- asexinfop->is_assigned=1;
- asexinfop->assigned_expression=value;
- clearflag(status_flags::evaluated);
+ asexinfop->is_assigned=1;
+ asexinfop->assigned_expression=value;
+ clearflag(status_flags::evaluated);
}
void symbol::unassign(void)
{
- if (asexinfop->is_assigned) {
- asexinfop->is_assigned=0;
- asexinfop->assigned_expression=_ex0();
- }
- setflag(status_flags::evaluated);
+ if (asexinfop->is_assigned) {
+ asexinfop->is_assigned=0;
+ asexinfop->assigned_expression=_ex0();
+ }
+ setflag(status_flags::evaluated);
}
// private
std::string & symbol::autoname_prefix(void)
{
- static std::string * s=new std::string("symbol");
- return *s;
+ static std::string * s=new std::string("symbol");
+ return *s;
}
//////////
* first place. */
class symbol : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS(symbol, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(symbol, basic)
// types
- /** Symbols as keys to expressions. */
- class assigned_ex_info {
- public:
- assigned_ex_info(); //!< Default ctor
- bool is_assigned; //!< True if there is an expression assigned
- ex assigned_expression; //!< The actual expression
- unsigned refcount; //!< Yet another refcounter. PLEASE EXPLAIN!
- };
-
+ /** Symbols as keys to expressions. */
+ class assigned_ex_info {
+ public:
+ assigned_ex_info(); //!< Default ctor
+ bool is_assigned; //!< True if there is an expression assigned
+ ex assigned_expression; //!< The actual expression
+ unsigned refcount; //!< Yet another refcounter. PLEASE EXPLAIN!
+ };
+
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
+ // default constructor, destructor, copy constructor assignment operator and helpers
public:
- symbol();
- ~symbol();
- symbol(const symbol & other);
+ symbol();
+ ~symbol();
+ symbol(const symbol & other);
protected:
- void copy(const symbol & other);
- void destroy(bool call_parent);
+ void copy(const symbol & other);
+ void destroy(bool call_parent);
- // other constructors
+ // other constructors
public:
- explicit symbol(const std::string & initname);
+ explicit symbol(const std::string & initname);
- // functions overriding virtual functions from base classes
+ // functions overriding virtual functions from base classes
public:
- basic * duplicate() const;
- void print(std::ostream & os, unsigned upper_precedence = 0) const;
- void printraw(std::ostream & os) const;
- void printtree(std::ostream & os, unsigned indent) const;
- void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence = 0) const;
- bool info(unsigned inf) const;
- ex expand(unsigned options = 0) const;
- bool has(const ex & other) const;
- int degree(const symbol & s) const;
- int ldegree(const symbol & s) const;
- ex coeff(const symbol & s, int n = 1) const;
- ex eval(int level = 0) const;
- ex series(const relational & s, int order, unsigned options = 0) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
- ex to_rational(lst &repl_lst) const;
- ex subs(const lst & ls, const lst & lr) const;
+ basic * duplicate() const;
+ void print(std::ostream & os, unsigned upper_precedence = 0) const;
+ void printraw(std::ostream & os) const;
+ void printtree(std::ostream & os, unsigned indent) const;
+ void printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence = 0) const;
+ bool info(unsigned inf) const;
+ ex expand(unsigned options = 0) const;
+ bool has(const ex & other) const;
+ int degree(const symbol & s) const;
+ int ldegree(const symbol & s) const;
+ ex coeff(const symbol & s, int n = 1) const;
+ ex eval(int level = 0) const;
+ ex series(const relational & s, int order, unsigned options = 0) const;
+ ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
+ ex to_rational(lst &repl_lst) const;
+ ex subs(const lst & ls, const lst & lr) const;
protected:
- ex derivative(const symbol & s) const;
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- unsigned calchash(void) const;
-
- // non-virtual functions in this class
+ ex derivative(const symbol & s) const;
+ int compare_same_type(const basic & other) const;
+ bool is_equal_same_type(const basic & other) const;
+ unsigned return_type(void) const;
+ unsigned return_type_tinfo(void) const;
+ unsigned calchash(void) const;
+
+ // non-virtual functions in this class
public:
- void assign(const ex & value);
- void unassign(void);
- void setname(const std::string & n) { name = n; }
- std::string getname(void) const { return name; }
+ void assign(const ex & value);
+ void unassign(void);
+ void setname(const std::string & n) { name = n; }
+ std::string getname(void) const { return name; }
private:
- std::string & autoname_prefix(void);
+ std::string & autoname_prefix(void);
// member variables
protected:
- assigned_ex_info * asexinfop;
- unsigned serial; //!< unique serial number for comparision
- std::string name;
+ assigned_ex_info * asexinfop;
+ unsigned serial; //!< unique serial number for comparision
+ std::string name;
private:
- static unsigned next_serial;
+ static unsigned next_serial;
};
// global constants
/** ctor for pole_error exception class. */
pole_error::pole_error(const std::string& what_arg, int degree)
- : domain_error(what_arg)
+ : domain_error(what_arg)
{
- deg = degree;
+ deg = degree;
}
/** Return the degree of the pole_error exception class. */
int pole_error::degree(void) const
{
- return deg;
+ return deg;
}
// some compilers (e.g. cygwin) define a macro log2, causing confusion
/** Integer binary logarithm */
unsigned log2(unsigned n)
{
- unsigned k;
- for (k = 0; n > 1; n >>= 1) ++k;
- return k;
+ unsigned k;
+ for (k = 0; n > 1; n >>= 1) ++k;
+ return k;
}
#endif
* @return -1, 0, or 1 */
int compare_pointers(const void * a, const void * b)
{
- if (a<b) {
- return -1;
- } else if (a>b) {
- return 1;
- }
- return 0;
+ if (a<b) {
+ return -1;
+ } else if (a>b) {
+ return 1;
+ }
+ return 0;
}
//////////
// numeric -120
const numeric & _num_120(void)
{
- const static ex e = ex(numeric(-120));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-120));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_120(void)
{
- static ex * e = new ex(_num_120());
- return *e;
+ static ex * e = new ex(_num_120());
+ return *e;
}
// numeric -60
const numeric & _num_60(void)
{
- const static ex e = ex(numeric(-60));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-60));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_60(void)
{
- static ex * e = new ex(_num_60());
- return *e;
+ static ex * e = new ex(_num_60());
+ return *e;
}
// numeric -48
const numeric & _num_48(void)
{
- const static ex e = ex(numeric(-48));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-48));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_48(void)
{
- static ex * e = new ex(_num_48());
- return *e;
+ static ex * e = new ex(_num_48());
+ return *e;
}
// numeric -30
const numeric & _num_30(void)
{
- const static ex e = ex(numeric(-30));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-30));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_30(void)
{
- static ex * e = new ex(_num_30());
- return *e;
+ static ex * e = new ex(_num_30());
+ return *e;
}
// numeric -25
const numeric & _num_25(void)
{
- const static ex e = ex(numeric(-25));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-25));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_25(void)
{
- static ex * e = new ex(_num_25());
- return *e;
+ static ex * e = new ex(_num_25());
+ return *e;
}
// numeric -24
const numeric & _num_24(void)
{
- const static ex e = ex(numeric(-24));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-24));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_24(void)
{
- static ex * e = new ex(_num_24());
- return *e;
+ static ex * e = new ex(_num_24());
+ return *e;
}
// numeric -20
const numeric & _num_20(void)
{
- const static ex e = ex(numeric(-20));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-20));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_20(void)
{
- static ex * e = new ex(_num_20());
- return *e;
+ static ex * e = new ex(_num_20());
+ return *e;
}
// numeric -18
const numeric & _num_18(void)
{
- const static ex e = ex(numeric(-18));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-18));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_18(void)
{
- static ex * e = new ex(_num_18());
- return *e;
+ static ex * e = new ex(_num_18());
+ return *e;
}
// numeric -15
const numeric & _num_15(void)
{
- const static ex e = ex(numeric(-15));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-15));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_15(void)
{
- static ex * e = new ex(_num_15());
- return *e;
+ static ex * e = new ex(_num_15());
+ return *e;
}
// numeric -12
const numeric & _num_12(void)
{
- const static ex e = ex(numeric(-12));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-12));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_12(void)
{
- static ex * e = new ex(_num_12());
- return *e;
+ static ex * e = new ex(_num_12());
+ return *e;
}
// numeric -11
const numeric & _num_11(void)
{
- const static ex e = ex(numeric(-11));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-11));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_11(void)
{
- static ex * e = new ex(_num_11());
- return *e;
+ static ex * e = new ex(_num_11());
+ return *e;
}
// numeric -10
const numeric & _num_10(void)
{
- const static ex e = ex(numeric(-10));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-10));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_10(void)
{
- static ex * e = new ex(_num_10());
- return *e;
+ static ex * e = new ex(_num_10());
+ return *e;
}
// numeric -9
const numeric & _num_9(void)
{
- const static ex e = ex(numeric(-9));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-9));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_9(void)
{
- static ex * e = new ex(_num_9());
- return *e;
+ static ex * e = new ex(_num_9());
+ return *e;
}
// numeric -8
const numeric & _num_8(void)
{
- const static ex e = ex(numeric(-8));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-8));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_8(void)
{
- static ex * e = new ex(_num_8());
- return *e;
+ static ex * e = new ex(_num_8());
+ return *e;
}
// numeric -7
const numeric & _num_7(void)
{
- const static ex e = ex(numeric(-7));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-7));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_7(void)
{
- static ex * e = new ex(_num_7());
- return *e;
+ static ex * e = new ex(_num_7());
+ return *e;
}
// numeric -6
const numeric & _num_6(void)
{
- const static ex e = ex(numeric(-6));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-6));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_6(void)
{
- static ex * e = new ex(_num_6());
- return *e;
+ static ex * e = new ex(_num_6());
+ return *e;
}
// numeric -5
const numeric & _num_5(void)
{
- const static ex e = ex(numeric(-5));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-5));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_5(void)
{
- static ex * e = new ex(_num_5());
- return *e;
+ static ex * e = new ex(_num_5());
+ return *e;
}
// numeric -4
const numeric & _num_4(void)
{
- const static ex e = ex(numeric(-4));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-4));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_4(void)
{
- static ex * e = new ex(_num_4());
- return *e;
+ static ex * e = new ex(_num_4());
+ return *e;
}
// numeric -3
const numeric & _num_3(void)
{
- const static ex e = ex(numeric(-3));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-3));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_3(void)
{
- static ex * e = new ex(_num_3());
- return *e;
+ static ex * e = new ex(_num_3());
+ return *e;
}
// numeric -2
const numeric & _num_2(void)
{
- const static ex e = ex(numeric(-2));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-2));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_2(void)
{
- static ex * e = new ex(_num_2());
- return *e;
+ static ex * e = new ex(_num_2());
+ return *e;
}
// numeric -1
const numeric & _num_1(void)
{
- const static ex e = ex(numeric(-1));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-1));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_1(void)
{
- static ex * e = new ex(_num_1());
- return *e;
+ static ex * e = new ex(_num_1());
+ return *e;
}
// numeric -1/2
const numeric & _num_1_2(void)
{
- const static ex e = ex(numeric(-1,2));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-1,2));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_1_2(void)
{
- static ex * e = new ex(_num_1_2());
- return *e;
+ static ex * e = new ex(_num_1_2());
+ return *e;
}
// numeric -1/3
const numeric & _num_1_3(void)
{
- const static ex e = ex(numeric(-1,3));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-1,3));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_1_3(void)
{
- static ex * e = new ex(_num_1_3());
- return *e;
+ static ex * e = new ex(_num_1_3());
+ return *e;
}
// numeric -1/4
const numeric & _num_1_4(void)
{
- const static ex e = ex(numeric(-1,4));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(-1,4));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex_1_4(void)
{
- static ex * e = new ex(_num_1_4());
- return *e;
+ static ex * e = new ex(_num_1_4());
+ return *e;
}
// numeric 0
const numeric & _num0(void)
{
- const static ex e = ex(numeric(0));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(0));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex0(void)
{
- static ex * e = new ex(_num0());
- return *e;
+ static ex * e = new ex(_num0());
+ return *e;
}
// numeric 1/4
const numeric & _num1_4(void)
{
- const static ex e = ex(numeric(1,4));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(1,4));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex1_4(void)
{
- static ex * e = new ex(_num1_4());
- return *e;
+ static ex * e = new ex(_num1_4());
+ return *e;
}
// numeric 1/3
const numeric & _num1_3(void)
{
- const static ex e = ex(numeric(1,3));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(1,3));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex1_3(void)
{
- static ex * e = new ex(_num1_3());
- return *e;
+ static ex * e = new ex(_num1_3());
+ return *e;
}
// numeric 1/2
const numeric & _num1_2(void)
{
- const static ex e = ex(numeric(1,2));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(1,2));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex1_2(void)
{
- static ex * e = new ex(_num1_2());
- return *e;
+ static ex * e = new ex(_num1_2());
+ return *e;
}
// numeric 1
const numeric & _num1(void)
{
- const static ex e = ex(numeric(1));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(1));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex1(void)
{
- static ex * e = new ex(_num1());
- return *e;
+ static ex * e = new ex(_num1());
+ return *e;
}
// numeric 2
const numeric & _num2(void)
{
- const static ex e = ex(numeric(2));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(2));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex2(void)
{
- static ex * e = new ex(_num2());
- return *e;
+ static ex * e = new ex(_num2());
+ return *e;
}
// numeric 3
const numeric & _num3(void)
{
- const static ex e = ex(numeric(3));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(3));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex3(void)
{
- static ex * e = new ex(_num3());
- return *e;
+ static ex * e = new ex(_num3());
+ return *e;
}
// numeric 4
const numeric & _num4(void)
{
- const static ex e = ex(numeric(4));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(4));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex4(void)
{
- static ex * e = new ex(_num4());
- return *e;
+ static ex * e = new ex(_num4());
+ return *e;
}
// numeric 5
const numeric & _num5(void)
{
- const static ex e = ex(numeric(5));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(5));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex5(void)
{
- static ex * e = new ex(_num5());
- return *e;
+ static ex * e = new ex(_num5());
+ return *e;
}
// numeric 6
const numeric & _num6(void)
{
- const static ex e = ex(numeric(6));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(6));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex6(void)
{
- static ex * e = new ex(_num6());
- return *e;
+ static ex * e = new ex(_num6());
+ return *e;
}
// numeric 7
const numeric & _num7(void)
{
- const static ex e = ex(numeric(7));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(7));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex7(void)
{
- static ex * e = new ex(_num7());
- return *e;
+ static ex * e = new ex(_num7());
+ return *e;
}
// numeric 8
const numeric & _num8(void)
{
- const static ex e = ex(numeric(8));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(8));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex8(void)
{
- static ex * e = new ex(_num8());
- return *e;
+ static ex * e = new ex(_num8());
+ return *e;
}
// numeric 9
const numeric & _num9(void)
{
- const static ex e = ex(numeric(9));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(9));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex9(void)
{
- static ex * e = new ex(_num9());
- return *e;
+ static ex * e = new ex(_num9());
+ return *e;
}
// numeric 10
const numeric & _num10(void)
{
- const static ex e = ex(numeric(10));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(10));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex10(void)
{
- static ex * e = new ex(_num10());
- return *e;
+ static ex * e = new ex(_num10());
+ return *e;
}
// numeric 11
const numeric & _num11(void)
{
- const static ex e = ex(numeric(11));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(11));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex11(void)
{
- static ex * e = new ex(_num11());
- return *e;
+ static ex * e = new ex(_num11());
+ return *e;
}
// numeric 12
const numeric & _num12(void)
{
- const static ex e = ex(numeric(12));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(12));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex12(void)
{
- static ex * e = new ex(_num12());
- return *e;
+ static ex * e = new ex(_num12());
+ return *e;
}
// numeric 15
const numeric & _num15(void)
{
- const static ex e = ex(numeric(15));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(15));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex15(void)
{
- static ex * e = new ex(_num15());
- return *e;
+ static ex * e = new ex(_num15());
+ return *e;
}
// numeric 18
const numeric & _num18(void)
{
- const static ex e = ex(numeric(18));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(18));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex18(void)
{
- static ex * e = new ex(_num18());
- return *e;
+ static ex * e = new ex(_num18());
+ return *e;
}
// numeric 20
const numeric & _num20(void)
{
- const static ex e = ex(numeric(20));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(20));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex20(void)
{
- static ex * e = new ex(_num20());
- return *e;
+ static ex * e = new ex(_num20());
+ return *e;
}
// numeric 24
const numeric & _num24(void)
{
- const static ex e = ex(numeric(24));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(24));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex24(void)
{
- static ex * e = new ex(_num24());
- return *e;
+ static ex * e = new ex(_num24());
+ return *e;
}
// numeric 25
const numeric & _num25(void)
{
- const static ex e = ex(numeric(25));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(25));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex25(void)
{
- static ex * e = new ex(_num25());
- return *e;
+ static ex * e = new ex(_num25());
+ return *e;
}
// numeric 30
const numeric & _num30(void)
{
- const static ex e = ex(numeric(30));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(30));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex30(void)
{
- static ex * e = new ex(_num30());
- return *e;
+ static ex * e = new ex(_num30());
+ return *e;
}
// numeric 48
const numeric & _num48(void)
{
- const static ex e = ex(numeric(48));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(48));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex48(void)
{
- static ex * e = new ex(_num48());
- return *e;
+ static ex * e = new ex(_num48());
+ return *e;
}
// numeric 60
const numeric & _num60(void)
{
- const static ex e = ex(numeric(60));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(60));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex60(void)
{
- static ex * e = new ex(_num60());
- return *e;
+ static ex * e = new ex(_num60());
+ return *e;
}
// numeric 120
const numeric & _num120(void)
{
- const static ex e = ex(numeric(120));
- const static numeric * n = static_cast<const numeric *>(e.bp);
- return *n;
+ const static ex e = ex(numeric(120));
+ const static numeric * n = static_cast<const numeric *>(e.bp);
+ return *n;
}
const ex & _ex120(void)
{
- static ex * e = new ex(_num120());
- return *e;
+ static ex * e = new ex(_num120());
+ return *e;
}
// comment skeleton for header files
// member functions
- // default constructor, destructor, copy constructor assignment operator and helpers
- // none
+ // default constructor, destructor, copy constructor assignment operator and helpers
+ // none
- // other constructors
- // none
+ // other constructors
+ // none
- // functions overriding virtual functions from bases classes
- // none
-
- // new virtual functions which can be overridden by derived classes
- // none
+ // functions overriding virtual functions from bases classes
+ // none
+
+ // new virtual functions which can be overridden by derived classes
+ // none
- // non-virtual functions in this class
- // none
+ // non-virtual functions in this class
+ // none
// member variables
// none
-
+
// comment skeleton for implementation files
template<class T>
std::string ToString(const T & t)
{
- char buf[256];
- std::ostrstream(buf,sizeof(buf)) << t << std::ends;
- return buf;
+ char buf[256];
+ std::ostrstream(buf,sizeof(buf)) << t << std::ends;
+ return buf;
}
/** Exception class thrown by classes which provide their own series expansion
/** Exception class thrown when a singularity is encountered. */
class pole_error : public std::domain_error {
public:
- explicit pole_error(const std::string& what_arg, int degree);
- int degree(void) const;
+ explicit pole_error(const std::string& what_arg, int degree);
+ int degree(void) const;
private:
- int deg;
+ int deg;
};
// some compilers (e.g. cygwin) define a macro log2, causing confusion
* (upper bits get cleared). */
inline unsigned rotate_left_31(unsigned n)
{
- // clear highest bit and shift 1 bit to the left
- n=(n & 0x7FFFFFFFU) << 1;
+ // clear highest bit and shift 1 bit to the left
+ n=(n & 0x7FFFFFFFU) << 1;
- // overflow? clear highest bit and set lowest bit
- if (n & 0x80000000U) {
- n=(n & 0x7FFFFFFFU) | 0x00000001U;
- }
- GINAC_ASSERT(n<0x80000000U);
+ // overflow? clear highest bit and set lowest bit
+ if (n & 0x80000000U) {
+ n=(n & 0x7FFFFFFFU) | 0x00000001U;
+ }
+ GINAC_ASSERT(n<0x80000000U);
- return n;
+ return n;
}
/** Golden ratio hash function. */
#if SIZEOF_LONG_DOUBLE > 8
// If "long double" is bigger than 64 bits, we assume that the mantissa
// has at least 64 bits. This is not guaranteed but it's a good guess.
- const static long double golden_ratio = .618033988749894848204586834370;
- long double m = golden_ratio * n;
- return unsigned((m - int(m)) * 0x80000000);
+ const static long double golden_ratio = .618033988749894848204586834370;
+ long double m = golden_ratio * n;
+ return unsigned((m - int(m)) * 0x80000000);
#elif SIZEOF_LONG >= 8
// "long" has 64 bits, so we prefer it because it might be more efficient
// than "long long"
return (l & 0x7fffffffU) ^ (l >> 32);
#elif SIZEOF_LONG_LONG >= 8
// This requires ´long long´ (or an equivalent 64 bit type)---which is,
- // unfortunately, not ANSI-compliant:
+ // unfortunately, not ANSI-compliant:
unsigned long long l = n * 0x4f1bbcddLL;
return (l & 0x7fffffffU) ^ (l >> 32);
#else
// modified from stl_algo.h: always do com(*first1,*first2) instead of comp(*first2,*first1)
template <class InputIterator1, class InputIterator2, class OutputIterator,
- class Compare>
+ class Compare>
OutputIterator mymerge(InputIterator1 first1, InputIterator1 last1,
- InputIterator2 first2, InputIterator2 last2,
- OutputIterator result, Compare comp) {
- while (first1 != last1 && first2 != last2) {
- if (comp(*first1, *first2)) {
- *result = *first1;
- ++first1;
- }
- else {
- *result = *first2;
- ++first2;
- }
- ++result;
- }
- return copy(first2, last2, copy(first1, last1, result));
+ InputIterator2 first2, InputIterator2 last2,
+ OutputIterator result, Compare comp) {
+ while (first1 != last1 && first2 != last2) {
+ if (comp(*first1, *first2)) {
+ *result = *first1;
+ ++first1;
+ }
+ else {
+ *result = *first2;
+ ++first2;
+ }
+ ++result;
+ }
+ return copy(first2, last2, copy(first1, last1, result));
}
// like merge(), but three lists with *last2<*first3
template <class InputIterator1, class InputIterator2, class InputIterator3,
- class OutputIterator, class Compare>
+ class OutputIterator, class Compare>
OutputIterator mymerge3(InputIterator1 first1, InputIterator1 last1,
- InputIterator2 first2, InputIterator2 last2,
- InputIterator3 first3, InputIterator3 last3,
- OutputIterator result, Compare comp) {
- while (first1 != last1 && first2 != last2) {
- if (comp(*first1, *first2)) {
- *result = *first1;
- ++first1;
- }
- else {
- *result = *first2;
- ++first2;
- }
- ++result;
- }
-
- if (first1==last1) {
- // list1 empty, copy rest of list2, then list3
- return copy(first3, last3, copy(first2, last2, result));
- } else {
- // list2 empty, merge rest of list1 with list3
- return mymerge(first1,last1,first3,last3,result,comp);
- }
+ InputIterator2 first2, InputIterator2 last2,
+ InputIterator3 first3, InputIterator3 last3,
+ OutputIterator result, Compare comp) {
+ while (first1 != last1 && first2 != last2) {
+ if (comp(*first1, *first2)) {
+ *result = *first1;
+ ++first1;
+ }
+ else {
+ *result = *first2;
+ ++first2;
+ }
+ ++result;
+ }
+
+ if (first1==last1) {
+ // list1 empty, copy rest of list2, then list3
+ return copy(first3, last3, copy(first2, last2, result));
+ } else {
+ // list2 empty, merge rest of list1 with list3
+ return mymerge(first1,last1,first3,last3,result,comp);
+ }
}
// Compute the sign of a permutation of a vector of things.
template <typename T>
int permutation_sign(std::vector<T> s)
{
- if (s.size() < 2)
- return 0;
- int sigma = 1;
- for (typename std::vector<T>::iterator i=s.begin(); i!=s.end()-1; ++i) {
- for (typename std::vector<T>::iterator j=i+1; j!=s.end(); ++j) {
- if (*i == *j)
- return 0;
- if (*i > *j) {
- iter_swap(i,j);
- sigma = -sigma;
- }
- }
- }
- return sigma;
+ if (s.size() < 2)
+ return 0;
+ int sigma = 1;
+ for (typename std::vector<T>::iterator i=s.begin(); i!=s.end()-1; ++i) {
+ for (typename std::vector<T>::iterator j=i+1; j!=s.end(); ++j) {
+ if (*i == *j)
+ return 0;
+ if (*i > *j) {
+ iter_swap(i,j);
+ sigma = -sigma;
+ }
+ }
+ }
+ return sigma;
}
// Collection of `construct on first use' wrappers for safely avoiding