- added find() (like has(), but returns list of all occurrences)
authorChristian Bauer <Christian.Bauer@uni-mainz.de>
Sat, 23 Jun 2001 16:52:04 +0000 (16:52 +0000)
committerChristian Bauer <Christian.Bauer@uni-mainz.de>
Sat, 23 Jun 2001 16:52:04 +0000 (16:52 +0000)
- 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().

31 files changed:
NEWS
ginac/add.cpp
ginac/basic.cpp
ginac/basic.h
ginac/clifford.cpp
ginac/clifford.h
ginac/color.cpp
ginac/color.h
ginac/container.pl
ginac/ex.cpp
ginac/ex.h
ginac/expairseq.cpp
ginac/flags.h
ginac/function.pl
ginac/idx.cpp
ginac/idx.h
ginac/inifcns.cpp
ginac/matrix.cpp
ginac/matrix.h
ginac/mul.cpp
ginac/ncmul.cpp
ginac/power.cpp
ginac/pseries.cpp
ginac/relational.cpp
ginac/relational.h
ginac/symbol.cpp
ginac/symbol.h
ginac/wildcard.cpp
ginac/wildcard.h
ginsh/ginsh.1.in
ginsh/ginsh_parser.yy

diff --git a/NEWS b/NEWS
index 276e9cc..de5777b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,8 @@ This file records noteworthy changes.
 
 0.9.1 (<date>)
 * 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<type>(foo)
   - is_ex_of_type(foo, type) -> is_a<type>(foo)
   - is_exaclty_of_type(foo, type) -> is_exaclty_a<type>(foo)
   - is_ex_exaclty_of_type(foo, type) -> is_exaclty_a<type>(foo)
   - ex_to_foobar(baz)  ->  ex_to<foobar>(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
index 28eeff5..c4e5336 100644 (file)
@@ -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
index 70f84ea..8d60fcf 100644 (file)
@@ -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; i<nops(); i++)
-               if (op(i).has(other))
+               if (op(i).has(pattern))
                        return true;
        
        return false;
@@ -274,6 +274,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));
 
@@ -459,7 +461,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,
@@ -493,7 +495,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(*pattern.bp);
+
+               // Check whether attributes that are not subexpressions match
+               if (!match_same_type(*pattern.bp))
+                       return false;
 
                // Otherwise the subexpressions must match one-to-one
                for (unsigned i=0; i<nops(); i++)
@@ -604,7 +610,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
@@ -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
index 84ed992..56369b8 100644 (file)
@@ -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;
        
index a6a1333..80d7d34 100644 (file)
@@ -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<const clifford &>(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<const clifford &>(other);
+
+       return representation_label == o.representation_label;
+}
+
 DEFAULT_COMPARE(diracone)
 DEFAULT_COMPARE(diracgamma)
 DEFAULT_COMPARE(diracgamma5)
index 0233ba0..7120a4b 100644 (file)
@@ -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;
index 195b93e..57364b5 100644 (file)
@@ -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<const color &>(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<const color &>(other);
+
+       return representation_label == o.representation_label;
+}
+
 DEFAULT_COMPARE(su3one)
 DEFAULT_COMPARE(su3t)
 DEFAULT_COMPARE(su3f)
