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
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
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
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;
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));
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,
// 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++)
* 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
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);
}
}
GINAC_ASSERT(typeid(*this)==typeid(other));
- return this->is_equal_same_type(other);
+ return is_equal_same_type(other);
}
// protected
* @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
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;
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) {
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)
// 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;
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) {
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)
// 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;
$STLHEADER="vector";
$reserve=1;
$prepend=0;
+ $sort=0;
$let_op=0;
$open_bracket='(';
$close_bracket=')';
$STLHEADER="list";
$reserve=0;
$prepend=1;
+ $sort=1;
$let_op=1;
$open_bracket='{';
$close_bracket='}';
seq.push_front(b);
return *this;
}
+
${CONTAINER} & ${CONTAINER}::remove_first(void)
{
ensure_if_modifiable();
$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)
* \$STLHEADER=${STLHEADER}
* \$reserve=${reserve}
* \$prepend=${prepend}
+ * \$sort=${sort}
* \$let_op=${let_op}
* \$open_bracket=${open_bracket}
* \$close_bracket=${close_bracket}
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,
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();
${PREPEND_IMPLEMENTATION}
+${SORT_IMPLEMENTATION}
+
// protected
void ${CONTAINER}::printseq(const print_context & c, char openbracket, char delim,
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);
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);
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); }
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); }
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);
}
public:
enum {
expand_trigonometric = 0x0001,
- expand_indexed = 0x0002
+ expand_indexed = 0x0002,
+ expand_function_args = 0x0004
};
};
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;
friend class remember_table_entry;
// friend class remember_table_list;
// friend class remember_table;
+ friend ex Derivative_eval(const ex &, const ex &);
// member functions
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;
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
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 */
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
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
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));
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));
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
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:
// 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. */
// 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. */
// 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
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
{
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:
ex mul::expand(unsigned options) const
{
- if (flags & status_flags::expanded)
+ if (options == 0 && (flags & status_flags::expanded))
return *this;
exvector sub_expanded_seq;
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;
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));
}
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;
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;
}
return (new add(distrseq))->setflag(status_flags::dynallocated |
- status_flags::expanded);
+ (options == 0 ? status_flags::expanded : 0));
}
int ncmul::degree(const ex & s) 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);
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));
}
}
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));
}
//////////
++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
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());
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;
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;
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;
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);
}
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)
// 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;}
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
.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
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);
{"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)},