From 708e9e647029af699333fceffc0a76bef70a4709 Mon Sep 17 00:00:00 2001 From: Christian Bauer Date: Sat, 23 Jun 2001 16:52:04 +0000 Subject: [PATCH] - added find() (like has(), but returns list of all occurrences) - added lst::sort() and lst::unique() - status_flags::expanded is only taken into account when no expand options are specified. This makes it possible to re-expand with other options. - added expand_options::expand_function_args - collect(foo, {}) doesn't crash any more - introduced match_same_type() method which is slightly similar to is_equal_same_type() but doesn't check subexpressions. Fixed a number of match() bugs with this (e.g. a==b matched a!=b, and matrices with different dimensions but the same number of elements could match). Only container classes with additional member variables that have to be equal for a match need to implement match_same_type(). --- NEWS | 8 +++++-- ginac/add.cpp | 6 ++--- ginac/basic.cpp | 53 ++++++++++++++++++++++++++++------------ ginac/basic.h | 1 + ginac/clifford.cpp | 10 +++++++- ginac/clifford.h | 1 + ginac/color.cpp | 10 +++++++- ginac/color.h | 1 + ginac/container.pl | 35 +++++++++++++++++++++++++++ ginac/ex.cpp | 21 +++++++++++++++- ginac/ex.h | 10 +++++--- ginac/expairseq.cpp | 2 +- ginac/flags.h | 3 ++- ginac/function.pl | 39 +++++++++++++++++------------- ginac/idx.cpp | 56 +++++++++++++++++++++---------------------- ginac/idx.h | 10 +++++--- ginac/inifcns.cpp | 31 ++++++++++++++++++++---- ginac/matrix.cpp | 10 ++++++++ ginac/matrix.h | 4 ++-- ginac/mul.cpp | 10 ++++---- ginac/ncmul.cpp | 6 ++--- ginac/power.cpp | 6 ++--- ginac/pseries.cpp | 2 +- ginac/relational.cpp | 8 +++++++ ginac/relational.h | 2 ++ ginac/symbol.cpp | 8 ------- ginac/symbol.h | 1 - ginac/wildcard.cpp | 6 ++--- ginac/wildcard.h | 8 ++++--- ginsh/ginsh.1.in | 7 ++++-- ginsh/ginsh_parser.yy | 8 +++++++ 31 files changed, 271 insertions(+), 112 deletions(-) diff --git a/NEWS b/NEWS index 276e9ccb..de5777b3 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,8 @@ This file records noteworthy changes. 0.9.1 () * New functions/methods: - - remove_first() and remove_last() for lists + - find() + - remove_first(), remove_last(), sort() and unique() for lists - symmetrize_cyclic() - decomp_rational() * Instead of just totally symmetric or antisymmetric, complex symmetries @@ -19,13 +20,16 @@ This file records noteworthy changes. take the trace on both sides, using diff() on a matrix differentiates every element etc. * diff() works properly with non-commutative products and indexed objects. +* New option flag "expand_function_args" for expand(). * Supplement some (now deprecated) macros by inlined template functions: - is_of_type(foo, type) -> is_a(foo) - is_ex_of_type(foo, type) -> is_a(foo) - is_exaclty_of_type(foo, type) -> is_exaclty_a(foo) - is_ex_exaclty_of_type(foo, type) -> is_exaclty_a(foo) - ex_to_foobar(baz) -> ex_to(baz) -* rem(c, p[x], x) erroneously returned p[x] instead of c. +* rem(c, p[x], x) (c: numeric, p[x]: polynomial) erroneously returned p[x] + instead of c. +* Small bugfixes in pattern matching. 0.9.0 (7 June 2001) * In the output and in ginsh, lists are now delimited by { } braces, and diff --git a/ginac/add.cpp b/ginac/add.cpp index 28eeff52..c4e53360 100644 --- a/ginac/add.cpp +++ b/ginac/add.cpp @@ -511,16 +511,16 @@ ex add::recombine_pair_to_ex(const expair & p) const ex add::expand(unsigned options) const { - if (flags & status_flags::expanded) + if (options == 0 && (flags & status_flags::expanded)) return *this; epvector *vp = expandchildren(options); if (vp == NULL) { // the terms have not changed, so it is safe to declare this expanded - return this->setflag(status_flags::expanded); + return (options == 0) ? setflag(status_flags::expanded) : *this; } - return (new add(vp, overall_coeff))->setflag(status_flags::expanded | status_flags::dynallocated); + return (new add(vp, overall_coeff))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } } // namespace GiNaC diff --git a/ginac/basic.cpp b/ginac/basic.cpp index 70f84ea8..8d60fcfc 100644 --- a/ginac/basic.cpp +++ b/ginac/basic.cpp @@ -213,18 +213,18 @@ 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); + GINAC_ASSERT(pattern.bp!=0); lst repl_lst; - if (match(*other.bp, repl_lst)) + if (match(*pattern.bp, repl_lst)) return true; for (unsigned i=0; icompare_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 @@ -655,10 +678,10 @@ struct expand_map_function : public map_function { ex basic::expand(unsigned options) const { if (nops() == 0) - return this->setflag(status_flags::expanded); + return (options == 0) ? setflag(status_flags::expanded) : *this; else { expand_map_function map_expand(options); - return map(map_expand).bp->setflag(status_flags::expanded); + return map(map_expand).bp->setflag(options == 0 ? status_flags::expanded : 0); } } @@ -759,7 +782,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 @@ -769,7 +792,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 diff --git a/ginac/basic.h b/ginac/basic.h index 84ed992c..56369b82 100644 --- a/ginac/basic.h +++ b/ginac/basic.h @@ -141,6 +141,7 @@ protected: // functions that 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 bool match_same_type(const basic & other) const; virtual unsigned calchash(void) const; virtual ex simplify_ncmul(const exvector & v) const; diff --git a/ginac/clifford.cpp b/ginac/clifford.cpp index a6a1333e..80d7d342 100644 --- a/ginac/clifford.cpp +++ b/ginac/clifford.cpp @@ -128,7 +128,7 @@ DEFAULT_ARCHIVING(diracgamma5) int clifford::compare_same_type(const basic & other) const { - GINAC_ASSERT(other.tinfo() == TINFO_clifford); + GINAC_ASSERT(is_of_type(other, clifford)); const clifford &o = static_cast(other); if (representation_label != o.representation_label) { @@ -139,6 +139,14 @@ int clifford::compare_same_type(const basic & other) const return inherited::compare_same_type(other); } +bool clifford::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_of_type(other, clifford)); + const clifford &o = static_cast(other); + + return representation_label == o.representation_label; +} + DEFAULT_COMPARE(diracone) DEFAULT_COMPARE(diracgamma) DEFAULT_COMPARE(diracgamma5) diff --git a/ginac/clifford.h b/ginac/clifford.h index 0233ba0e..7120a4b6 100644 --- a/ginac/clifford.h +++ b/ginac/clifford.h @@ -49,6 +49,7 @@ public: // functions overriding virtual functions from base classes protected: + bool match_same_type(const basic & other) const; ex simplify_ncmul(const exvector & v) const; ex thisexprseq(const exvector & v) const; ex thisexprseq(exvector * vp) const; diff --git a/ginac/color.cpp b/ginac/color.cpp index 195b93e7..57364b5c 100644 --- a/ginac/color.cpp +++ b/ginac/color.cpp @@ -129,7 +129,7 @@ DEFAULT_ARCHIVING(su3d) int color::compare_same_type(const basic & other) const { - GINAC_ASSERT(other.tinfo() == TINFO_color); + GINAC_ASSERT(is_of_type(other, color)); const color &o = static_cast(other); if (representation_label != o.representation_label) { @@ -140,6 +140,14 @@ int color::compare_same_type(const basic & other) const return inherited::compare_same_type(other); } +bool color::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_of_type(other, color)); + const color &o = static_cast(other); + + return representation_label == o.representation_label; +} + DEFAULT_COMPARE(su3one) DEFAULT_COMPARE(su3t) DEFAULT_COMPARE(su3f) diff --git a/ginac/color.h b/ginac/color.h index c0eb614f..ba627350 100644 --- a/ginac/color.h +++ b/ginac/color.h @@ -51,6 +51,7 @@ public: // functions overriding virtual functions from base classes protected: + bool match_same_type(const basic & other) const; ex simplify_ncmul(const exvector & v) const; ex thisexprseq(const exvector & v) const; ex thisexprseq(exvector * vp) const; diff --git a/ginac/container.pl b/ginac/container.pl index 8f7cb87d..a0a4a7b1 100755 --- a/ginac/container.pl +++ b/ginac/container.pl @@ -23,6 +23,7 @@ if ($type eq 'exprseq') { $STLHEADER="vector"; $reserve=1; $prepend=0; + $sort=0; $let_op=0; $open_bracket='('; $close_bracket=')'; @@ -34,6 +35,7 @@ if ($type eq 'exprseq') { $STLHEADER="list"; $reserve=0; $prepend=1; + $sort=1; $let_op=1; $open_bracket='{'; $close_bracket='}'; @@ -64,6 +66,7 @@ ${CONTAINER} & ${CONTAINER}::prepend(const ex & b) seq.push_front(b); return *this; } + ${CONTAINER} & ${CONTAINER}::remove_first(void) { ensure_if_modifiable(); @@ -76,6 +79,32 @@ END_OF_PREPEND_IMPLEMENTATION $PREPEND_IMPLEMENTATION=""; } +if ($sort) { + $SORT_INTERFACE=<flags & status_flags::expanded) + if (options == 0 && (bp->flags & status_flags::expanded)) // The "expanded" flag only covers the standard options; someone might want to re-expand with different options return *bp; else return bp->expand(options); @@ -143,6 +143,25 @@ bool ex::match(const ex & pattern) const return bp->match(pattern, repl_lst); } +/** Find all occurrences of a pattern. The found matches are appended to + * the "found" list. If the expression itself matches the pattern, the + * children are not further examined. This function returns true when any + * matches were found. */ +bool ex::find(const ex & pattern, lst & found) const +{ + if (match(pattern)) { + found.append(*this); + found.sort(); + found.unique(); + return true; + } + bool any_found = false; + for (unsigned i=0; iinfo(inf); } unsigned nops() const { return bp->nops(); } ex expand(unsigned options=0) const; - bool has(const ex & other) const { return bp->has(other); } + bool has(const ex & pattern) const { return bp->has(pattern); } ex map(map_function & f) const { return bp->map(f); } ex map(ex (*f)(const ex & e)) const; + bool find(const ex & pattern, lst & found) const; int degree(const ex & s) const { return bp->degree(s); } int ldegree(const ex & s) const { return bp->ldegree(s); } ex coeff(const ex & s, int n = 1) const { return bp->coeff(s, n); } @@ -346,8 +347,11 @@ inline unsigned nops(const ex & thisex) inline ex expand(const ex & thisex, unsigned options = 0) { return thisex.expand(options); } -inline bool has(const ex & thisex, const ex & other) -{ return thisex.has(other); } +inline bool has(const ex & thisex, const ex & pattern) +{ return thisex.has(pattern); } + +inline bool find(const ex & thisex, const ex & pattern, lst & found) +{ return thisex.find(pattern, found); } inline int degree(const ex & thisex, const ex & s) { return thisex.degree(s); } diff --git a/ginac/expairseq.cpp b/ginac/expairseq.cpp index 96da57c2..1530564b 100644 --- a/ginac/expairseq.cpp +++ b/ginac/expairseq.cpp @@ -579,7 +579,7 @@ ex expairseq::expand(unsigned options) const epvector *vp = expandchildren(options); if (vp == NULL) { // The terms have not changed, so it is safe to declare this expanded - return this->setflag(status_flags::expanded); + return (options == 0) ? setflag(status_flags::expanded) : *this; } else return thisexpairseq(vp, overall_coeff); } diff --git a/ginac/flags.h b/ginac/flags.h index 9c11862e..b7f6222d 100644 --- a/ginac/flags.h +++ b/ginac/flags.h @@ -29,7 +29,8 @@ class expand_options { public: enum { expand_trigonometric = 0x0001, - expand_indexed = 0x0002 + expand_indexed = 0x0002, + expand_function_args = 0x0004 }; }; diff --git a/ginac/function.pl b/ginac/function.pl index baaf9106..b9ee7871 100755 --- a/ginac/function.pl +++ b/ginac/function.pl @@ -273,6 +273,7 @@ $series_func_interface void test_and_set_nparams(unsigned n); std::string get_name(void) const { return name; } unsigned get_nparams(void) const { return nparams; } + bool has_derivative(void) const { return derivative_f != NULL; } protected: std::string name; @@ -315,6 +316,7 @@ class function : public exprseq friend class remember_table_entry; // friend class remember_table_list; // friend class remember_table; + friend ex Derivative_eval(const ex &, const ex &); // member functions @@ -340,12 +342,12 @@ public: ex evalf(int level=0) const; unsigned calchash(void) const; ex series(const relational & r, int order, unsigned options = 0) const; - bool match(const ex & pattern, lst & repl_lst) const; ex thisexprseq(const exvector & v) const; ex thisexprseq(exvector * vp) const; protected: ex derivative(const symbol & s) const; bool is_equal_same_type(const basic & other) const; + bool match_same_type(const basic & other) const; unsigned return_type(void) const; unsigned return_type_tinfo(void) const; @@ -702,7 +704,11 @@ void function::print(const print_context & c, unsigned level) const ex function::expand(unsigned options) const { - return this->setflag(status_flags::expanded); + // Only expand arguments when asked to do so + if (options & expand_options::expand_function_args) + return inherited::expand(options); + else + return (options == 0) ? setflag(status_flags::expanded) : *this; } int function::degree(const ex & s) const @@ -843,17 +849,8 @@ ${series_switch_statement} throw(std::logic_error("function::series(): invalid nparams")); } -bool function::match(const ex & pattern, lst & repl_lst) const -{ - // Serial number must match - if (is_ex_of_type(pattern, function) && serial != ex_to(pattern).serial) - return false; - return inherited::match(pattern, repl_lst); -} - // protected - /** Implementation of ex::diff() for functions. It applies the chain rule, * except for the Order term function. * \@see ex::diff */ @@ -902,10 +899,10 @@ int function::compare_same_type(const basic & other) const GINAC_ASSERT(is_of_type(other, function)); const function & o = static_cast(other); - if (serial!=o.serial) { + if (serial != o.serial) return serial < o.serial ? -1 : 1; - } - return exprseq::compare_same_type(o); + else + return exprseq::compare_same_type(o); } bool function::is_equal_same_type(const basic & other) const @@ -913,8 +910,18 @@ bool function::is_equal_same_type(const basic & other) const GINAC_ASSERT(is_of_type(other, function)); const function & o = static_cast(other); - if (serial!=o.serial) return false; - return exprseq::is_equal_same_type(o); + if (serial != o.serial) + return false; + else + return exprseq::is_equal_same_type(o); +} + +bool function::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_of_type(other, function)); + const function & o = static_cast(other); + + return serial == o.serial; } unsigned function::return_type(void) const diff --git a/ginac/idx.cpp b/ginac/idx.cpp index 67249e5a..bc567171 100644 --- a/ginac/idx.cpp +++ b/ginac/idx.cpp @@ -285,6 +285,14 @@ int idx::compare_same_type(const basic & other) const return dim.compare(o.dim); } +bool idx::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_of_type(other, idx)); + const idx &o = static_cast(other); + + return dim.is_equal(o.dim); +} + int varidx::compare_same_type(const basic & other) const { GINAC_ASSERT(is_of_type(other, varidx)); @@ -300,6 +308,16 @@ int varidx::compare_same_type(const basic & other) const return 0; } +bool varidx::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_of_type(other, varidx)); + const varidx &o = static_cast(other); + + if (covariant != o.covariant) + return false; + return inherited::match_same_type(other); +} + int spinidx::compare_same_type(const basic & other) const { GINAC_ASSERT(is_of_type(other, spinidx)); @@ -316,41 +334,21 @@ int spinidx::compare_same_type(const basic & other) const return 0; } -/** By default, basic::evalf would evaluate the index value but we don't want - * a.1 to become a.(1.0). */ -ex idx::evalf(int level) const -{ - return *this; -} - -bool idx::match(const ex & pattern, lst & repl_lst) const +bool spinidx::match_same_type(const basic & other) const { - if (!is_ex_of_type(pattern, idx)) - return false; - const idx &o = ex_to(pattern); - if (!dim.is_equal(o.dim)) - return false; - return value.match(o.value, repl_lst); -} + GINAC_ASSERT(is_of_type(other, spinidx)); + const spinidx &o = static_cast(other); -bool varidx::match(const ex & pattern, lst & repl_lst) const -{ - if (!is_ex_of_type(pattern, varidx)) - return false; - const varidx &o = ex_to(pattern); - if (covariant != o.covariant) + if (dotted != o.dotted) return false; - return inherited::match(pattern, repl_lst); + return inherited::match_same_type(other); } -bool spinidx::match(const ex & pattern, lst & repl_lst) const +/** By default, basic::evalf would evaluate the index value but we don't want + * a.1 to become a.(1.0). */ +ex idx::evalf(int level) const { - if (!is_ex_of_type(pattern, spinidx)) - return false; - const spinidx &o = ex_to(pattern); - if (dotted != o.dotted) - return false; - return inherited::match(pattern, repl_lst); + return *this; } ex idx::subs(const lst & ls, const lst & lr, bool no_pattern) const diff --git a/ginac/idx.h b/ginac/idx.h index 1c7bb9c2..d98d4b14 100644 --- a/ginac/idx.h +++ b/ginac/idx.h @@ -52,11 +52,11 @@ public: unsigned nops() const; ex & let_op(int i); ex evalf(int level = 0) const; - bool match(const ex & pattern, lst & repl_lst) const; ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const; protected: ex derivative(const symbol & s) const; + bool match_same_type(const basic & other) const; // new virtual functions in this class public: @@ -109,9 +109,11 @@ public: // functions overriding virtual functions from bases classes public: void print(const print_context & c, unsigned level = 0) const; - bool match(const ex & pattern, lst & repl_lst) const; bool is_dummy_pair_same_type(const basic & other) const; +protected: + bool match_same_type(const basic & other) const; + // non-virtual functions in this class public: /** Check whether the index is covariant. */ @@ -152,9 +154,11 @@ public: // functions overriding virtual functions from bases classes public: void print(const print_context & c, unsigned level = 0) const; - bool match(const ex & pattern, lst & repl_lst) const; bool is_dummy_pair_same_type(const basic & other) const; +protected: + bool match_same_type(const basic & other) const; + // non-virtual functions in this class public: /** Check whether the index is dotted. */ diff --git a/ginac/inifcns.cpp b/ginac/inifcns.cpp index 1fcba692..7ac21530 100644 --- a/ginac/inifcns.cpp +++ b/ginac/inifcns.cpp @@ -413,18 +413,39 @@ REGISTER_FUNCTION(Order, eval_func(Order_eval). // Inert partial differentiation operator ////////// -static ex Derivative_eval(const ex & f, const ex & l) +ex Derivative_eval(const ex & f, const ex & l) { - if (!is_ex_exactly_of_type(f, function)) { + if (!is_ex_of_type(f, function)) throw(std::invalid_argument("Derivative(): 1st argument must be a function")); - } - if (!is_ex_exactly_of_type(l, lst)) { + if (!is_ex_of_type(l, lst)) throw(std::invalid_argument("Derivative(): 2nd argument must be a list")); + +#if 0 + // Perform differentiations if possible + const function &fcn = ex_to(f); + if (fcn.registered_functions()[fcn.get_serial()].has_derivative() && l.nops() > 0) { + + // The function actually seems to have a derivative, let's calculate it + ex d = fcn.pderivative(ex_to_numeric(l.op(0)).to_int()); + + // If this was the last differentiation, return the result + if (l.nops() == 1) + return d; + + // Otherwise recursively continue as long as the derivative is still + // a function + if (is_ex_of_type(d, function)) { + lst l_copy = ex_to(l); + l_copy.remove_first(); + return Derivative(d, l_copy); + } } +#endif return Derivative(f, l).hold(); } -REGISTER_FUNCTION(Derivative, eval_func(Derivative_eval)); +REGISTER_FUNCTION(Derivative, eval_func(Derivative_eval). + latex_name("\\mathrm{D}")); ////////// // Solve linear system diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp index 8d2e0b88..91382c2f 100644 --- a/ginac/matrix.cpp +++ b/ginac/matrix.cpp @@ -259,6 +259,16 @@ int matrix::compare_same_type(const basic & other) const return 0; } +bool matrix::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_exactly_of_type(other, matrix)); + const matrix & o = static_cast(other); + + // The number of rows and columns must be the same. This is necessary to + // prevent a 2x3 matrix from matching a 3x2 one. + return row == o.rows() && col == o.cols(); +} + /** Automatic symbolic evaluation of an indexed matrix. */ ex matrix::eval_indexed(const basic & i) const { diff --git a/ginac/matrix.h b/ginac/matrix.h index fcf2d63b..927c27c1 100644 --- a/ginac/matrix.h +++ b/ginac/matrix.h @@ -53,10 +53,10 @@ public: ex add_indexed(const ex & self, const ex & other) const; ex scalar_mul_indexed(const ex & self, const numeric & other) const; bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const; + protected: + bool match_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: diff --git a/ginac/mul.cpp b/ginac/mul.cpp index a6a2df2c..3bc70b44 100644 --- a/ginac/mul.cpp +++ b/ginac/mul.cpp @@ -668,7 +668,7 @@ bool mul::can_make_flat(const expair & p) const ex mul::expand(unsigned options) const { - if (flags & status_flags::expanded) + if (options == 0 && (flags & status_flags::expanded)) return *this; exvector sub_expanded_seq; @@ -700,7 +700,7 @@ ex mul::expand(unsigned options) const distrseq.push_back(add1.op(i1)*add2.op(i2)); } } - last_expanded = (new add(distrseq))->setflag(status_flags::dynallocated | status_flags::expanded); + last_expanded = (new add(distrseq))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } else { non_adds.push_back(split_ex_to_pair(last_expanded)); last_expanded = (*cit).rest; @@ -721,14 +721,14 @@ ex mul::expand(unsigned options) const for (int i=0; isetflag(status_flags::dynallocated | status_flags::expanded)); + distrseq.push_back((new mul(factors,overall_coeff))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0))); } return ((new add(distrseq))-> - setflag(status_flags::dynallocated | status_flags::expanded)); + setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0))); } non_adds.push_back(split_ex_to_pair(last_expanded)); return (new mul(non_adds, overall_coeff))-> - setflag(status_flags::dynallocated | status_flags::expanded); + setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } diff --git a/ginac/ncmul.cpp b/ginac/ncmul.cpp index 7874509e..25ffca31 100644 --- a/ginac/ncmul.cpp +++ b/ginac/ncmul.cpp @@ -174,7 +174,7 @@ ex ncmul::expand(unsigned options) const if (number_of_adds==0) { return (new ncmul(expanded_seq,1))->setflag(status_flags::dynallocated || - status_flags::expanded); + (options == 0 ? status_flags::expanded : 0)); } exvector distrseq; @@ -197,7 +197,7 @@ ex ncmul::expand(unsigned options) const 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)); + (options == 0 ? status_flags::expanded : 0))); // increment k[] l=number_of_adds-1; @@ -209,7 +209,7 @@ ex ncmul::expand(unsigned options) const } return (new add(distrseq))->setflag(status_flags::dynallocated | - status_flags::expanded); + (options == 0 ? status_flags::expanded : 0)); } int ncmul::degree(const ex & s) const diff --git a/ginac/power.cpp b/ginac/power.cpp index 227da2fb..1fe5063c 100644 --- a/ginac/power.cpp +++ b/ginac/power.cpp @@ -565,7 +565,7 @@ unsigned power::return_type_tinfo(void) const ex power::expand(unsigned options) const { - if (flags & status_flags::expanded) + if (options == 0 && (flags & status_flags::expanded)) return *this; ex expanded_basis = basis.expand(options); @@ -604,7 +604,7 @@ ex power::expand(unsigned options) const if (are_ex_trivially_equal(basis,expanded_basis) && are_ex_trivially_equal(exponent,expanded_exponent)) { return this->hold(); } else { - return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | status_flags::expanded); + return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } } @@ -624,7 +624,7 @@ ex power::expand(unsigned options) const if (are_ex_trivially_equal(basis,expanded_basis) && are_ex_trivially_equal(exponent,expanded_exponent)) return this->hold(); else - return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | status_flags::expanded); + return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } ////////// diff --git a/ginac/pseries.cpp b/ginac/pseries.cpp index 2c8aa8f6..0602ddd7 100644 --- a/ginac/pseries.cpp +++ b/ginac/pseries.cpp @@ -429,7 +429,7 @@ ex pseries::expand(unsigned options) const ++i; } return (new pseries(relational(var,point), newseq)) - ->setflag(status_flags::dynallocated | status_flags::expanded); + ->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } /** Implementation of ex::diff() for a power series. It treats the series as a diff --git a/ginac/relational.cpp b/ginac/relational.cpp index 88f2ad64..74ce1acb 100644 --- a/ginac/relational.cpp +++ b/ginac/relational.cpp @@ -205,6 +205,14 @@ int relational::compare_same_type(const basic & other) const return (o < oth.o) ? -1 : 1; } +bool relational::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_exactly_of_type(other, relational)); + const relational &oth = static_cast(other); + + return o == oth.o; +} + unsigned relational::return_type(void) const { GINAC_ASSERT(lh.return_type()==rh.return_type()); diff --git a/ginac/relational.h b/ginac/relational.h index 0447e94a..fc559b5f 100644 --- a/ginac/relational.h +++ b/ginac/relational.h @@ -58,7 +58,9 @@ public: ex & let_op(int i); ex eval(int level=0) const; ex simplify_ncmul(const exvector & v) const; + protected: + bool match_same_type(const basic & other) const; unsigned return_type(void) const; unsigned return_type_tinfo(void) const; diff --git a/ginac/symbol.cpp b/ginac/symbol.cpp index b15f9b78..ba0cccd1 100644 --- a/ginac/symbol.cpp +++ b/ginac/symbol.cpp @@ -179,14 +179,6 @@ bool symbol::info(unsigned inf) const return inherited::info(inf); } -bool symbol::has(const ex & other) const -{ - if (this->is_equal(*other.bp)) - return true; - else - return false; -} - int symbol::degree(const ex & s) const { return is_equal(*s.bp) ? 1 : 0; diff --git a/ginac/symbol.h b/ginac/symbol.h index 76b87720..16c31933 100644 --- a/ginac/symbol.h +++ b/ginac/symbol.h @@ -75,7 +75,6 @@ public: basic * duplicate() const; void print(const print_context & c, unsigned level = 0) const; bool info(unsigned inf) const; - bool has(const ex & other) const; int degree(const ex & s) const; int ldegree(const ex & s) const; ex coeff(const ex & s, int n = 1) const; diff --git a/ginac/wildcard.cpp b/ginac/wildcard.cpp index 528df593..33ccb461 100644 --- a/ginac/wildcard.cpp +++ b/ginac/wildcard.cpp @@ -115,9 +115,9 @@ unsigned wildcard::calchash(void) const bool wildcard::match(const ex & pattern, lst & repl_lst) const { - // Wildcards must match exactly (this is required for subs() to work - // properly because in the final step it substitutes all wildcards by - // their matching expressions) + // Wildcards must match each other exactly (this is required for + // subs() to work properly because in the final step it substitutes + // all wildcards by their matching expressions) return is_equal(*pattern.bp); } diff --git a/ginac/wildcard.h b/ginac/wildcard.h index 6bddc5e1..f787bcba 100644 --- a/ginac/wildcard.h +++ b/ginac/wildcard.h @@ -28,8 +28,8 @@ namespace GiNaC { -/** This class acts as a wildcard for subs(), match() and has(). An integer - * label is used to identify different wildcards. */ +/** This class acts as a wildcard for subs(), match(), has() and find(). An + * integer label is used to identify different wildcards. */ class wildcard : public basic { GINAC_DECLARE_REGISTERED_CLASS(wildcard, basic) @@ -42,9 +42,11 @@ public: // functions overriding virtual functions from base classes public: void print(const print_context & c, unsigned level = 0) const; - unsigned calchash(void) const; bool match(const ex & pattern, lst & repl_lst) const; +protected: + unsigned calchash(void) const; + // non-virtual functions in this class public: unsigned get_label(void) const {return label;} diff --git a/ginsh/ginsh.1.in b/ginsh/ginsh.1.in index e8c24a50..5f780648 100644 --- a/ginsh/ginsh.1.in +++ b/ginsh/ginsh.1.in @@ -110,8 +110,8 @@ symbol that controls the numeric precision of calculations with inexact numbers. Assigning an integer value to digits will change the precision to the given number of decimal places. .SS WILDCARDS -The has(), match() and subs() functions accept wildcards as placeholders for -expressions. These have the syntax +The has(), find(), match() and subs() functions accept wildcards as placeholders +for expressions. These have the syntax .RS .BI $ number .RE @@ -279,6 +279,9 @@ detail here. Please refer to the GiNaC documentation. .BI expand( expression ) \- expands an expression .br +.BI find( expression ", " expression ) +\- returns a list of all occurrences of a pattern in an expression +.br .BI gcd( expression ", " expression ) \- greatest common divisor .br diff --git a/ginsh/ginsh_parser.yy b/ginsh/ginsh_parser.yy index 10383e8e..a94b92c7 100644 --- a/ginsh/ginsh_parser.yy +++ b/ginsh/ginsh_parser.yy @@ -375,6 +375,13 @@ static ex f_evalf2(const exprseq &e) return e[0].evalf(ex_to(e[1]).to_int()); } +static ex f_find(const exprseq &e) +{ + lst found; + e[0].find(e[1], found); + return found; +} + static ex f_inverse(const exprseq &e) { CHECK_ARG(0, matrix, inverse); @@ -510,6 +517,7 @@ static const fcn_init builtin_fcns[] = { {"evalf", fcn_desc(f_evalf2, 2)}, {"evalm", fcn_desc(f_evalm, 1)}, {"expand", fcn_desc(f_expand, 1)}, + {"find", fcn_desc(f_find, 2)}, {"gcd", fcn_desc(f_gcd, 2)}, {"has", fcn_desc(f_has, 2)}, {"inverse", fcn_desc(f_inverse, 1)}, -- 2.44.0