function layer = sinusoidalPositionEncodingLayer(outputSize, nameValueArgs)
% sinusoidalPositionEncodingLayer   Sinusoidal position encoding layer
%
%   layer = sinusoidalPositionEncodingLayer(outputSize) creates a
%   sinusoidal position encoding layer that maps positions to vectors using
%   sinusoidal operations. outputSize is an even number that specifies the
%   number of channels of the layer output.
%
%   layer = sinusoidalPositionEncodingLayer(outputSize, Name=value)
%   specifies additional options using one or more name-value arguments:
%
%     Positions              - Positions in the input, specified as one of
%                              the following:
%                              "auto"              - For sequence or
%                                                    spatial-temporal
%                                                    input, use the
%                                                    temporal indices as
%                                                    positions. For
%                                                    one-dimensional image 
%                                                    input, use the spatial
%                                                    indices as positions.
%                                                    For other input, use
%                                                    the input values as
%                                                    positions.
%                              "temporal-indices"  - Use the temporal
%                                                    indices of the input
%                                                    as positions.
%                              "spatial-indices"   - Use the spatial
%                                                    indices of the input
%                                                    as positions.
%                              "data-values"       - Use the values in the
%                                                    input as positions.
%                              The default value is "auto".
%
%     Name                   - Name for the layer.
%                              The default value is "".
%
%   Example:
%       % Create a sinusoidal position encoding layer with an output size
%       % of 256.
%
%       outputSize = 256;
%       layer = sinusoidalPositionEncodingLayer(outputSize);
%
%   See also nnet.cnn.layer.SinusoidalPositionEncodingLayer, positionEmbeddingLayer.
%
%   <a href="matlab:helpview('deeplearning','list_of_layers')">List of Deep Learning Layers</a>

%   Copyright 2023 The MathWorks, Inc.

arguments
    outputSize (1,1) {mustBeNumeric, mustBeInteger, mustBeNonempty, mustBePositive}
    nameValueArgs.Positions {mustBeTextScalar} = 'auto'
    nameValueArgs.Name {iAssertValidLayerName} = ''
end

outputSize = iValidateOutputSize(outputSize);
positions = iValidatePositions(nameValueArgs.Positions);
name = convertStringsToChars(nameValueArgs.Name);

layer = nnet.cnn.layer.SinusoidalPositionEncodingLayer(name, outputSize, positions);

end

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

function value = iValidateOutputSize(value)
value = iConvertToDouble(value);
if mod(value,2) ~= 0
    throwAsCaller(MException(message('nnet_cnn:layer:SinusoidalPositionEncodingLayer:OddOutputSize')));
end
end

function validString = iValidatePositions(value)
validString = validatestring(value, {'auto', 'temporal-indices', 'spatial-indices', 'data-values'});
end

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