index c0eb614..ba62735 100644 (file)
@@ -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;
index 8f7cb87..a0a4a7b 100755 (executable)
@@ -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=<<END_OF_SORT_INTERFACE;
+       virtual ${CONTAINER} & sort(void);
+       virtual ${CONTAINER} & unique(void);
+END_OF_SORT_INTERFACE
+
+       $SORT_IMPLEMENTATION=<<END_OF_SORT_IMPLEMENTATION;
+${CONTAINER} & ${CONTAINER}::sort(void)
+{
+       ensure_if_modifiable();
+       seq.sort(ex_is_less());
+       return *this;
+}
+
+${CONTAINER} & ${CONTAINER}::unique(void)
+{
+       ensure_if_modifiable();
+       seq.unique(ex_is_equal());
+       return *this;
+}
+END_OF_SORT_IMPLEMENTATION
+} else {
+       $SORT_INTERFACE="    // no sort possible for ${CONTAINER}";
+       $SORT_IMPLEMENTATION="";
+}
+
 if ($let_op) {
        $LET_OP_IMPLEMENTATION=<<END_OF_LET_OP_IMPLEMENTATION
 ex & ${CONTAINER}::let_op(int i)
@@ -157,6 +186,7 @@ $interface=<<END_OF_INTERFACE;
  *                        \$STLHEADER=${STLHEADER}
  *                        \$reserve=${reserve}
  *                        \$prepend=${prepend}
+ *                        \$sort=${sort}
  *                        \$let_op=${let_op}
  *                        \$open_bracket=${open_bracket}
  *                        \$close_bracket=${close_bracket}
@@ -222,6 +252,7 @@ public:
        virtual ${CONTAINER} & append(const ex & b);
        virtual ${CONTAINER} & remove_last(void);
 ${PREPEND_INTERFACE}
+${SORT_INTERFACE}
 protected:
        virtual void printseq(const print_context & c, char openbracket, char delim,
                              char closebracket, unsigned this_precedence,
@@ -439,6 +470,8 @@ ${LET_OP_IMPLEMENTATION}
 
 ex ${CONTAINER}::map(map_function & f) const
 {
+       // This implementation is here because basic::map() uses let_op()
+       // which is not defined for all containers
        ${STLT} s;
        RESERVE(s,seq.size());
        ${STLT}::const_iterator i = seq.begin(), end = seq.end();
@@ -534,6 +567,8 @@ ${CONTAINER} & ${CONTAINER}::remove_last(void)
 
 ${PREPEND_IMPLEMENTATION}
 
+${SORT_IMPLEMENTATION}
+
 // protected
 
 void ${CONTAINER}::printseq(const print_context & c, char openbracket, char delim,
index b8a35d3..de48a4f 100644 (file)
@@ -115,7 +115,7 @@ void ex::dbgprinttree(void) const
 ex ex::expand(unsigned options) const
 {
        GINAC_ASSERT(bp!=0);
-       if (bp->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; i<nops(); i++)
+               if (op(i).find(pattern, found))
+                       any_found = true;
+       return any_found;
+}
+
 ex ex::operator[](const ex & index) const
 {
        debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
index b1b639b..fcba458 100644 (file)
@@ -86,9 +86,10 @@ public:
        bool info(unsigned inf) const { return bp->info(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); }
index 96da57c..1530564 100644 (file)
@@ -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);
 }
index 9c11862..b7f6222 100644 (file)
@@ -29,7 +29,8 @@ class expand_options {
 public:
        enum {
                expand_trigonometric = 0x0001,
-               expand_indexed = 0x0002
+               expand_indexed = 0x0002,
+               expand_function_args = 0x0004
        };
 };
 
index baaf910..b9ee787 100755 (executable)
@@ -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<function>(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<const function &>(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<const function &>(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<const function &>(other);
+
+       return serial == o.serial;
 }
 
 unsigned function::return_type(void) const
index 67249e5..bc56717 100644 (file)
@@ -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<const idx &>(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<const varidx &>(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<idx>(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<const spinidx &>(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<varidx>(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<spinidx>(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
index 1c7bb9c..d98d4b1 100644 (file)
@@ -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. */
index 1fcba69..7ac2153 100644 (file)
@@ -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<function>(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<lst>(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
index 8d2e0b8..91382c2 100644 (file)
@@ -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<const matrix &>(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
 {
index fcf2d63..927c27c 100644 (file)
@@ -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:
index a6a2df2..3bc70b4 100644 (file)
@@ -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; i<n; ++i) {
                        epvector factors = non_adds;
                        factors.push_back(split_ex_to_pair(finaladd.op(i)));
-                       distrseq.push_back((new mul(factors,overall_coeff))->setflag(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));
 }
 
   
index 7874509..25ffca3 100644 (file)
@@ -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
index 227da2f..1fe5063 100644 (file)
@@ -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));
 }
 
 //////////
index 2c8aa8f..0602ddd 100644 (file)
@@ -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
index 88f2ad6..74ce1ac 100644 (file)
@@ -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<const relational &>(other);
+
+       return o == oth.o;
+}
+
 unsigned relational::return_type(void) const
 {
        GINAC_ASSERT(lh.return_type()==rh.return_type());
index 0447e94..fc559b5 100644 (file)
@@ -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;
 
index b15f9b7..ba0cccd 100644 (file)
@@ -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;
index 76b8772..16c3193 100644 (file)
@@ -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;
index 528df59..33ccb46 100644 (file)
@@ -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);
 }
 
index 6bddc5e..f787bcb 100644 (file)
@@ -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;}
index e8c24a5..5f78064 100644 (file)
@@ -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
index 10383e8..a94b92c 100644 (file)
@@ -375,6 +375,13 @@ static ex f_evalf2(const exprseq &e)
        return e[0].evalf(ex_to<numeric>(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)},