function [pd,varargout] = partialDependence(model,features,X,varargin)
%PARTIALDEPENDENCE Partial Dependence for one and two variables
%
%   PD = partialDependence(MODEL,VAR,DATA) returns a vector PD of partial
%   dependence for a single predictor variable VAR, and input data DATA,
%   based on the response of a blaxbox model MODEL. The blackbox model to
%   be interpreted can be specified as a function handle. VAR is a scalar
%   containing the index of a predictor or a character array specifying a
%   predictor name. DATA is a matrix or table to be used as predictor data.
%   DATA is required when MODEL is a function handle.
%
%   PD = partialDependence(MODEL,VARS,DATA) returns a two dimensional
%   array PD of the partial dependencies for two predictors VARS, based on
%   the response of a blackbox model MODEL. VARS is either a string or cell
%   array containing two predictor names, or a two-element vector containing
%   the indices of two predictors.
%
%   PD = partialDependence(...,Name,Value) specifies additional options
%   using one or more name-value arguments:
%
%       'NumObservationsToSample'       An integer specifying the number
%                                       of rows to sample at random from the
%                                       data set. The default is to use all
%                                       rows.
%
%       'QueryPoints'                   The points at which to calculate
%                                       the partial dependence. For the case
%                                       of a single predictor, the value of
%                                       'QueryPoints' must be a column vector.
%                                       For the case of two predictors, the
%                                       value of 'QueryPoints' must be a 1x2
%                                       cell array containing a separate vector
%                                       for each predictor. The default is to
%                                       use 100 points equally spaced across
%                                       the range of the predictor.
%
%       'UseParallel'                   Can be true to instruct the function to
%                                       perform the averaging calculations in
%                                       parallel (using parfor), or false
%                                       (default) to instruct the function not to
%                                       use parallel computation.
%
%      'CategoricalPredictors'          List of categorical predictors when MODEL
%                                       is a function handle. Pass 'CategoricalPredictors'
%                                       as one of:
%                                       * A numeric vector with indices between 1 and P,
%                                         where P is the number of predictor
%                                         variables.
%                                       * A logical vector of length P, where a true
%                                         entry means that the corresponding predictor
%                                         is a categorical variable.
%                                       * 'all', meaning all predictors are categorical.
%                                       * A string array or cell array of character
%                                         vectors, where each element in the array is
%                                         the name of a predictor variable. The names
%                                         must match variable names in table DATA.
%                                       Default: for a matrix input DATA, no categorical
%                                       predictors; for a table DATA, predictors are
%                                       treated as categorical if they are character
%                                       array, string array, cell arrays of character
%                                       vectors, logical, or of type 'categorical'.
%
%      'OutputColumns'                  List of output columns of function handle
%                                       to be considered for PD. Pass 'OutputColumns'
%                                       as one of:
%                                       * A numeric vector with indices between 1 and M,
%                                       where M is the number of columns returned as output
%                                       from the function handle MODEL.
%                                       * A logical vector of length M, where a true
%                                         entry means that the corresponding output column
%                                         is considered for computing PD.
%                                       * 'all', meaning all output columns are considered
%                                       for computing PD.
%                                       The default value is 'all'.
%
%   [PD,X,Y] = partialDependence(...) also returns the arrays X and Y
%   containing the query point values of the first and second predictor in VARS,
%   respectively.
%
%   See also
%   classreg.learning.classif.FullClassificationModel/partialDependence,
%   classreg.learning.regr.FullRegressionModel/partialDependence.

%   Copyright 2021-2022 The MathWorks, Inc.

[varargin{:}] = convertStringsToChars(varargin{:});

% Verify model is a function handle
isFunctionHandle = isa(model, 'function_handle');
if ~isFunctionHandle
    error(message('stats:responsible:plotPartialDependence:ModelFuncHandle'));
end

% Check inputs with inputParser. This step ensures that only
% allowed Name-Value pairs are passed.
p = inputParser;
addRequired(p,'Model');
addRequired(p,'Var');
addRequired(p,'Data',@(data)validateattributes(data,{'single','double','table'},...
    {'nonempty','2d'}));
addParameter(p,'NumObservationsToSample',0);
addParameter(p,'QueryPoints',[]);
addParameter(p,'UseParallel',false);
addParameter(p,'CategoricalPredictors',[]);
addParameter(p,'OutputColumns',[]);
parse(p,model,features,X,varargin{:});

% Models as Function Handle are treated as classification problems since
% multiple outputs (response/score) can be returned.
classif = true;
label   = [];

% Call the function partialDependence from classreg.learning.impl
% Pass additional internal Name-Value argument that allows complex values in
% predictor variables and output of function handle when validating data.
[pd,x,y] = responsible.impl.partialDependence(...
    model,features,label,X,classif,'AllowComplexValues',true,varargin{:});
varargout{1} = x;
varargout{2} = y;
end
