3 * Implementation of symbolic differentiation in all of GiNaC's classes. */
6 * GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "expairseq.h"
36 #include "relational.h"
41 #ifndef NO_GINAC_NAMESPACE
43 #endif // ndef NO_GINAC_NAMESPACE
45 /** Default implementation of ex::diff(). It prints and error message and returns a fail object.
47 ex basic::diff(symbol const & s) const
49 throw(std::logic_error("differentiation not supported by this type"));
53 /** Implementation of ex::diff() for a numeric. It always returns 0.
56 ex numeric::diff(symbol const & s) const
62 /** Implementation of ex::diff() for single differentiation of a symbol.
66 ex symbol::diff(symbol const & s) const
68 if (compare_same_type(s)) {
75 /** Implementation of ex::diff() for a constant. It always returns 0.
78 ex constant::diff(symbol const & s) const
83 /** Implementation of ex::diff() for multiple differentiation of a symbol.
84 * It returns the symbol, 1 or 0.
86 * @param nth order of differentiation
88 ex symbol::diff(symbol const & s, unsigned nth) const
90 if (compare_same_type(s)) {
107 /** Implementation of ex::diff() for an indexed object. It always returns 0.
109 ex indexed::diff(symbol const & s) const
115 /** Implementation of ex::diff() for an expairseq. It differentiates all elements of the sequence.
117 ex expairseq::diff(symbol const & s) const
119 return thisexpairseq(diffchildren(s),overall_coeff);
123 /** Implementation of ex::diff() for a sum. It differentiates each term.
125 ex add::diff(symbol const & s) const
127 // D(a+b+c)=D(a)+D(b)+D(c)
128 return (new add(diffchildren(s)))->setflag(status_flags::dynallocated);
132 /** Implementation of ex::diff() for a product. It applies the product rule.
134 ex mul::diff(symbol const & s) const
137 new_seq.reserve(seq.size());
139 // D(a*b*c)=D(a)*b*c+a*D(b)*c+a*b*D(c)
140 for (unsigned i=0; i!=seq.size(); i++) {
141 epvector sub_seq=seq;
142 sub_seq[i] = split_ex_to_pair(sub_seq[i].coeff*
143 power(sub_seq[i].rest,sub_seq[i].coeff-1)*
144 sub_seq[i].rest.diff(s));
145 new_seq.push_back((new mul(sub_seq,overall_coeff))->setflag(status_flags::dynallocated));
147 return (new add(new_seq))->setflag(status_flags::dynallocated);
151 /** Implementation of ex::diff() for a non-commutative product. It always returns 0.
153 ex ncmul::diff(symbol const & s) const
159 /** Implementation of ex::diff() for a power.
161 ex power::diff(symbol const & s) const
163 if (exponent.info(info_flags::real)) {
164 // D(b^r) = r * b^(r-1) * D(b) (faster than the formula below)
165 return mul(mul(exponent, power(basis, exponent - _ex1())), basis.diff(s));
167 // D(b^e) = b^e * (D(e)*ln(b) + e*D(b)/b)
168 return mul(power(basis, exponent),
169 add(mul(exponent.diff(s), log(basis)),
170 mul(mul(exponent, basis.diff(s)), power(basis, -1))));
175 /** Implementation of ex::diff() for functions. It applies the chain rule,
176 * except for the Order term function.
178 ex function::diff(symbol const & s) const
182 if (serial==function_index_Order) {
183 // Order Term function only differentiates the argument
184 return Order(seq[0].diff(s));
188 for (unsigned i=0; i!=seq.size(); i++) {
189 arg_diff = seq[i].diff(s);
190 // We apply the chain rule only when it makes sense. This is not
191 // just for performance reasons but also to allow functions to
192 // throw when differentiated with respect to one of its arguments
193 // without running into trouble with our automatic full
195 if (!arg_diff.is_zero())
196 new_seq.push_back(mul(pdiff(i), arg_diff));
203 /** Implementation of ex::diff() for a power-series. It treats the series as a polynomial.
205 ex series::diff(symbol const & s) const
209 epvector::const_iterator it = seq.begin(), itend = seq.end();
211 // FIXME: coeff might depend on var
212 while (it != itend) {
213 if (is_order_function(it->rest)) {
214 new_seq.push_back(expair(it->rest, it->coeff - 1));
216 ex c = it->rest * it->coeff;
218 new_seq.push_back(expair(c, it->coeff - 1));
222 return series(var, point, new_seq);
229 /** Compute partial derivative of an expression.
231 * @param s symbol by which the expression is derived
232 * @param nth order of derivative (default 1)
233 * @return partial derivative as a new expression */
235 ex ex::diff(symbol const & s, unsigned nth) const
243 ex ndiff = bp->diff(s);
245 ndiff = ndiff.diff(s);
251 #ifndef NO_GINAC_NAMESPACE
253 #endif // ndef NO_GINAC_NAMESPACE