function this = reduce(this,varargin)

if isempty(this.func)
   if isnumeric(this.args)
      % This is a number. Do nothing.
      return
   elseif islogical(this.args)
      % This is a logical index indicating a particular derivative among
      % multiple derivatives. You cannot run reduce without the second
      % input argument in that case.
      if isempty(varargin)
         % Do nothing if no reduction wrt to a k-th variable is requested.
         return
      end
      k = varargin{1};
      if k == find(this.args)
         this.func = '';
         this.args = 1;
      else
         this.func = '';
         this.args = 0;
      end
      return
   elseif ischar(this.args)
      % This is a variable name. Do nothing.
      return
   else      
      utils.error('sydney', ...
         'Cannot run reduction before differentation.');
   end
end

if strcmp(this.func,'sydney.d')
   % This is diff of an external function.
   return
end

for i = 1 : length(this.args)
    if isa(this.args{i},'sydney')
        this.args{i} = reduce(this.args{i},varargin{:});
    end
end

% Evaluate the function if all arguments are numeric.
if ~isempty(this.func) && iscell(this.args) && ~isempty(this.args)
    allnumeric = true;
    nargs = length(this.args);
    args = cell(1,nargs);
    for i = 1 : nargs
        allnumeric = allnumeric ...
            && isa(this.args{i},'sydney') ...
            && isnumeric(this.args{i}.args);
        args{i} = this.args{i}.args;
    end
    if allnumeric
        this.args = builtin(this.func,args{:});
        this.func = '';
    end
end

%{
if length(this.args) == 1
   if isnumeric(this.args{1}.args)
      this.args = builtin(this.func,this.args{1}.args);
      this.func = '';
   end
elseif length(this.args) == 2 ...
        && isa(this.args{1},'sydney') ...
        && isa(this.args{2},'sydney')
   if isnumeric(this.args{1}.args) && isnumeric(this.args{2}.args)
      this.args = builtin(this.func,this.args{1}.args,this.args{2}.args);
      this.func = '';
   end
end
%}

switch this.func
   case 'uplus'
      douplus();
   case 'uminus'
      douminus();
   case 'plus'
      doplus();
   case 'minus'
      dominus();
   case 'times'
      dotimes();
   case 'rdivide'
      dordivide();
   case 'power'
      dopower();
end

   function douplus()
      if isequal(this.args{1}.args,0)
         this.func = '';
         this.args = 0;
      elseif isnumeric(this.args{1}.args)
         this.func = '';
         this.args = this.args{1}.args;
      end
   end

   function douminus()
      if isequal(this.args{1}.args,0)
         this.func = '';
         this.args = 0;
      elseif isnumeric(this.args{1}.args)
         this.func = '';
         this.args = -this.args{1}.args;
      end
   end

   function doplus()
      if isequal(this.args{1}.args,0)
         this = this.args{2};
      elseif isequal(this.args{2}.args,0)
         this = this.args{1};
      end
   end

   function dominus()
      if isequal(this.args{1}.args,0)
         this.func = 'uminus';
         this.args = this.args(2);
      elseif isequal(this.args{2}.args,0)
         this = this.args{1};
      end
   end

   function dotimes()
      if isequal(this.args{1}.args,0) || isequal(this.args{2}.args,0)
         % 0*x or x*0
         this.func = '';
         this.args = 0;
         return
      end
      if isequal(this.args{1}.args,1)
         % 1*x
         this = this.args{2};
      elseif isequal(this.args{2}.args,1)
         % x*1
         this = this.args{1};
      elseif isequal(this.args{1}.args,-1)
         % (-1)*x
         this.func = 'uminus';
         this.args = this.args(2);
      elseif isequal(this.args{2}.args,-1)
         % x*(-1)
         this.func = 'uminus';
         this.args = this.args(1);
      end
   end

   function dordivide()
      if isequal(this.args{1}.args,0)
         this.func = '';
         this.args = 0;
      elseif isequal(this.args{2}.args,1)
         this = this.args{1};
      elseif isequal(this.args{2}.args,-1)
         this.func = 'uminus';
         this.args = this.args(1);
      end
   end

   function dopower()
      if isequal(this.args{2}.args,0) || isequal(this.args{1}.args,1)
         this.func = '';
         this.args = 1;
      elseif isequal(this.args{1}.args,0)
         this.func = '';
         this.args = 0;
      elseif isequal(this.args{2}.args,1)
         this = this.args{1};
      end
   end

end