@cindex container
@cindex atom
-To get an idea about what kinds of symbolic composits may be built we
+To get an idea about what kinds of symbolic composites may be built we
have a look at the most important classes in the class hierarchy and
some of the relations among the classes:
For storing numerical things, GiNaC uses Bruno Haible's library CLN.
The classes therein serve as foundation classes for GiNaC. CLN stands
for Class Library for Numbers or alternatively for Common Lisp Numbers.
-In order to find out more about CLN's internals the reader is refered to
+In order to find out more about CLN's internals, the reader is referred to
the documentation of that library. @inforef{Introduction, , cln}, for
more information. Suffice to say that it is by itself build on top of
another library, the GNU Multiple Precision library GMP, which is an
that in both cases you got a couple of extra digits. This is because
numbers are internally stored by CLN as chunks of binary digits in order
to match your machine's word size and to not waste precision. Thus, on
-architectures with differnt word size, the above output might even
+architectures with different word size, the above output might even
differ with regard to actually computed digits.
It should be clear that objects of class @code{numeric} should be used
are also valid patterns.
@end itemize
+@subsection Matching expressions
@cindex @code{match()}
The most basic application of patterns is to check whether an expression
matches a given pattern. This is done by the function
@{$0==x^2@}
@end example
+@subsection Matching parts of expressions
@cindex @code{has()}
A more general way to look for patterns in expressions is provided by the
member function
@{sin(y),sin(x)@}
@end example
+@subsection Substituting expressions
@cindex @code{subs()}
Probably the most useful application of patterns is to use them for
substituting expressions with the @code{subs()} method. Wildcards can be
@}
@end example
+@subsection Algebraic substitutions
+This subsection is not written by one of the original authors of GiNaC but
+by Chris Dams. All errors in the here described feature can be attributed to
+him (but mailed to the GiNaC mailing list, which he reads).
+
+The @code{subs()} method has an extra, optional, argument. This
+argument can be used to pass one of the @code{subs_options} to it.
+The only option that is currently
+available is the @code{subs_smart} option and it affects multiplications
+and powers. If you want to substitute some factors of a multiplication, you
+only need to list these factors in your pattern. Furthermore if a(n) (integer)
+power of some expression occurs in your pattern and in the expression that
+you want the substitution to occur in, it can be substituted as many times
+as possible, without getting negative powers.
+
+An example clarifies it all (hopefully).
+
+@example
+cout << (a*a*a*a+b*b*b*b+pow(x+y,4)).subs(wild()*wild()==pow(wild(),3),
+ subs_options::subs_smart) << endl;
+// --> (y+x)^6+b^6+a^6
+
+cout << ((a+b+c)*(a+b+c)).subs(a+b==x,subs_options::subs_smart) << endl;
+// --> (c+b+a)^2
+// Powers and multiplications are smart, but addition is just the same.
+
+cout << ((a+b+c)*(a+b+c)).subs(a+b+wild()==x+wild(), subs_options::subs_smart)
+ << endl;
+// --> (x+c)^2
+// As I said: addition is just the same.
+
+cout << (pow(a,5)*pow(b,7)+2*b).subs(b*b*a==x,subs_options::subs_smart) << endl;
+// --> x^3*b*a^2+2*b
+
+cout << (pow(a,-5)*pow(b,-7)+2*b).subs(1/(b*b*a)==x,subs_options::subs_smart)
+ << endl;
+// --> 2*b+x^3*b^(-1)*a^(-2)
+
+cout << (4*x*x*x-2*x*x+5*x-1).subs(x==a,subs_options::subs_smart)
+ << endl;
+// --> -1-2*a^2+4*a^3+5*a
+
+cout << (4*x*x*x-2*x*x+5*x-1).subs(pow(x,wild())==pow(a,wild()),
+ subs_options::subs_smart) << endl;
+// --> -1+5*x+4*x^3-2*x^2
+// You should not really need this kind of patterns very often now.
+// But perhaps this it's-not-a-bug-it's-a-feature (c/sh)ould still change.
+
+cout << ex(sin(1+sin(x))).subs(sin(wild())==cos(wild()),
+ subs_options::subs_smart) << endl;
+// --> cos(1+cos(x))
+
+cout << expand((a*sin(x+y)*sin(x+y)+a*cos(x+y)*cos(x+y)+b)
+ .subs((pow(cos(wild()),2)==1-pow(sin(wild()),2)),
+ subs_options::subs_smart)) << endl;
+// --> b+a
+@end example
@node Applying a Function on Subexpressions, Polynomial Arithmetic, Pattern Matching and Advanced Substitutions, Methods and Functions
@c node-name, next, previous, up
@end example
This @file{Makefile.am}, says that we are building a single executable,
-from a single sourcefile @file{simple.cpp}. Since every program
+from a single source file @file{simple.cpp}. Since every program
we are building uses GiNaC we simply added the GiNaC options
to @env{$LIBS} and @env{$CPPFLAGS}, but in other circumstances, we might
want to specify them on a per-program basis: for instance by
/** Substitute a set of objects by arbitrary expressions. The ex returned
* will already be evaluated. */
-ex basic::subs(const lst & ls, const lst & lr, bool no_pattern) const
+ex basic::subs(const lst & ls, const lst & lr, unsigned options) const
{
GINAC_ASSERT(ls.nops() == lr.nops());
- if (no_pattern) {
+ if (options & subs_options::subs_no_pattern) {
for (unsigned i=0; i<ls.nops(); i++) {
if (is_equal(ex_to<basic>(ls.op(i))))
return lr.op(i);
for (unsigned i=0; i<ls.nops(); i++) {
lst repl_lst;
if (match(ex_to<basic>(ls.op(i)), repl_lst))
- return lr.op(i).subs(repl_lst, true); // avoid infinite recursion when re-substituting the wildcards
+ return lr.op(i).subs(repl_lst, options | subs_options::subs_no_pattern); // avoid infinite recursion when re-substituting the wildcards
}
}
* replacement arguments: 1) a relational like object==ex and 2) a list of
* relationals lst(object1==ex1,object2==ex2,...), which is converted to
* subs(lst(object1,object2,...),lst(ex1,ex2,...)). */
-ex basic::subs(const ex & e, bool no_pattern) const
+ex basic::subs(const ex & e, unsigned options) const
{
if (e.info(info_flags::relation_equal)) {
- return subs(lst(e), no_pattern);
+ return subs(lst(e), options);
}
if (!e.info(info_flags::list)) {
throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
ls.append(r.op(0));
lr.append(r.op(1));
}
- return subs(ls, lr, no_pattern);
+ return subs(ls, lr, options);
}
/** Compare objects syntactically to establish canonical ordering.
virtual ex evalm(void) const;
virtual ex series(const relational & r, int order, unsigned options = 0) const;
virtual bool match(const ex & pattern, lst & repl_lst) const;
- virtual ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ virtual ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
virtual ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
virtual ex to_rational(lst &repl_lst) const;
virtual numeric integer_content(void) const;
// non-virtual functions in this class
public:
- ex subs(const ex & e, bool no_pattern = false) const;
+ ex subs(const ex & e, unsigned options = 0) const;
ex diff(const symbol & s, unsigned nth=1) const;
int compare(const basic & other) const;
bool is_equal(const basic & other) const;
ex & let_op(int i);
ex map(map_function & f) const;
ex eval(int level=0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
protected:
bool is_equal_same_type(const basic & other) const;
unsigned return_type(void) const;
protected:
bool is_canonical() const;
${STLT} evalchildren(int level) const;
- ${STLT} * subschildren(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ${STLT} * subschildren(const lst & ls, const lst & lr, unsigned options = 0) const;
protected:
${STLT} seq;
return this${CONTAINER}(evalchildren(level));
}
-ex ${CONTAINER}::subs(const lst & ls, const lst & lr, bool no_pattern) const
-{
- ${STLT} *vp = subschildren(ls, lr, no_pattern);
+ex ${CONTAINER}::subs(const lst & ls, const lst & lr, unsigned options) const
+{
+ ${STLT} *vp = subschildren(ls, lr, options);
if (vp)
- return ex_to<basic>(this${CONTAINER}(vp)).basic::subs(ls, lr, no_pattern);
+ return ex_to<basic>(this${CONTAINER}(vp)).basic::subs(ls, lr, options);
else
- return basic::subs(ls, lr, no_pattern);
+ return basic::subs(ls, lr, options);
}
// protected
return s;
}
-${STLT} * ${CONTAINER}::subschildren(const lst & ls, const lst & lr, bool no_pattern) const
+${STLT} * ${CONTAINER}::subschildren(const lst & ls, const lst & lr, unsigned options) const
{
// returns a NULL pointer if nothing had to be substituted
// returns a pointer to a newly created epvector otherwise
${STLT}::const_iterator cit = seq.begin(), end = seq.end();
while (cit != end) {
- const ex & subsed_ex = cit->subs(ls, lr, no_pattern);
+ const ex & subsed_ex = cit->subs(ls, lr, options);
if (!are_ex_trivially_equal(*cit, subsed_ex)) {
// something changed, copy seq, subs and return it
// copy rest
while (cit2 != end) {
- s->push_back(cit2->subs(ls, lr, no_pattern));
+ s->push_back(cit2->subs(ls, lr, options));
++cit2;
}
return s;
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); }
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const { return bp->subs(ls, lr, options); }
+ ex subs(const ex & e, unsigned options = 0) const { return bp->subs(e, options); }
exvector get_free_indices(void) const { return bp->get_free_indices(); }
ex simplify_indexed(void) const;
ex simplify_indexed(const scalar_products & sp) const;
inline bool match(const ex & thisex, const ex & pattern, lst & repl_lst)
{ return thisex.match(pattern, repl_lst); }
-inline ex subs(const ex & thisex, const ex & e)
-{ return thisex.subs(e); }
+inline ex subs(const ex & thisex, const ex & e, unsigned options = 0)
+{ return thisex.subs(e, options); }
-inline ex subs(const ex & thisex, const lst & ls, const lst & lr)
-{ return thisex.subs(ls, lr); }
+inline ex subs(const ex & thisex, const lst & ls, const lst & lr, unsigned options = 0)
+{ return thisex.subs(ls, lr, options); }
inline ex simplify_indexed(const ex & thisex)
{ return thisex.simplify_indexed(); }
return inherited::match(pattern, repl_lst);
}
-ex expairseq::subs(const lst &ls, const lst &lr, bool no_pattern) const
-{
- epvector *vp = subschildren(ls, lr, no_pattern);
+ex expairseq::subs(const lst &ls, const lst &lr, unsigned options) const
+{
+ if ((options & subs_options::subs_algebraic) && is_exactly_a<mul>(*this))
+ return static_cast<const mul *>(this)->algebraic_subs_mul(ls, lr, options);
+
+ epvector *vp = subschildren(ls, lr, options);
if (vp)
return ex_to<basic>(thisexpairseq(vp, overall_coeff));
else
- return basic::subs(ls, lr, no_pattern);
+ return basic::subs(ls, lr, options);
}
// protected
* @see expairseq::subs()
* @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
+epvector * expairseq::subschildren(const lst &ls, const lst &lr, unsigned options) const
{
GINAC_ASSERT(ls.nops()==lr.nops());
// 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)
+ for (unsigned i=0; i<ls.nops(); ++i) {
if (is_exactly_a<mul>(ls.op(i)) || is_exactly_a<power>(ls.op(i))) {
complex_subs = true;
break;
}
+ }
if (complex_subs) {
while (cit != last) {
const ex &orig_ex = recombine_pair_to_ex(*cit);
- const ex &subsed_ex = orig_ex.subs(ls, lr, no_pattern);
+ const ex &subsed_ex = orig_ex.subs(ls, lr, options);
if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
// Something changed, copy seq, subs and return it
// Copy rest
while (cit != last) {
- s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(ls, lr, no_pattern)));
+ s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(ls, lr, options)));
++cit;
}
return s;
epvector::const_iterator cit = seq.begin(), last = seq.end();
while (cit != last) {
- const ex &subsed_ex = cit->rest.subs(ls, lr, no_pattern);
+ const ex &subsed_ex = cit->rest.subs(ls, lr, options);
if (!are_ex_trivially_equal(cit->rest, subsed_ex)) {
// Something changed, copy seq, subs and return it
// Copy rest
while (cit != last) {
- s->push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(ls, lr, no_pattern),
+ s->push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(ls, lr, options),
cit->coeff));
++cit;
}
ex eval(int level=0) const;
ex to_rational(lst &repl_lst) const;
bool match(const ex & pattern, lst & repl_lst) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
protected:
int compare_same_type(const basic & other) const;
bool is_equal_same_type(const basic & other) const;
bool is_canonical() const;
epvector * expandchildren(unsigned options) const;
epvector * evalchildren(int level) const;
- epvector * subschildren(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ epvector * subschildren(const lst & ls, const lst & lr, unsigned options = 0) const;
// member variables
namespace GiNaC {
+/** Flags to control the behavior of expand(). */
class expand_options {
public:
enum {
};
};
+/** Flags to control the behavior of subs(). */
+class subs_options {
+public:
+ enum {
+ subs_no_pattern = 0x0001,
+ subs_algebraic = 0x0002
+ };
+};
+
/** Flags to control series expansion. */
class series_options {
public:
return *this;
}
-ex idx::subs(const lst & ls, const lst & lr, bool no_pattern) const
+ex idx::subs(const lst & ls, const lst & lr, unsigned options) const
{
GINAC_ASSERT(ls.nops() == lr.nops());
}
// None, substitute objects in value (not in dimension)
- const ex &subsed_value = value.subs(ls, lr, no_pattern);
+ const ex &subsed_value = value.subs(ls, lr, options);
if (are_ex_trivially_equal(value, subsed_value))
return *this;
unsigned nops() const;
ex & let_op(int i);
ex evalf(int level = 0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
protected:
ex derivative(const symbol & s) const;
status_flags::evaluated);
}
-ex matrix::subs(const lst & ls, const lst & lr, bool no_pattern) const
-{
+ex matrix::subs(const lst & ls, const lst & lr, unsigned options) const
+{
exvector m2(row * col);
for (unsigned r=0; r<row; ++r)
for (unsigned c=0; c<col; ++c)
- m2[r*col+c] = m[r*col+c].subs(ls, lr, no_pattern);
+ m2[r*col+c] = m[r*col+c].subs(ls, lr, options);
- return matrix(row, col, m2).basic::subs(ls, lr, no_pattern);
+ return matrix(row, col, m2).basic::subs(ls, lr, options);
}
// protected
ex & let_op(int i);
ex eval(int level=0) const;
ex evalm(void) const {return *this;}
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
ex 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;
#include <iostream>
#include <vector>
#include <stdexcept>
+#include <limits>
#include "mul.h"
#include "add.h"
#include "power.h"
#include "operators.h"
#include "matrix.h"
+#include "lst.h"
#include "archive.h"
#include "utils.h"
return inherited::eval_ncmul(v);
}
+bool tryfactsubs(const ex & origfactor, const ex & patternfactor, unsigned & nummatches, lst & repls)
+{
+ ex origbase;
+ int origexponent;
+ int origexpsign;
+
+ if (is_exactly_a<power>(origfactor) && origfactor.op(1).info(info_flags::integer)) {
+ origbase = origfactor.op(0);
+ int expon = ex_to<numeric>(origfactor.op(1)).to_int();
+ origexponent = expon > 0 ? expon : -expon;
+ origexpsign = expon > 0 ? 1 : -1;
+ } else {
+ origbase = origfactor;
+ origexponent = 1;
+ origexpsign = 1;
+ }
+
+ ex patternbase;
+ int patternexponent;
+ int patternexpsign;
+
+ if (is_exactly_a<power>(patternfactor) && patternfactor.op(1).info(info_flags::integer)) {
+ patternbase = patternfactor.op(0);
+ int expon = ex_to<numeric>(patternfactor.op(1)).to_int();
+ patternexponent = expon > 0 ? expon : -expon;
+ patternexpsign = expon > 0 ? 1 : -1;
+ } else {
+ patternbase = patternfactor;
+ patternexponent = 1;
+ patternexpsign = 1;
+ }
+
+ lst saverepls = repls;
+ if (origexponent < patternexponent || origexpsign != patternexpsign || !origbase.match(patternbase,saverepls))
+ return false;
+ repls = saverepls;
+
+ int newnummatches = origexponent / patternexponent;
+ if (newnummatches < nummatches)
+ nummatches = newnummatches;
+ return true;
+}
+
+ex mul::algebraic_subs_mul(const lst & ls, const lst & lr, unsigned options) const
+{
+ std::vector<bool> subsed(seq.size(), false);
+ exvector subsresult(seq.size());
+
+ for (int i=0; i<ls.nops(); i++) {
+
+ if (is_exactly_a<mul>(ls.op(i))) {
+
+ unsigned nummatches = std::numeric_limits<unsigned>::max();
+ std::vector<bool> currsubsed(seq.size(), false);
+ bool succeed = true;
+ lst repls;
+
+ for (int j=0; j<ls.op(i).nops(); j++) {
+ bool found=false;
+ for (int k=0; k<nops(); k++) {
+ if (currsubsed[k] || subsed[k])
+ continue;
+ if (tryfactsubs(op(k), ls.op(i).op(j), nummatches, repls)) {
+ currsubsed[k] = true;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ succeed = false;
+ break;
+ }
+ }
+ if (!succeed)
+ continue;
+
+ bool foundfirstsubsedfactor = false;
+ for (int j=0; j<subsed.size(); j++) {
+ if (currsubsed[j]) {
+ if (foundfirstsubsedfactor)
+ subsresult[j] = op(j);
+ else {
+ foundfirstsubsedfactor = true;
+ subsresult[j] = op(j) * power(lr.op(i).subs(ex(repls), subs_options::subs_no_pattern) / ls.op(i).subs(ex(repls), subs_options::subs_no_pattern), nummatches);
+ }
+ subsed[j] = true;
+ }
+ }
+
+ } else {
+
+ unsigned nummatches = std::numeric_limits<unsigned>::max();
+ lst repls;
+
+ for (int j=0; j<this->nops(); j++) {
+ if (!subsed[j] && tryfactsubs(op(j), ls.op(i), nummatches, repls)) {
+ subsed[j] = true;
+ subsresult[j] = op(j) * power(lr.op(i).subs(ex(repls), subs_options::subs_no_pattern) / ls.op(i).subs(ex(repls), subs_options::subs_no_pattern), nummatches);
+ }
+ }
+ }
+ }
+
+ bool subsfound = false;
+ for (int i=0; i<subsed.size(); i++) {
+ if (subsed[i]) {
+ subsfound = true;
+ break;
+ }
+ }
+ if (!subsfound)
+ return basic::subs(ls, lr, options | subs_options::subs_algebraic);
+
+ exvector ev; ev.reserve(nops());
+ for (int i=0; i<nops(); i++) {
+ if (subsed[i])
+ ev.push_back(subsresult[i]);
+ else
+ ev.push_back(op(i));
+ }
+
+ return (new mul(ev))->setflag(status_flags::dynallocated);
+}
+
// protected
/** Implementation of ex::diff() for a product. It applies the product rule.
// none
// non-virtual functions in this class
+public:
+ ex algebraic_subs_mul(const lst & ls, const lst & lr, unsigned options) const;
protected:
epvector * expandchildren(unsigned options) const;
};
#include <vector>
#include <iostream>
#include <stdexcept>
+#include <limits>
#include "power.h"
#include "expairseq.h"
#include "matrix.h"
#include "indexed.h"
#include "symbol.h"
+#include "lst.h"
#include "print.h"
#include "archive.h"
#include "utils.h"
return (new power(ebasis, eexponent))->setflag(status_flags::dynallocated);
}
-ex power::subs(const lst & ls, const lst & lr, bool no_pattern) const
+extern bool tryfactsubs(const ex &, const ex &, unsigned &, lst &);
+
+ex power::subs(const lst & ls, const lst & lr, unsigned options) const
{
- const ex &subsed_basis = basis.subs(ls, lr, no_pattern);
- const ex &subsed_exponent = exponent.subs(ls, lr, no_pattern);
+ if (options & subs_options::subs_algebraic) {
+ for (int i=0; i<ls.nops(); i++) {
+ unsigned nummatches = std::numeric_limits<unsigned>::max();
+ lst repls;
+ if (tryfactsubs(*this, ls.op(i), nummatches, repls))
+ return (ex_to<basic>((*this) * power(lr.op(i).subs(ex(repls), subs_options::subs_no_pattern) / ls.op(i).subs(ex(repls), subs_options::subs_no_pattern), nummatches))).basic::subs(ls, lr, options);
+ }
+ return basic::subs(ls, lr, options);
+ }
+
+ const ex &subsed_basis = basis.subs(ls, lr, options);
+ const ex &subsed_exponent = exponent.subs(ls, lr, options);
if (are_ex_trivially_equal(basis, subsed_basis)
&& are_ex_trivially_equal(exponent, subsed_exponent))
- return basic::subs(ls, lr, no_pattern);
+ return basic::subs(ls, lr, options);
else
- return power(subsed_basis, subsed_exponent).basic::subs(ls, lr, no_pattern);
+ return power(subsed_basis, subsed_exponent).basic::subs(ls, lr, options);
}
ex power::eval_ncmul(const exvector & v) const
ex evalf(int level=0) const;
ex evalm(void) const;
ex series(const relational & s, int order, unsigned options = 0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
ex to_rational(lst &repl_lst) const;
exvector get_free_indices(void) const;
return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
}
-ex pseries::subs(const lst & ls, const lst & lr, bool no_pattern) const
+ex pseries::subs(const lst & ls, const lst & lr, unsigned options) const
{
// If expansion variable is being substituted, convert the series to a
// polynomial and do the substitution there because the result might
// no longer be a power series
if (ls.has(var))
- return convert_to_poly(true).subs(ls, lr, no_pattern);
+ return convert_to_poly(true).subs(ls, lr, options);
// Otherwise construct a new series with substituted coefficients and
// expansion point
newseq.reserve(seq.size());
epvector::const_iterator it = seq.begin(), itend = seq.end();
while (it != itend) {
- newseq.push_back(expair(it->rest.subs(ls, lr, no_pattern), it->coeff));
+ newseq.push_back(expair(it->rest.subs(ls, lr, options), it->coeff));
++it;
}
- return (new pseries(relational(var,point.subs(ls, lr, no_pattern)), newseq))->setflag(status_flags::dynallocated);
+ return (new pseries(relational(var,point.subs(ls, lr, options)), newseq))->setflag(status_flags::dynallocated);
}
/** Implementation of ex::expand() for a power series. It expands all the
ex eval(int level=0) const;
ex evalf(int level=0) const;
ex series(const relational & r, int order, unsigned options = 0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
ex expand(unsigned options = 0) const;
protected: