X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fbasic.cpp;h=fb73096fa70a4796e301ade46306d53849d25068;hp=eb8e8ca90605c12d7a84f0ed4608353293acfcb8;hb=e93f20fd0deb9b45d2163cbec247e5181f021a28;hpb=f1637dceefe0fbf79308958f8bc28dedd38aab85 diff --git a/ginac/basic.cpp b/ginac/basic.cpp index eb8e8ca9..fb73096f 100644 --- a/ginac/basic.cpp +++ b/ginac/basic.cpp @@ -3,7 +3,7 @@ * Implementation of GiNaC's ABC. */ /* - * GiNaC Copyright (C) 1999-2001 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2002 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,30 +34,28 @@ #include "lst.h" #include "ncmul.h" #include "relational.h" +#include "wildcard.h" #include "print.h" #include "archive.h" #include "utils.h" -#include "debugmsg.h" namespace GiNaC { GINAC_IMPLEMENT_REGISTERED_CLASS_NO_CTORS(basic, void) ////////// -// default ctor, dtor, copy ctor assignment operator and helpers +// default ctor, dtor, copy ctor, assignment operator and helpers ////////// // public basic::basic(const basic & other) : tinfo_key(TINFO_basic), flags(0), refcount(0) { - debugmsg("basic copy ctor", LOGLEVEL_CONSTRUCT); copy(other); } const basic & basic::operator=(const basic & other) { - debugmsg("basic operator=", LOGLEVEL_ASSIGNMENT); if (this != &other) { destroy(true); copy(other); @@ -82,8 +80,6 @@ const basic & basic::operator=(const basic & other) /** Construct object from archive_node. */ basic::basic(const archive_node &n, const lst &sym_lst) : flags(0), refcount(0) { - debugmsg("basic ctor from archive_node", LOGLEVEL_CONSTRUCT); - // Reconstruct tinfo_key from class name std::string class_name; if (n.find_string("class", class_name)) @@ -101,12 +97,6 @@ void basic::archive(archive_node &n) const n.add_string("class", class_name()); } -////////// -// functions overriding virtual functions from bases classes -////////// - -// none - ////////// // new virtual functions which can be overridden by derived classes ////////// @@ -119,8 +109,6 @@ void basic::archive(archive_node &n) const * level for placing parentheses and formatting */ void basic::print(const print_context & c, unsigned level) const { - debugmsg("basic print", LOGLEVEL_PRINT); - if (is_of_type(c, print_tree)) { c.s << std::string(level, ' ') << class_name() @@ -166,7 +154,6 @@ unsigned basic::precedence(void) const * construction of an ex from a basic. */ basic * basic::duplicate() const { - debugmsg("basic duplicate",LOGLEVEL_DUPLICATE); return new basic(*this); } @@ -202,9 +189,9 @@ ex & basic::let_op(int i) 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_ex_exactly_of_type(index,numeric)) + return op(ex_to(index).to_int()); + throw(std::invalid_argument("non-numeric indices not supported by this type")); } @@ -213,18 +200,17 @@ ex basic::operator[](int i) const return op(i); } -/** Search ocurrences. An object 'has' an expression if it is the expression - * itself or one of the children 'has' it. As a consequence (according to - * the definition of children) given e=x+y+z, e.has(x) is true but e.has(x+y) - * is false. The expression can also contain wildcards. */ -bool basic::has(const ex & other) const +/** Test for occurrence of a pattern. An object 'has' a pattern if it matches + * the pattern itself or one of the children 'has' it. As a consequence + * (according to the definition of children) given e=x+y+z, e.has(x) is true + * but e.has(x+y) is false. */ +bool basic::has(const ex & pattern) const { - GINAC_ASSERT(other.bp!=0); lst repl_lst; - if (match(*other.bp, repl_lst)) + if (match(pattern, repl_lst)) return true; for (unsigned i=0; isetflag(status_flags::dynallocated); - copy->clearflag(status_flags::hash_calculated); + copy->clearflag(status_flags::hash_calculated | status_flags::expanded); ex e(*copy); for (unsigned i=0; i(s)) ? 1 : 0; } /** Return degree of lowest power in object s. */ int basic::ldegree(const ex & s) const { - return 0; + return is_equal(ex_to(s)) ? 1 : 0; } /** Return coefficient of degree n in object s. */ ex basic::coeff(const ex & s, int n) const { - return n==0 ? *this : _ex0(); + if (is_equal(ex_to(s))) + return n==1 ? _ex1 : _ex0; + else + return n==0 ? *this : _ex0; } /** Sort expanded expression in terms of powers of some object(s). @@ -274,6 +263,8 @@ ex basic::collect(const ex & s, bool distributed) const if (is_ex_of_type(s, lst)) { // List of objects specified + if (s.nops() == 0) + return *this; if (s.nops() == 1) return collect(s.op(0)); @@ -299,7 +290,7 @@ ex basic::collect(const ex & s, bool distributed) const while (true) { // Calculate coeff*x1^c1*...*xn^cn - ex y = _ex1(); + ex y = _ex1; for (int i=0; ihold(); } +/** Function object to be applied by basic::evalf(). */ +struct evalf_map_function : public map_function { + int level; + evalf_map_function(int l) : level(l) {} + ex operator()(const ex & e) { return evalf(e, level); } +}; + /** Evaluate object numerically. */ ex basic::evalf(int level) const { - // There is nothing to do for basic objects: - return *this; + if (nops() == 0) + return *this; + else { + if (level == 1) + return *this; + else if (level == -max_recursion_level) + throw(std::runtime_error("max recursion level reached")); + else { + evalf_map_function map_evalf(level - 1); + return map(map_evalf); + } + } } -/** Evaluate sums and products of matrices. */ +/** Function object to be applied by basic::evalm(). */ +struct evalm_map_function : public map_function { + ex operator()(const ex & e) { return evalm(e); } +} map_evalm; + +/** Evaluate sums, products and integer powers of matrices. */ ex basic::evalm(void) const { if (nops() == 0) return *this; else - return map(GiNaC::evalm); + return map(map_evalm); } /** Perform automatic symbolic evaluations on indexed expression that @@ -437,7 +450,7 @@ bool basic::match(const ex & pattern, lst & repl_lst) const But who is the king tonight? Who is the king tonight? Pattern is the thing, the key thing-a-ling, - But who is the king of pattern? + But who is the king of Pattern? But who is the king, the king thing-a-ling, Who is the king of Pattern? Bog is the king, the king thing-a-ling, @@ -453,7 +466,7 @@ bool basic::match(const ex & pattern, lst & repl_lst) const // be the same expression) for (unsigned i=0; i(repl_lst.op(i).op(1))); } repl_lst.append(pattern == *this); return true; @@ -461,7 +474,7 @@ bool basic::match(const ex & pattern, lst & repl_lst) const } else { // Expression must be of the same type as the pattern - if (tinfo() != pattern.bp->tinfo()) + if (tinfo() != ex_to(pattern).tinfo()) return false; // Number of subexpressions must match @@ -471,7 +484,11 @@ bool basic::match(const ex & pattern, lst & repl_lst) const // No subexpressions? Then just compare the objects (there can't be // wildcards in the pattern) if (nops() == 0) - return is_equal(*pattern.bp); + return is_equal_same_type(ex_to(pattern)); + + // Check whether attributes that are not subexpressions match + if (!match_same_type(ex_to(pattern))) + return false; // Otherwise the subexpressions must match one-to-one for (unsigned i=0; i(ls.op(i)))) return lr.op(i); } } else { for (unsigned i=0; isubs(repl_lst, true); // avoid infinite recursion when re-substituting the wildcards + if (match(ex_to(ls.op(i)), repl_lst)) + return lr.op(i).subs(repl_lst, true); // avoid infinite recursion when re-substituting the wildcards } } @@ -544,13 +561,25 @@ ex basic::simplify_ncmul(const exvector & v) const // protected -/** Default implementation of ex::diff(). It simply throws an error message. +/** Function object to be applied by basic::derivative(). */ +struct derivative_map_function : public map_function { + const symbol &s; + derivative_map_function(const symbol &sym) : s(sym) {} + ex operator()(const ex & e) { return diff(e, s); } +}; + +/** Default implementation of ex::diff(). It maps the operation on the + * operands (or returns 0 when the object has no operands). * - * @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")); + if (nops() == 0) + return _ex0; + else { + derivative_map_function map_derivative(s); + return map(map_derivative); + } } /** Returns order relation between two objects of same type. This needs to be @@ -570,7 +599,24 @@ int basic::compare_same_type(const basic & other) const * than an order relation and then it can be overridden. */ bool basic::is_equal_same_type(const basic & other) const { - return this->compare_same_type(other)==0; + return compare_same_type(other)==0; +} + +/** Returns true if the attributes of two objects are similar enough for + * a match. This function must not match subexpressions (this is already + * done by basic::match()). Only attributes not accessible by op() should + * be compared. This is also the reason why this function doesn't take the + * wildcard replacement list from match() as an argument: only subexpressions + * are subject to wildcard matches. Also, this function only needs to be + * implemented for container classes because is_equal_same_type() is + * automatically used instead of match_same_type() if nops() == 0. + * + * @see basic::match */ +bool basic::match_same_type(const basic & other) const +{ + // The default is to only consider subexpressions, but not any other + // attributes + return true; } unsigned basic::return_type(void) const @@ -609,11 +655,23 @@ unsigned basic::calchash(void) const return v; } +/** Function object to be applied by basic::expand(). */ +struct expand_map_function : public map_function { + unsigned options; + expand_map_function(unsigned o) : options(o) {} + ex operator()(const ex & e) { return expand(e, options); } +}; + /** 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); + if (nops() == 0) + return (options == 0) ? setflag(status_flags::expanded) : *this; + else { + expand_map_function map_expand(options); + return ex_to(map(map_expand)).setflag(options == 0 ? status_flags::expanded : 0); + } } @@ -713,7 +771,7 @@ bool basic::is_equal(const basic & other) const GINAC_ASSERT(typeid(*this)==typeid(other)); - return this->is_equal_same_type(other); + return is_equal_same_type(other); } // protected @@ -723,7 +781,7 @@ bool basic::is_equal(const basic & other) const * @see basic::eval */ const basic & basic::hold(void) const { - return this->setflag(status_flags::evaluated); + return setflag(status_flags::evaluated); } /** Ensure the object may be modified without hurting others, throws if this @@ -732,6 +790,7 @@ void basic::ensure_if_modifiable(void) const { if (this->refcount>1) throw(std::runtime_error("cannot modify multiply referenced object")); + clearflag(status_flags::hash_calculated); } //////////