#include "add.h"
#include "mul.h"
+#include "matrix.h"
#include "archive.h"
#include "debugmsg.h"
#include "utils.h"
return this->hold();
}
+ex add::evalm(void) const
+{
+ // Evaluate children first and add up all matrices. Stop if there's one
+ // term that is not a matrix.
+ epvector *s = new epvector;
+ s->reserve(seq.size());
+
+ bool all_matrices = true;
+ bool first_term = true;
+ matrix sum;
+
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ const ex &m = recombine_pair_to_ex(*it).evalm();
+ s->push_back(split_ex_to_pair(m));
+ if (is_ex_of_type(m, matrix)) {
+ if (first_term) {
+ sum = ex_to_matrix(m);
+ first_term = false;
+ } else
+ sum = sum.add(ex_to_matrix(m));
+ } else
+ all_matrices = false;
+ it++;
+ }
+
+ if (all_matrices)
+ return sum + overall_coeff;
+ else
+ return (new add(s, overall_coeff))->setflag(status_flags::dynallocated);
+}
+
ex add::simplify_ncmul(const exvector & v) const
{
if (seq.size()==0) {
int ldegree(const ex & s) const;
ex coeff(const ex & s, int n=1) const;
ex eval(int level=0) const;
+ ex evalm(void) const;
ex series(const relational & r, int order, unsigned options = 0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
numeric integer_content(void) const;
{
GINAC_ASSERT(other.bp!=0);
lst repl_lst;
- if (match(*other.bp, repl_lst)) return true;
- if (nops()>0) {
- for (unsigned i=0; i<nops(); i++)
- if (op(i).has(other))
- return true;
- }
+ if (match(*other.bp, repl_lst))
+ return true;
+ for (unsigned i=0; i<nops(); i++)
+ if (op(i).has(other))
+ return true;
return false;
}
+/** Construct new expression by applying the specified function to all
+ * sub-expressions. */
+ex basic::map(map_func f) const
+{
+ unsigned num = nops();
+ if (num == 0)
+ return *this;
+
+ basic *copy = duplicate();
+ copy->setflag(status_flags::dynallocated);
+ copy->clearflag(status_flags::hash_calculated);
+ ex e(*copy);
+ for (unsigned i=0; i<num; i++)
+ e.let_op(i) = f(e.op(i));
+ return e.eval();
+}
+
/** Return degree of highest power in object s. */
int basic::degree(const ex & s) const
{
return *this;
}
+/** Evaluate sums and products of matrices. */
+ex basic::evalm(void) const
+{
+ unsigned num = nops();
+ if (num == 0)
+ return *this;
+ else
+ return map(GiNaC::evalm);
+}
+
/** Perform automatic symbolic evaluations on indexed expression that
* contains this object as the base expression. */
ex basic::eval_indexed(const basic & i) const
typedef std::vector<ex> exvector;
#endif
+typedef ex (*map_func)(const ex & e);
+
/** This class is the ABC (abstract base class) of GiNaC's class hierarchy.
* It is responsible for the reference counting. */
class basic
virtual ex operator[](const ex & index) const;
virtual ex operator[](int i) const;
virtual bool has(const ex & other) const;
+ virtual ex map(map_func f) const;
virtual int degree(const ex & s) const;
virtual int ldegree(const ex & s) const;
virtual ex coeff(const ex & s, int n = 1) const;
virtual ex collect(const ex & s, bool distributed = false) const;
virtual ex eval(int level = 0) const;
virtual ex evalf(int level = 0) const;
+ 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;
$reserve=0;
$prepend=1;
$let_op=1;
- $open_bracket='[';
- $close_bracket=']';
+ $open_bracket='{';
+ $close_bracket='}';
} else {
die "invalid type $type";
bool info(unsigned inf) const;
unsigned nops() const;
ex & let_op(int i);
+ ex map(map_func f) const;
ex expand(unsigned options=0) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
${LET_OP_IMPLEMENTATION}
+ex ${CONTAINER}::map(map_func f) const
+{
+ ${STLT} s;
+ RESERVE(s,seq.size());
+ for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ s.push_back(f(*it));
+ }
+
+ return this${CONTAINER}(s);
+}
+
ex ${CONTAINER}::expand(unsigned options) const
{
${STLT} s;
unsigned nops() const { return bp->nops(); }
ex expand(unsigned options=0) const;
bool has(const ex & other) const { return bp->has(other); }
+ ex map(map_func f) const { return bp->map(f); }
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); }
ex collect(const ex & s, bool distributed = false) const { return bp->collect(s, distributed); }
ex eval(int level = 0) const { return bp->eval(level); }
ex evalf(int level = 0) const { return bp->evalf(level); }
+ ex evalm(void) const { return bp->evalm(); }
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;
inline ex evalf(const ex & thisex, int level = 0)
{ return thisex.evalf(level); }
+inline ex evalm(const ex & thisex)
+{ return thisex.evalm(); }
+
inline ex diff(const ex & thisex, const symbol & s, unsigned nth = 1)
{ return thisex.diff(s, nth); }
throw(std::logic_error("let_op not defined for expairseq and derived classes (add,mul,...)"));
}
+ex expairseq::map(map_func f) const
+{
+ epvector *v = new epvector;
+ v->reserve(seq.size());
+
+ epvector::const_iterator cit = seq.begin(), last = seq.end();
+ while (cit != last) {
+ v->push_back(split_ex_to_pair(f(recombine_pair_to_ex(*cit))));
+ cit++;
+ }
+
+ return thisexpairseq(v, f(overall_coeff));
+}
+
ex expairseq::eval(int level) const
{
if ((level==1) && (flags &status_flags::evaluated))
unsigned nops() const;
ex op(int i) const;
ex & let_op(int i);
+ ex map(map_func f) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
return sollist;
}
-/** non-commutative power. */
-ex ncpow(const ex & basis, unsigned exponent)
-{
- if (exponent == 0)
- return _ex1();
-
- exvector v;
- v.reserve(exponent);
- for (unsigned i=0; i<exponent; ++i)
- v.push_back(basis);
-
- return ncmul(v, true);
-}
-
// Symmetrize/antisymmetrize over a vector of objects
static ex symm(const ex & e, exvector::const_iterator first, exvector::const_iterator last, bool asymmetric)
{
ex lsolve(const ex &eqns, const ex &symbols);
-/** Power of non-commutative basis. */
-ex ncpow(const ex & basis, unsigned exponent);
-
/** Symmetrize expression over a set of objects (symbols, indices). */
ex symmetrize(const ex & e, exvector::const_iterator first, exvector::const_iterator last);
"<=" return T_LESSEQ;
">=" return T_GREATEREQ;
- /* matrix delimiters */
-\[\[ return T_MATRIX_BEGIN;
-\]\] return T_MATRIX_END;
-
/* numbers */
{D}+ |
"#"{D}+"R"{AN}+ |
/* Tokens (T_LITERAL means a literal value returned by the parser, but not
of class numeric or symbol (e.g. a constant or the FAIL object)) */
-%token T_NUMBER T_SYMBOL T_LITERAL T_DIGITS T_EQUAL T_NOTEQ T_LESSEQ T_GREATEREQ T_MATRIX_BEGIN T_MATRIX_END
+%token T_NUMBER T_SYMBOL T_LITERAL T_DIGITS T_EQUAL T_NOTEQ T_LESSEQ T_GREATEREQ
/* Operator precedence and associativity */
%right '='
| exp '^' exp {$$ = pow($1, $3);}
| exp '!' {$$ = factorial($1);}
| '(' exp ')' {$$ = $2;}
- | '[' list_or_empty ']' {$$ = $2;}
- | T_MATRIX_BEGIN matrix T_MATRIX_END {$$ = lst_to_matrix(ex_to_lst($2));}
+ | '{' list_or_empty '}' {$$ = $2;}
+ | '[' matrix ']' {$$ = lst_to_matrix(ex_to_lst($2));}
;
exprseq : exp {$$ = exprseq($1);}
| list ',' exp {lst l(static_cast<lst &>(*($1.bp))); $$ = l.append($3);}
;
-matrix : T_MATRIX_BEGIN row T_MATRIX_END {$$ = lst($2);}
- | matrix ',' T_MATRIX_BEGIN row T_MATRIX_END {lst l(static_cast<lst &>(*($1.bp))); $$ = l.append($4);}
+matrix : '[' row ']' {$$ = lst($2);}
+ | matrix ',' '[' row ']' {lst l(static_cast<lst &>(*($1.bp))); $$ = l.append($4);}
;
row : exp {$$ = lst($1);}
} else {
- c.s << "[[ ";
+ c.s << "[";
for (unsigned y=0; y<row-1; ++y) {
- c.s << "[[";
+ c.s << "[";
for (unsigned x=0; x<col-1; ++x) {
m[y*col+x].print(c);
c.s << ",";
}
m[col*(y+1)-1].print(c);
- c.s << "]], ";
+ c.s << "],";
}
- c.s << "[[";
+ c.s << "[";
for (unsigned x=0; x<col-1; ++x) {
m[(row-1)*col+x].print(c);
c.s << ",";
}
m[row*col-1].print(c);
- c.s << "]] ]]";
+ c.s << "]]";
}
}
}
+/** Product of matrix and scalar expression. */
+matrix matrix::mul_scalar(const ex & other) const
+{
+ exvector prod(row * col);
+
+ for (unsigned r=0; r<row; ++r)
+ for (unsigned c=0; c<col; ++c)
+ prod[r*col+c] = m[r*col+c] * other;
+
+ return matrix(row, col, prod);
+}
+
+
/** operator() to access elements.
*
* @param ro row of element
ex expand(unsigned options=0) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
+ ex evalm(void) const {return *this;}
ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
ex eval_indexed(const basic & i) const;
ex add_indexed(const ex & self, const ex & other) const;
matrix sub(const matrix & other) const;
matrix mul(const matrix & other) const;
matrix mul(const numeric & other) const;
+ matrix mul_scalar(const ex & other) const;
const ex & operator() (unsigned ro, unsigned co) const;
matrix & set(unsigned ro, unsigned co, ex value);
matrix transpose(void) const;
#include "mul.h"
#include "add.h"
#include "power.h"
+#include "matrix.h"
#include "archive.h"
#include "debugmsg.h"
#include "utils.h"
return mul(s,overall_coeff.evalf(level));
}
+ex mul::evalm(void) const
+{
+ // numeric*matrix
+ if (seq.size() == 1 && is_ex_of_type(seq[0].rest, matrix))
+ return ex_to_matrix(seq[0].rest).mul(ex_to_numeric(overall_coeff));
+
+ // Evaluate children first, look whether there are any matrices at all
+ // (there can be either no matrices or one matrix; if there were more
+ // than one matrix, it would be a non-commutative product)
+ epvector *s = new epvector;
+ s->reserve(seq.size());
+
+ bool have_matrix = false;
+ epvector::iterator the_matrix;
+
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ const ex &m = recombine_pair_to_ex(*it).evalm();
+ s->push_back(split_ex_to_pair(m));
+ if (is_ex_of_type(m, matrix)) {
+ have_matrix = true;
+ the_matrix = s->end() - 1;
+ }
+ it++;
+ }
+
+ if (have_matrix) {
+
+ // The product contained a matrix. We will multiply all other factors
+ // into that matrix.
+ matrix m = ex_to_matrix(the_matrix->rest);
+ s->erase(the_matrix);
+ ex scalar = (new mul(s, overall_coeff))->setflag(status_flags::dynallocated);
+ return m.mul_scalar(scalar);
+
+ } else
+ return (new mul(s, overall_coeff))->setflag(status_flags::dynallocated);
+}
+
ex mul::simplify_ncmul(const exvector & v) const
{
if (seq.size()==0) {
ex coeff(const ex & s, int n = 1) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
+ ex evalm(void) const;
ex series(const relational & s, int order, unsigned options = 0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
numeric integer_content(void) const;
#include "ex.h"
#include "add.h"
#include "mul.h"
+#include "matrix.h"
#include "print.h"
#include "archive.h"
#include "debugmsg.h"
status_flags::evaluated);
}
+ex ncmul::evalm(void) const
+{
+ // Evaluate children first
+ exvector *s = new exvector;
+ s->reserve(seq.size());
+ exvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ s->push_back(it->evalm());
+ it++;
+ }
+
+ // If there are only matrices, simply multiply them
+ it = s->begin(); itend = s->end();
+ if (is_ex_of_type(*it, matrix)) {
+ matrix prod(ex_to_matrix(*it));
+ it++;
+ while (it != itend) {
+ if (!is_ex_of_type(*it, matrix))
+ goto no_matrix;
+ prod = prod.mul(ex_to_matrix(*it));
+ it++;
+ }
+ delete s;
+ return prod;
+ }
+
+no_matrix:
+ return (new ncmul(s))->setflag(status_flags::dynallocated);
+}
+
ex ncmul::thisexprseq(const exvector & v) const
{
return (new ncmul(v))->setflag(status_flags::dynallocated);
{
exvector s;
s.reserve(seq.size());
-
- for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
- s.push_back((*it).expand(options));
+ exvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ s.push_back(it->expand(options));
+ it++;
}
return s;
}
ex expand(unsigned options=0) const;
ex coeff(const ex & s, int n=1) const;
ex eval(int level=0) const;
+ ex evalm(void) const;
exvector get_free_indices(void) const;
ex thisexprseq(const exvector & v) const;
ex thisexprseq(exvector * vp) const;
#include "expairseq.h"
#include "add.h"
#include "mul.h"
+#include "ncmul.h"
#include "numeric.h"
#include "inifcns.h"
-#include "relational.h"
#include "symbol.h"
#include "print.h"
#include "archive.h"
power::power(const ex & lh, const ex & rh) : basic(TINFO_power), basis(lh), exponent(rh)
{
debugmsg("power ctor from ex,ex",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(basis.return_type()==return_types::commutative);
}
/** Ctor from an ex and a bare numeric. This is somewhat more efficient than
power::power(const ex & lh, const numeric & rh) : basic(TINFO_power), basis(lh), exponent(rh)
{
debugmsg("power ctor from ex,numeric",LOGLEVEL_CONSTRUCT);
- GINAC_ASSERT(basis.return_type()==return_types::commutative);
}
//////////
return i==0 ? basis : exponent;
}
+ex power::map(map_func f) const
+{
+ return (new power(f(basis), f(exponent)))->setflag(status_flags::dynallocated);
+}
+
int power::degree(const ex & s) const
{
if (is_exactly_of_type(*exponent.bp,numeric)) {
const ex & ebasis = level==1 ? basis : basis.eval(level-1);
const ex & eexponent = level==1 ? exponent : exponent.eval(level-1);
- bool basis_is_numerical = 0;
- bool exponent_is_numerical = 0;
+ bool basis_is_numerical = false;
+ bool exponent_is_numerical = false;
numeric * num_basis;
numeric * num_exponent;
if (is_exactly_of_type(*ebasis.bp,numeric)) {
- basis_is_numerical = 1;
+ basis_is_numerical = true;
num_basis = static_cast<numeric *>(ebasis.bp);
}
if (is_exactly_of_type(*eexponent.bp,numeric)) {
- exponent_is_numerical = 1;
+ exponent_is_numerical = true;
num_exponent = static_cast<numeric *>(eexponent.bp);
}
if (ebasis.is_equal(_ex1()))
return _ex1();
- if (basis_is_numerical && exponent_is_numerical) {
+ if (exponent_is_numerical) {
+
// ^(c1,c2) -> c1^c2 (c1, c2 numeric(),
// except if c1,c2 are rational, but c1^c2 is not)
- bool basis_is_crational = num_basis->is_crational();
- bool exponent_is_crational = num_exponent->is_crational();
- numeric res = num_basis->power(*num_exponent);
+ if (basis_is_numerical) {
+ bool basis_is_crational = num_basis->is_crational();
+ bool exponent_is_crational = num_exponent->is_crational();
+ numeric res = num_basis->power(*num_exponent);
- if ((!basis_is_crational || !exponent_is_crational)
- || res.is_crational()) {
- return res;
- }
- GINAC_ASSERT(!num_exponent->is_integer()); // has been handled by now
- // ^(c1,n/m) -> *(c1^q,c1^(n/m-q)), 0<(n/m-h)<1, q integer
- if (basis_is_crational && exponent_is_crational
- && num_exponent->is_real()
- && !num_exponent->is_integer()) {
- numeric n = num_exponent->numer();
- numeric m = num_exponent->denom();
- numeric r;
- numeric q = iquo(n, m, r);
- if (r.is_negative()) {
- r = r.add(m);
- q = q.sub(_num1());
+ if ((!basis_is_crational || !exponent_is_crational)
+ || res.is_crational()) {
+ return res;
}
- if (q.is_zero()) // the exponent was in the allowed range 0<(n/m)<1
- return this->hold();
- else {
- epvector res;
- res.push_back(expair(ebasis,r.div(m)));
- return (new mul(res,ex(num_basis->power_dyn(q))))->setflag(status_flags::dynallocated | status_flags::evaluated);
+ GINAC_ASSERT(!num_exponent->is_integer()); // has been handled by now
+
+ // ^(c1,n/m) -> *(c1^q,c1^(n/m-q)), 0<(n/m-h)<1, q integer
+ if (basis_is_crational && exponent_is_crational
+ && num_exponent->is_real()
+ && !num_exponent->is_integer()) {
+ numeric n = num_exponent->numer();
+ numeric m = num_exponent->denom();
+ numeric r;
+ numeric q = iquo(n, m, r);
+ if (r.is_negative()) {
+ r = r.add(m);
+ q = q.sub(_num1());
+ }
+ if (q.is_zero()) // the exponent was in the allowed range 0<(n/m)<1
+ return this->hold();
+ else {
+ epvector res;
+ res.push_back(expair(ebasis,r.div(m)));
+ return (new mul(res,ex(num_basis->power_dyn(q))))->setflag(status_flags::dynallocated | status_flags::evaluated);
+ }
}
}
- }
- // ^(^(x,c1),c2) -> ^(x,c1*c2)
- // (c1, c2 numeric(), c2 integer or -1 < c1 <= 1,
- // case c1==1 should not happen, see below!)
- if (exponent_is_numerical && is_ex_exactly_of_type(ebasis,power)) {
- const power & sub_power = ex_to_power(ebasis);
- const ex & sub_basis = sub_power.basis;
- const ex & sub_exponent = sub_power.exponent;
- if (is_ex_exactly_of_type(sub_exponent,numeric)) {
- const numeric & num_sub_exponent = ex_to_numeric(sub_exponent);
- GINAC_ASSERT(num_sub_exponent!=numeric(1));
- if (num_exponent->is_integer() || abs(num_sub_exponent)<1)
- return power(sub_basis,num_sub_exponent.mul(*num_exponent));
+ // ^(^(x,c1),c2) -> ^(x,c1*c2)
+ // (c1, c2 numeric(), c2 integer or -1 < c1 <= 1,
+ // case c1==1 should not happen, see below!)
+ if (is_ex_exactly_of_type(ebasis,power)) {
+ const power & sub_power = ex_to_power(ebasis);
+ const ex & sub_basis = sub_power.basis;
+ const ex & sub_exponent = sub_power.exponent;
+ if (is_ex_exactly_of_type(sub_exponent,numeric)) {
+ const numeric & num_sub_exponent = ex_to_numeric(sub_exponent);
+ GINAC_ASSERT(num_sub_exponent!=numeric(1));
+ if (num_exponent->is_integer() || (abs(num_sub_exponent) - _num1()).is_negative())
+ return power(sub_basis,num_sub_exponent.mul(*num_exponent));
+ }
}
- }
- // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
- if (exponent_is_numerical && num_exponent->is_integer() &&
- is_ex_exactly_of_type(ebasis,mul)) {
- return expand_mul(ex_to_mul(ebasis), *num_exponent);
- }
+ // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
+ if (num_exponent->is_integer() && is_ex_exactly_of_type(ebasis,mul)) {
+ return expand_mul(ex_to_mul(ebasis), *num_exponent);
+ }
- // ^(*(...,x;c1),c2) -> ^(*(...,x;1),c2)*c1^c2 (c1, c2 numeric(), c1>0)
- // ^(*(...,x,c1),c2) -> ^(*(...,x;-1),c2)*(-c1)^c2 (c1, c2 numeric(), c1<0)
- if (exponent_is_numerical && is_ex_exactly_of_type(ebasis,mul)) {
- GINAC_ASSERT(!num_exponent->is_integer()); // should have been handled above
- const mul & mulref = ex_to_mul(ebasis);
- if (!mulref.overall_coeff.is_equal(_ex1())) {
- const numeric & num_coeff = ex_to_numeric(mulref.overall_coeff);
- if (num_coeff.is_real()) {
- if (num_coeff.is_positive()) {
- mul * mulp = new mul(mulref);
- mulp->overall_coeff = _ex1();
- mulp->clearflag(status_flags::evaluated);
- mulp->clearflag(status_flags::hash_calculated);
- return (new mul(power(*mulp,exponent),
- power(num_coeff,*num_exponent)))->setflag(status_flags::dynallocated);
- } else {
- GINAC_ASSERT(num_coeff.compare(_num0())<0);
- if (num_coeff.compare(_num_1())!=0) {
+ // ^(*(...,x;c1),c2) -> ^(*(...,x;1),c2)*c1^c2 (c1, c2 numeric(), c1>0)
+ // ^(*(...,x,c1),c2) -> ^(*(...,x;-1),c2)*(-c1)^c2 (c1, c2 numeric(), c1<0)
+ if (is_ex_exactly_of_type(ebasis,mul)) {
+ GINAC_ASSERT(!num_exponent->is_integer()); // should have been handled above
+ const mul & mulref = ex_to_mul(ebasis);
+ if (!mulref.overall_coeff.is_equal(_ex1())) {
+ const numeric & num_coeff = ex_to_numeric(mulref.overall_coeff);
+ if (num_coeff.is_real()) {
+ if (num_coeff.is_positive()) {
mul * mulp = new mul(mulref);
- mulp->overall_coeff = _ex_1();
+ mulp->overall_coeff = _ex1();
mulp->clearflag(status_flags::evaluated);
mulp->clearflag(status_flags::hash_calculated);
return (new mul(power(*mulp,exponent),
- power(abs(num_coeff),*num_exponent)))->setflag(status_flags::dynallocated);
+ power(num_coeff,*num_exponent)))->setflag(status_flags::dynallocated);
+ } else {
+ GINAC_ASSERT(num_coeff.compare(_num0())<0);
+ if (num_coeff.compare(_num_1())!=0) {
+ mul * mulp = new mul(mulref);
+ mulp->overall_coeff = _ex_1();
+ mulp->clearflag(status_flags::evaluated);
+ mulp->clearflag(status_flags::hash_calculated);
+ return (new mul(power(*mulp,exponent),
+ power(abs(num_coeff),*num_exponent)))->setflag(status_flags::dynallocated);
+ }
}
}
}
}
+
+ // ^(nc,c1) -> ncmul(nc,nc,...) (c1 positive integer)
+ if (num_exponent->is_pos_integer() && ebasis.return_type() != return_types::commutative) {
+ return ncmul(exvector(num_exponent->to_int(), ebasis), true);
+ }
}
if (are_ex_trivially_equal(ebasis,basis) &&
bool info(unsigned inf) const;
unsigned nops() const;
ex & let_op(int i);
+ ex map(map_func f) const;
int degree(const ex & s) const;
int ldegree(const ex & s) const;
ex coeff(const ex & s, int n = 1) const;
return i==0 ? lh : rh;
}
+
+ex relational::map(map_func f) const
+{
+ return (new relational(f(lh), f(rh), o))->setflag(status_flags::dynallocated);
+}
ex relational::eval(int level) const
{
bool info(unsigned inf) const;
unsigned nops() const;
ex & let_op(int i);
+ ex map(map_func f) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;