function layer = additionLayer(numInputs,nameValueArgs)
% 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-2023 The MathWorks, Inc.

arguments
    numInputs            {iAssertValidNumInputs}
    nameValueArgs.Name   {iAssertValidLayerName} = ""
end

% Gather inputs to CPU.
numInputs = nnet.internal.cnn.layer.util.gatherParametersToCPU(numInputs);
nameValueArgs = nnet.internal.cnn.layer.util.gatherParametersToCPU(nameValueArgs);

% Canonicalization.
numInputs = iConvertToDouble(numInputs);
nameValueArgs.Name = convertStringsToChars(nameValueArgs.Name);

% Create an internal representation of an addition layer.
internalLayer = nnet.internal.cnn.layer.Addition(nameValueArgs.Name, numInputs);

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

end

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

function iAssertValidLayerName(name)
nnet.internal.cnn.layer.paramvalidation.validateLayerName(name)
end

function value = iConvertToDouble(value)
value = nnet.internal.cnn.layer.util.convertToDouble(value);
end
