function outputPvPairs = ensureOnlySpecifiedPVPairsOnDevice(pvPairNames, varargin)
%ENSUREONLYSPECIFIEDPVPAIRSONDEVICE Send the specified PV pair values to the GPU and ensure the remaining PV pair values are on the host
%   OUTPUTPVPAIRS = ensureOnlySpecifiedPVPairsOnDevice( PVPAIRNAMES, ...
%   'NAME1', VAL1, 'NAME2', VAL2 ... ) returns a cell array containing the
%   PV pairs 'NAME1', VAL1, 'NAME2', VAL2 ..., modified as follows: The PV
%   pair values specified in PVPAIRNAMES are sent to the GPU if they are
%   numerical or logical and not already gpuArrays.  The remaining PV pair
%   values are all gathered back to the host.

%   Copyright 2020 The MathWorks, Inc.

% Convert all PV pair strings to chars, as this is the format expected by
% internal.stats.parseArgs.
[varargin{:}] = convertStringsToChars(varargin{:});

% Extract the PV pair values to send to GPU and the remaining PV pairs
pvPairNames = cellstr(pvPairNames);
dummyDefaultValues = cell(size(pvPairNames));
PvPairValuesToSendToDevice = cell(size(pvPairNames));
[PvPairValuesToSendToDevice{:}, setFlagStruct, remainingPvPairs] = internal.stats.parseArgs(pvPairNames, dummyDefaultValues, varargin{:});

% All the remaining PV pairs should be gathered.
if ~isempty(remainingPvPairs)
    [remainingPvPairs{:}] = gather(remainingPvPairs{:});
end

% Calculate how many PV pair values to send to GPU were actually received
% so we can allocate a cell array to hold them.
numPvPairsToSendToGpuReceived = nnz(structfun(@(x) x, setFlagStruct));
outputPvPairs = cell(1, 2*numPvPairsToSendToGpuReceived);
counter = 0;
for ii = 1:numel(pvPairNames)
    if setFlagStruct.(pvPairNames{ii})
        outputPvPairs{counter + 1} = pvPairNames{ii};
        outputPvPairs{counter + 2} = sendToDeviceIfPossible(PvPairValuesToSendToDevice{ii});
        counter = counter + 2;
    end
end
outputPvPairs = [outputPvPairs(:)', remainingPvPairs(:)'];
end