function layer = additionLayer(varargin)
% additionLayer   Addition layer
%
%   layer = additionLayer(numInputs) creates an addition layer with the
%   number of inputs specified by numInputs. This layer takes multiple
%   inputs and adds them element-wise.
%
%   layer = additionLayer(numInputs, 'PARAM1', VAL1) specifies optional parameter
%   name/value pairs for creating the layer:
%
%       'Name'                    - A name for the layer. The default is
%                                   ''.
%   An addition layer has the following inputs:
%       'in1','in2',...,'inN'     - Inputs to be added together. Note that 
%                                   all of the inputs must have the same
%                                   dimensions. See the example below for
%                                   usage.
%
%   Example:
%       % Create an addition layer with two inputs that sums the output from
%       % two ReLU layers.
%
%       add_1 = additionLayer(2,'Name','add_1');
%       relu_1 = reluLayer('Name','relu_1');
%       relu_2 = reluLayer('Name','relu_2');
%
%       lgraph = layerGraph();
%       lgraph = addLayers(lgraph, relu_1);
%       lgraph = addLayers(lgraph, relu_2);
%       lgraph = addLayers(lgraph, add_1);
%
%       lgraph = connectLayers(lgraph, 'relu_1', 'add_1/in1');
%       lgraph = connectLayers(lgraph, 'relu_2', 'add_1/in2');
%
%       plot(lgraph);
%
%   See also nnet.cnn.layer.AdditionLayer, concatenationLayer, reluLayer.
%
%   <a href="matlab:helpview('deeplearning','list_of_layers')">List of Deep Learning Layers</a>

%   Copyright 2017-2018 The MathWorks, Inc.

% Parse the input arguments.
varargin = nnet.internal.cnn.layer.util.gatherParametersToCPU(varargin);
inputArguments = iParseInputArguments(varargin{:});

% Create an internal representation of a depth slice layer.
internalLayer = nnet.internal.cnn.layer.Addition(inputArguments.Name, inputArguments.NumInputs);

% Pass the internal layer to a function to construct a user visible depth
% slice layer.
layer = nnet.cnn.layer.AdditionLayer(internalLayer);

end

function inputArguments = iParseInputArguments(varargin)
p = inputParser;
addRequired(p, 'NumInputs', @iAssertValidNumInputs);
addParameter(p, 'Name', '', @nnet.internal.cnn.layer.paramvalidation.validateLayerName);
p.parse(varargin{:});
inputArguments = struct;
% make sure strings get converted to char vectors and num inputs to double
inputArguments.Name = convertStringsToChars(p.Results.Name); 
inputArguments.NumInputs = double( p.Results.NumInputs );
end

function iAssertValidNumInputs(value)
validateattributes(value, {'numeric'}, ...
    {'positive', 'real', 'integer', 'nonempty', 'scalar', '>', 1});
end
