X-Git-Url: https://ginac.de/ginac.git//ginac.git?a=blobdiff_plain;f=ginac%2Fbasic.cpp;h=83b777bbf9f8fc8c2592d5c34eea54a19aad2581;hb=0d9b6e6d134917a8fb5cf76ade55dcbaf01acb28;hp=a8f2baa02b2f532d83b073b091416a306a2ecb91;hpb=15d4b353c85f8815a95d97ab977c9ca48e155574;p=ginac.git diff --git a/ginac/basic.cpp b/ginac/basic.cpp index a8f2baa0..83b777bb 100644 --- a/ginac/basic.cpp +++ b/ginac/basic.cpp @@ -31,12 +31,15 @@ #include "symbol.h" #include "lst.h" #include "ncmul.h" +#include "archive.h" #include "utils.h" #include "debugmsg.h" -#ifndef NO_GINAC_NAMESPACE +#ifndef NO_NAMESPACE_GINAC namespace GiNaC { -#endif // ndef NO_GINAC_NAMESPACE +#endif // ndef NO_NAMESPACE_GINAC + +GINAC_IMPLEMENT_REGISTERED_CLASS(basic, void) ////////// // default constructor, destructor, copy constructor assignment operator and helpers @@ -47,27 +50,27 @@ namespace GiNaC { #ifndef INLINE_BASIC_CONSTRUCTORS basic::basic() : flags(0), refcount(0), tinfo_key(TINFO_BASIC) { - debugmsg("basic default constructor",LOGLEVEL_CONSTRUCT); + debugmsg("basic default constructor", LOGLEVEL_CONSTRUCT); // nothing to do } basic::~basic() { - debugmsg("basic destructor",LOGLEVEL_DESTRUCT); + debugmsg("basic destructor", LOGLEVEL_DESTRUCT); destroy(0); GINAC_ASSERT((!(flags & status_flags::dynallocated))||(refcount==0)); } -basic::basic(basic const & other) : flags(0), refcount(0), tinfo_key(TINFO_BASIC) +basic::basic(const basic & other) : flags(0), refcount(0), tinfo_key(TINFO_BASIC) { - debugmsg("basic copy constructor",LOGLEVEL_CONSTRUCT); + debugmsg("basic copy constructor", LOGLEVEL_CONSTRUCT); copy(other); } #endif -basic const & basic::operator=(basic const & other) +const basic & basic::operator=(const basic & other) { - debugmsg("basic operator=",LOGLEVEL_ASSIGNMENT); + debugmsg("basic operator=", LOGLEVEL_ASSIGNMENT); if (this != &other) { destroy(1); copy(other); @@ -77,14 +80,7 @@ basic const & basic::operator=(basic const & other) // protected -#if 0 -void basic::copy(basic const & other) -{ - flags=other.flags & ~ status_flags::dynallocated; - hashvalue=other.hashvalue; - tinfo_key=other.tinfo_key; -} -#endif +// none (all inlined) ////////// // other constructors @@ -93,11 +89,40 @@ void basic::copy(basic const & other) #ifndef INLINE_BASIC_CONSTRUCTORS basic::basic(unsigned ti) : flags(0), refcount(0), tinfo_key(ti) { - debugmsg("basic constructor with tinfo_key",LOGLEVEL_CONSTRUCT); + debugmsg("basic constructor with tinfo_key", LOGLEVEL_CONSTRUCT); // nothing to do } #endif +////////// +// archiving +////////// + +/** 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); + + // Reconstruct tinfo_key from class name + 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); +} + +/** Archive the object. */ +void basic::archive(archive_node &n) const +{ + n.add_string("class", class_name()); +} + ////////// // functions overriding virtual functions from bases classes ////////// @@ -169,40 +194,51 @@ basic * basic::duplicate() const 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 } +/** 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; } -ex basic::op(int const i) const +/** Return operand/member at position i. */ +ex basic::op(int i) const { return (const_cast(this))->let_op(i); } -ex & basic::let_op(int const i) +/** Return modifyable operand/member at position i. */ +ex & basic::let_op(int i) { throw(std::out_of_range("op() out of range")); } -ex basic::operator[](ex const & index) const +ex basic::operator[](const ex & index) const { - if (is_exactly_of_type(*index.bp,numeric)) { - return op(static_cast(*index.bp).to_int()); - } + if (is_exactly_of_type(*index.bp,numeric)) + return op(static_cast(*index.bp).to_int()); + throw(std::invalid_argument("non-numeric indices not supported by this type")); } -ex basic::operator[](int const i) const +ex basic::operator[](int i) const { return op(i); } -bool basic::has(ex const & other) const +/** 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; @@ -214,65 +250,115 @@ bool basic::has(ex const & other) const return false; } -int basic::degree(symbol const & s) const +/** Return degree of highest power in symbol s. */ +int basic::degree(const symbol & s) const { return 0; } -int basic::ldegree(symbol const & s) const +/** Return degree of lowest power in symbol s. */ +int basic::ldegree(const symbol & s) const { return 0; } -ex basic::coeff(symbol const & s, int const n) const +/** Return coefficient of degree n in symbol s. */ +ex basic::coeff(const symbol & s, int n) const { return n==0 ? *this : _ex0(); } -ex basic::collect(symbol const & s) const +/** 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=ldegree(s); - int deg=degree(s); + int ldeg = this->ldegree(s); + int deg = this->degree(s); for (int n=ldeg; n<=deg; n++) { - x += coeff(s,n)*power(s,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(); } +/** Evaluate object numerically. */ ex basic::evalf(int level) const { + // There is nothing to do for basic objects: return *this; } -ex basic::subs(lst const & ls, lst const & lr) const +/* Substitute a set of symbols. */ +ex basic::subs(const lst & ls, const lst & lr) const { return *this; } +/** Default interface of nth derivative ex::diff(s, n). It should be called + * instead of ::derivative(s) for first derivatives and for nth derivatives it + * just recurses down. + * + * @param s symbol to differentiate in + * @param nth order of differentiation + * @see ex::diff */ +ex basic::diff(const symbol & s, unsigned nth) const +{ + // trivial: zeroth derivative + if (!nth) + return ex(*this); + + // evaluate unevaluated *this before differentiating + if (!(flags & status_flags::evaluated)) + return ex(*this).diff(s, nth); + + ex ndiff = 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 } -ex basic::simplify_ncmul(exvector const & v) const +ex basic::simplify_ncmul(const exvector & v) const { return simplified_ncmul(v); } // protected -int basic::compare_same_type(basic const & other) const +/** Default implementation of ex::diff(). It simply throws an error message. + * + * @exception logic_error (differentiation not supported by this type) + * @see ex::diff */ +ex basic::derivative(const symbol & s) const +{ + 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); } -bool basic::is_equal_same_type(basic const & other) const +/** Returns true if two objects of same type are equal. Normally needs + * not be reimplemented as long as it wasn't overwritten by some parent + * class, since it just calls complare_same_type(). */ +bool basic::is_equal_same_type(const basic & other) const { return compare_same_type(other)==0; } @@ -292,7 +378,7 @@ unsigned basic::calchash(void) const unsigned v=golden_ratio_hash(tinfo()); for (unsigned i=0; i(this))->let_op(i).gethash(); + v ^= (const_cast(this))->op(i).gethash(); } v = v & 0x7FFFFFFFU; @@ -306,24 +392,27 @@ unsigned basic::calchash(void) const 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); } + ////////// // non-virtual functions in this class ////////// // public -ex basic::subs(ex const & e) const +/** Substitute symbols in expression and return the result as a new expression. + * There are two valid types of replacement arguments: 1) a relational like + * symbol==ex and 2) a list of relationals lst(symbol1==ex1,symbol2==ex2,...), + * which is converted to subs(lst(symbol1,symbol2,...),lst(ex1,ex2,...)). + * In addition, an object of class idx can be used instead of a symbol. */ +ex basic::subs(const ex & e) const { - // accept 2 types of replacement expressions: - // - symbol==ex - // - lst(symbol1==ex1,symbol2==ex2,...) - // convert to subs(lst(symbol1,symbol2,...),lst(ex1,ex2,...)) - // additionally, idx can be used instead of symbol if (e.info(info_flags::relation_equal)) { return subs(lst(e)); } @@ -350,7 +439,7 @@ ex basic::subs(ex const & e) const /** Compare objects to establish canonical order. * All compare functions return: -1 for *this less than other, 0 equal, * 1 greater. */ -int basic::compare(basic const & other) const +int basic::compare(const basic & other) const { unsigned hash_this = gethash(); unsigned hash_other = other.gethash(); @@ -400,7 +489,8 @@ int basic::compare(basic const & other) const return cmpval; } -bool basic::is_equal(basic const & other) const +/** Test for equality. */ +bool basic::is_equal(const basic & other) const { unsigned hash_this = gethash(); unsigned hash_other = other.gethash(); @@ -419,7 +509,9 @@ bool basic::is_equal(basic const & other) const // protected -basic const & basic::hold(void) const +/** Stop further evaluation. + * @see basic::eval */ +const basic & basic::hold(void) const { return setflag(status_flags::evaluated); } @@ -437,15 +529,15 @@ void basic::ensure_if_modifiable(void) const // protected -unsigned basic::precedence=70; -unsigned basic::delta_indent=4; +unsigned basic::precedence = 70; +unsigned basic::delta_indent = 4; ////////// // global constants ////////// const basic some_basic; -type_info const & typeid_basic=typeid(some_basic); +const type_info & typeid_basic=typeid(some_basic); ////////// // global variables @@ -453,6 +545,6 @@ type_info const & typeid_basic=typeid(some_basic); int max_recursion_level=1024; -#ifndef NO_GINAC_NAMESPACE +#ifndef NO_NAMESPACE_GINAC } // namespace GiNaC -#endif // ndef NO_GINAC_NAMESPACE +#endif // ndef NO_NAMESPACE_GINAC