return op(i);
}
-/** Search ocurrences. An object 'has' an expression if it is the expression
+/** 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. */
+ * is false. The expression can also contain wildcards. */
bool basic::has(const ex & other) const
{
GINAC_ASSERT(other.bp!=0);
* is added to repl_lst. */
bool basic::match(const ex & pattern, lst & repl_lst) const
{
-//clog << "match " << *this << " with " << pattern << ", repl_lst = " << repl_lst << endl;
+/*
+ Sweet sweet shapes, sweet sweet shapes,
+ Thats the key thing, right right.
+ Feed feed face, feed feed shapes,
+ 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, the king thing-a-ling,
+ Who is the king of Pattern?
+ Bog is the king, the king thing-a-ling,
+ Bog is the king of Pattern.
+ Ba bu-bu-bu-bu bu-bu-bu-bu-bu-bu bu-bu
+ Bog is the king of Pattern.
+*/
+
if (is_ex_exactly_of_type(pattern, wildcard)) {
// Wildcard matches anything, but check whether we already have found
for (unsigned i=0; i<ls.nops(); i++) {
lst repl_lst;
if (match(*ls.op(i).bp, repl_lst))
- return lr.op(i).bp->subs(repl_lst, true); // avoid recursion when re-substituting the wildcards
+ return lr.op(i).bp->subs(repl_lst, true); // avoid infinite recursion when re-substituting the wildcards
}
}
#include "power.h"
#include "relational.h"
#include "indexed.h"
+#include "lst.h"
#include "input_lexer.h"
#include "debugmsg.h"
#include "utils.h"
return bp->diff(s, nth);
}
+/** Check whether expression matches a specified pattern. */
+bool ex::match(const ex & pattern) const
+{
+ lst repl_lst;
+ return bp->match(pattern, repl_lst);
+}
+
/** Simplify/canonicalize expression containing indexed objects. This
* performs contraction of dummy indices where possible and checks whether
* the free indices in sums are consistent.
ex evalf(int level = 0) const { return bp->evalf(level); }
ex diff(const symbol & s, unsigned nth = 1) const;
ex series(const ex & r, int order, unsigned options = 0) const;
+ bool match(const ex & pattern) const;
bool match(const ex & pattern, lst & repl_lst) const { return bp->match(pattern, repl_lst); }
ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const { return bp->subs(ls, lr, no_pattern); }
ex subs(const ex & e, bool no_pattern = false) const { return bp->subs(e, no_pattern); }
bool expairseq::match(const ex & pattern, lst & repl_lst) const
{
-//clog << "match " << *this << " with " << pattern << ", repl_lst = " << repl_lst << endl;
// This differs from basic::match() because we want "a+b+c+d" to
// match "d+*+b" with "*" being "a+c", and we want to honor commutativity
/** Member-wise substitute in this sequence.
*
* @see expairseq::subs()
- * @return pointer to epvector containing pairs after application of subs or zero
- * pointer, if no members were changed. */
+ * @return pointer to epvector containing pairs after application of subs,
+ * or NULL pointer if no members were changed. */
epvector * expairseq::subschildren(const lst &ls, const lst &lr, bool no_pattern) const
{
- // returns a NULL pointer if nothing had to be substituted
- // returns a pointer to a newly created epvector otherwise
- // (which has to be deleted somewhere else)
GINAC_ASSERT(ls.nops()==lr.nops());
-
- epvector::const_iterator last = seq.end();
- epvector::const_iterator cit = seq.begin();
- while (cit!=last) {
- const ex &subsed_ex=(*cit).rest.subs(ls,lr,no_pattern);
- if (!are_ex_trivially_equal((*cit).rest,subsed_ex)) {
+
+ // The substitution is "complex" when any of the objects to be substituted
+ // is a product or power. In this case we have to recombine the pairs
+ // because the numeric coefficients may be part of the search pattern.
+ bool complex_subs = false;
+ for (unsigned i=0; i<ls.nops(); i++)
+ if (is_ex_exactly_of_type(ls.op(i), mul) || is_ex_exactly_of_type(ls.op(i), power)) {
+ complex_subs = true;
+ break;
+ }
+
+ if (complex_subs) {
+
+ // Substitute in the recombined pairs
+ epvector::const_iterator cit = seq.begin(), last = seq.end();
+ while (cit != last) {
+
+ const ex &orig_ex = recombine_pair_to_ex(*cit);
+ const ex &subsed_ex = orig_ex.subs(ls, lr, no_pattern);
+ if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
+
+ // Something changed, copy seq, subs and return it
+ epvector *s = new epvector;
+ s->reserve(seq.size());
+
+ // Copy parts of seq which are known not to have changed
+ s->insert(s->begin(), seq.begin(), cit);
+
+ // Copy first changed element
+ s->push_back(split_ex_to_pair(subsed_ex));
+ ++cit;
+
+ // Copy rest
+ while (cit != last) {
+ s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(ls, lr, no_pattern)));
+ ++cit;
+ }
+ return s;
+ }
+
+ ++cit;
+ }
+
+ } else {
+
+ // Substitute only in the "rest" part of the pairs
+ epvector::const_iterator cit = seq.begin(), last = seq.end();
+ while (cit != last) {
+
+ const ex &subsed_ex = cit->rest.subs(ls, lr, no_pattern);
+ if (!are_ex_trivially_equal(cit->rest, subsed_ex)) {
- // something changed, copy seq, subs and return it
- epvector *s = new epvector;
- s->reserve(seq.size());
+ // Something changed, copy seq, subs and return it
+ epvector *s = new epvector;
+ s->reserve(seq.size());
+
+ // Copy parts of seq which are known not to have changed
+ s->insert(s->begin(), seq.begin(), cit);
- // copy parts of seq which are known not to have changed
- epvector::const_iterator cit2 = seq.begin();
- while (cit2!=cit) {
- s->push_back(*cit2);
- ++cit2;
- }
- // copy first changed element
- s->push_back(combine_ex_with_coeff_to_pair(subsed_ex,
- (*cit2).coeff));
- ++cit2;
- // copy rest
- while (cit2!=last) {
- s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.subs(ls,lr,no_pattern),
- (*cit2).coeff));
- ++cit2;
+ // Copy first changed element
+ s->push_back(combine_ex_with_coeff_to_pair(subsed_ex, cit->coeff));
+ ++cit;
+
+ // Copy rest
+ while (cit != last) {
+ s->push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(ls, lr, no_pattern),
+ cit->coeff));
+ ++cit;
+ }
+ return s;
}
- return s;
+
+ ++cit;
}
- ++cit;
}
- return 0; // signalling nothing has changed
+ // Nothing has changed
+ return NULL;
}
//////////
GINAC_ASSERT(is_of_type(other, spinidx));
const spinidx &o = static_cast<const spinidx &>(other);
+ // Check dottedness first so dummy indices will end up next to each other
+ if (dotted != o.dotted)
+ return dotted ? -1 : 1;
+
int cmpval = inherited::compare_same_type(other);
if (cmpval)
return cmpval;
- // Check variance and dottedness last so dummy indices will end up next to each other
+ return 0;
+}
+
+bool idx::match(const ex & pattern, lst & repl_lst) 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);
+}
+
+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)
- return covariant ? -1 : 1;
- if (dotted != o.dotted)
- return dotted ? -1 : 1;
+ return false;
+ return inherited::match(pattern, repl_lst);
+}
- return 0;
+bool spinidx::match(const ex & pattern, lst & repl_lst) 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);
}
ex idx::subs(const lst & ls, const lst & lr, bool no_pattern) const
bool info(unsigned inf) const;
unsigned nops() const;
ex & let_op(int i);
-protected:
+ bool match(const ex & pattern, lst & repl_lst) const;
ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
// new virtual functions in this class
// 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;
// non-virtual functions in this class
// 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;
// non-virtual functions in this class