|
| 1 | +%% Copyright (C) 2014-2016 Colin B. Macdonald |
| 2 | +%% |
| 3 | +%% This file is part of OctSymPy. |
| 4 | +%% |
| 5 | +%% OctSymPy is free software; you can redistribute it and/or modify |
| 6 | +%% it under the terms of the GNU General Public License as published |
| 7 | +%% by the Free Software Foundation; either version 3 of the License, |
| 8 | +%% or (at your option) any later version. |
| 9 | +%% |
| 10 | +%% This software is distributed in the hope that it will be useful, |
| 11 | +%% but WITHOUT ANY WARRANTY; without even the implied warranty |
| 12 | +%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| 13 | +%% the GNU General Public License for more details. |
| 14 | +%% |
| 15 | +%% You should have received a copy of the GNU General Public |
| 16 | +%% License along with this software; see the file COPYING. |
| 17 | +%% If not, see <http://www.gnu.org/licenses/>. |
| 18 | + |
| 19 | +%% -*- texinfo -*- |
| 20 | +%% @documentencoding UTF-8 |
| 21 | +%% @defmethod @@sym diff (@var{f}) |
| 22 | +%% @defmethodx @@sym diff (@var{f}, @var{x}) |
| 23 | +%% @defmethodx @@sym diff (@var{f}, @var{x}, @dots{}) |
| 24 | +%% @defmethodx @@sym diff (@var{f}, @dots{}) |
| 25 | +%% Symbolic differentiation. |
| 26 | +%% |
| 27 | +%% Examples: |
| 28 | +%% @example |
| 29 | +%% @group |
| 30 | +%% syms x |
| 31 | +%% f = sin (cos (x)); |
| 32 | +%% diff (f) |
| 33 | +%% @result{} (sym) -sin(x)⋅cos(cos(x)) |
| 34 | +%% diff (f, x) |
| 35 | +%% @result{} (sym) -sin(x)⋅cos(cos(x)) |
| 36 | +%% simplify (diff (f, x, x)) |
| 37 | +%% @result{} (sym) |
| 38 | +%% 2 |
| 39 | +%% - sin (x)⋅sin(cos(x)) - cos(x)⋅cos(cos(x)) |
| 40 | +%% @end group |
| 41 | +%% @end example |
| 42 | +%% |
| 43 | +%% Partial differentiation: |
| 44 | +%% @example |
| 45 | +%% @group |
| 46 | +%% syms x y |
| 47 | +%% f = cos(2*x + 3*y); |
| 48 | +%% diff(f, x, y, x) |
| 49 | +%% @result{} (sym) 12⋅sin(2⋅x + 3⋅y) |
| 50 | +%% diff(f, x, 2, y, 3) |
| 51 | +%% @result{} (sym) -108⋅sin(2⋅x + 3⋅y) |
| 52 | +%% @end group |
| 53 | +%% @end example |
| 54 | +%% |
| 55 | +%% Other examples: |
| 56 | +%% @example |
| 57 | +%% @group |
| 58 | +%% diff(sym(1)) |
| 59 | +%% @result{} (sym) 0 |
| 60 | +%% @end group |
| 61 | +%% @end example |
| 62 | +%% |
| 63 | +%% @seealso{@@sym/int} |
| 64 | +%% @end defmethod |
| 65 | + |
| 66 | + |
| 67 | +function z = diff(f, varargin) |
| 68 | + |
| 69 | + cmd = { 'f = _ins[0]' |
| 70 | + 'args = _ins[1:]' |
| 71 | + 'd = list(f.free_symbols)' |
| 72 | + 'if len(d) == 0:' |
| 73 | + ' return sympy.S(0),' |
| 74 | + 'if len(args) == 0:' |
| 75 | + ' if len(d) > 1:' |
| 76 | + ' return ("NO_DEV_VAR"),' |
| 77 | + 'else:' |
| 78 | + ' if args[0].is_integer:' |
| 79 | + ' if len(d) > 1:' |
| 80 | + ' return ("NO_DEV_VAR"),' |
| 81 | + ' d = d*args[0]' |
| 82 | + ' else:' |
| 83 | + ' d = [args[0]]' |
| 84 | + ' for i in xrange(1, len(args)):' |
| 85 | + ' if args[i].is_integer:' |
| 86 | + ' if args[i] >= 1:' |
| 87 | + ' d = d + [d[-1]]*(args[i]-1)' |
| 88 | + ' else:' |
| 89 | + ' d = d + [args[i]]' |
| 90 | + 'return f.diff(*d),' }; |
| 91 | + |
| 92 | + varargin = sym(varargin); |
| 93 | + z = python_cmd (cmd, sym(f), varargin{:}); |
| 94 | + |
| 95 | + if strcmp(z, 'NO_DEV_VAR') |
| 96 | + error('Please set a derive var, actually we do not support autodetect vars to chain rule'); |
| 97 | + end |
| 98 | + |
| 99 | +end |
| 100 | + |
| 101 | + |
| 102 | +%!shared x,y,z |
| 103 | +%! syms x y z |
| 104 | + |
| 105 | +%!test |
| 106 | +%! % basic |
| 107 | +%! assert(logical( diff(sin(x)) - cos(x) == 0 )) |
| 108 | +%! assert(logical( diff(sin(x),x) - cos(x) == 0 )) |
| 109 | +%! assert(logical( diff(sin(x),x,x) + sin(x) == 0 )) |
| 110 | + |
| 111 | +%!test |
| 112 | +%! % these fail when doubles are not converted to sym |
| 113 | +%! assert(logical( diff(sin(x),x,2) + sin(x) == 0 )) |
| 114 | +%! assert(logical( diff(sym(1),x) == 0 )) |
| 115 | +%! assert(logical( diff(1,x) == 0 )) |
| 116 | +%! assert(logical( diff(pi,x) == 0 )) |
| 117 | + |
| 118 | +%!test |
| 119 | +%! % symbolic diff of const (w/o variable) fails in sympy, but we work around |
| 120 | +%! assert (isequal (diff(sym(1)), sym(0))) |
| 121 | + |
| 122 | +%!test |
| 123 | +%! % nth symbolic diff of const |
| 124 | +%! assert (isequal (diff(sym(1), 2), sym(0))) |
| 125 | +%! assert (isequal (diff(sym(1), sym(1)), sym(0))) |
| 126 | + |
| 127 | +%!test |
| 128 | +%! % octave's vector difference still works |
| 129 | +%! assert(isempty(diff(1))) |
| 130 | +%! assert((diff([2 6]) == 4)) |
| 131 | + |
| 132 | +%!test |
| 133 | +%! % other forms |
| 134 | +%! f = sin(x); |
| 135 | +%! g = diff(f,x,2); |
| 136 | +%! assert (isequal (diff(f,2), g)) |
| 137 | +%! assert (isequal (diff(f,sym(2)), g)) |
| 138 | +%! assert (isequal (diff(f,sym(2),x), diff(g))) |
| 139 | +%! g = diff(f,x); |
| 140 | +%! assert (isequal (diff(f), g)) |
| 141 | +%! assert (isequal (diff(f,1), g)) |
| 142 | +%! assert (isequal (diff(f,1,x), diff(g))) |
| 143 | + |
| 144 | +%!test |
| 145 | +%! % matrix |
| 146 | +%! A = [x sin(x); x*y 10]; |
| 147 | +%! B = [1 cos(x); y 0]; |
| 148 | +%! assert(isequal(diff(A,x),B)) |
| 149 | + |
| 150 | +%!error |
| 151 | +%! % bug: use symvar |
| 152 | +%! a = x*y; |
| 153 | +%! b = diff(a); |
| 154 | + |
| 155 | +%!test |
| 156 | +%! % bug: symvar should be used on the matrix, not comp-by-comp |
| 157 | +%! a = [x y x*x]; |
| 158 | +%! b = diff(a, x); |
| 159 | +%! assert (~isequal (b(2), 1)) |
| 160 | +%! assert (isequal (b, [1 0 2*x])) |
| 161 | +%! b = diff(a, x, 1); |
| 162 | +%! assert (~isequal (b(2), 1)) |
| 163 | +%! assert (isequal (b, [1 0 2*x])) |
0 commit comments