Arguments#

Here we will take a look at arguments end which is a method for input argument validation.

A look back at the structure of a function.#

As mentioned in the first section of this lesson, the function is made up of outputs and inputs. The values you pass as arguments are called inputs. Let’s look at this with the mySum() example.

function ans = mySum(a, b)

ans = a + b
sprintf('%g + %g = %g', a, b, ans)

end

Here the arguments are a and b. If I call the function mySum(3, 4) the inputs are \(3\) and \(4\).

What happens when you have more complicated functions?#

A lot of times, custom functions are meant to carry out complex code and require that the correct inputs are given. It is common to see “error checks” which ensure that your function inputs can be handeled by the function and, if not, return an error. Let’s take a closer look at what I mean by this.

funWithSVD()#

In the new function funWithSVD() we require a few things. First we require an image, and then we require a number of components. There are optional inputs we can give as well, but I will go over those later. In this function, we are making use of a computation called single value decomposition, which you don’t need to know a lot about. Just know that it identifies the spatial patterns in a matrix and which features are more or less important to those spatial patterns. You also don’t need to know necessarily what is going on in the function itself. This is just a demonstration of input argument handeling.

Before we look at the components of the function let’s just see what it looks like when we call it.

funWithSVD('/path/to/image/', 1:5)

% with additional optional args
funWithSVD('/path/to/image/', 1:5, 'newPic', 'no', 'originalPic', 'yes')
            Error: MATLAB Kernel for Jupyter was unable to find the notebook server from which it was spawned!

            Resolution: Please relaunch kernel from JupyterLab or Classic Jupyter Notebook.
            

You can see that there are a few ways to call the function and multiple different inputs. To navigate these inputs, the easiset option would be to create an if/elseif block that checks the class and dimensions of the inputs. Let’s see what this might look like.

function funWithSVD(pic, features, varargin)
% FUNWITHSVD demonstrating how different features change image
% pic -- image you wish to analyze
% features -- (double) number of features to include in analyzed image (e.g., 1:4)

% Optional
    % 'originalPic' -- ('yes' | 'no') display original picture after SVD. Default 'no'.
    % 'newPic' -- ('yes' | 'no') Display new pic. Default 'yes'.
    
    % check inputs
    if ~ischar(pic) || ~isstring(pic) % checks if pic arg is a char or string
        error('pic must be string')
    elseif isempty(pic) % checks if you forgot to provide pic
    end
        error('must provide a pic input')
    end
    
    if ~isnumeric(features) % checks if features are numeric
        error('Must be numeric')
    elseif isempty(features)
        error('Must provide features') % checks if you forgot to provide feautres
    end
    
    for i = 1:length(varargin)
        if ~ischar(varargin{i + 1}) || ~isstring(varargin{i + 1}) % checks if optional arg is a char or string
            error('%s must be string', varargin{i}
        end
    end
    
    %%%%%%%%%%%%%%%%%%%%%
        
            Error: MATLAB Kernel for Jupyter was unable to find the notebook server from which it was spawned!

            Resolution: Please relaunch kernel from JupyterLab or Classic Jupyter Notebook.
            

As you can see, this takes up a lot of code. It is also computationaly inefficient. Fortunately, MATLAB has an additional option that we can use. It is called arguments end. This allows us to validate inputs to ensure that match with the function requirements. Let’s take a look at the previous code converted to an arguments end method.

function funWithSVD(pic, features, options)
% FUNWITHSVD demonstrating how different features change image
% pic -- image you wish to analyze
% features -- (double) number of features to include in analyzed image (e.g., 1:4)

% Optional
    % 'originalPic' -- ('yes' | 'no') display original picture after SVD. Default 'no'.
    % 'newPic' -- ('yes' | 'no') Display new pic. Default 'yes'.
    
% checks arguments
    arguments
        pic (1, 1) string {mustBeTextScalar} % checks pic
        features (1, :) double {mustBeNumeric} % checks features
        options.originalPic string = 'no' % manages optional args
        options.newPic string = 'yes' % manages optional args
    end
            Error: MATLAB Kernel for Jupyter was unable to find the notebook server from which it was spawned!

            Resolution: Please relaunch kernel from JupyterLab or Classic Jupyter Notebook.
            

As you can tell. The above code is much shorter than that of the previous iteration of funWithSVD(). Let’s dive deeper into arguments end.

Structure of arguments end#

Below is a description of arguments end taken from Mathworks

arguments
    argName1 (dimensions) class {validators} = defaultValue
    ...
    argNameN ...
end

In the case of funWithSVD(), argName1 is pic. (dimensions) is (1, 1) class is string and the {validator} {mustBeTextScalar} which checks that the value is a single piece of text. This structure repeats for feautures as well. For our options we have two. The = operator sets their default values. Let’s take a look at the completed function.

Final funWithSVD()#

function funWithSVD(pic, features, options)
% FUNWITHSVD demonstrating how different features change image
% pic -- image you wish to analyze
% features -- (double) number of features to include in analyzed image (e.g., 1:4)

% Optional
    % 'originalPic' -- ('yes' | 'no') display original picture after SVD. Default 'no'.
    % 'newPic' -- ('yes' | 'no') Display new pic. Default 'yes'.
    
% checks arguments
    arguments
        pic (1, 1) string {mustBeTextScalar}
        features (1, :) double {mustBeNumeric}
        options.originalPic string = 'no'
        options.newPic string = 'yes'
    end

    % begins SVD
    
    image2matrix = double(imread(pic));
    [U, S, V] = svd(image2matrix(:, :, 1));

    newPic = U(:, features)*S(features, features)*V(:, features)';

    % checks output options
    switch options.originalPic
        case 'yes'
            figure(1),
            imshow(pic(:, :, 1));
            colormap gray
    end

    switch options.newPic
        case 'yes'
            figure(2),
            imagesc(newPic);
            colormap gray
        otherwise
            fprintf('...calculating features\n')
            imageMatrix = newPic;
            assignin('base', 'imageMatrix', imageMatrix);
    end
end
            Error: MATLAB Kernel for Jupyter was unable to find the notebook server from which it was spawned!

            Resolution: Please relaunch kernel from JupyterLab or Classic Jupyter Notebook.
            

Again, you don’t need to know what is going on inside the function, just that there is an easier way to organize function inputs without inlcuding extraneous lines of code.

For the curious#

I reccomend executing the function. It is a fun little thing to experiment and you can see how the important features make up a matrix/image. Let’s quickly see below. REMEMBER!!! Local functions must go at the end of the file/script…even in the MATLAB kernel for Jupyter.

Using the first 4 features.#

funWithSVD('files/teddy.jpg', 1:4)

function funWithSVD(pic, features, options)
% FUNWITHSVD demonstrating how different features change image
% pic -- image you wish to analyze
% features -- (double) number of features to include in analyzed image (e.g., 1:4)

% Optional
    % 'originalPic' -- ('yes' | 'no') display original picture after SVD. Default 'no'.
    % 'newPic' -- ('yes' | 'no') Display new pic. Default 'yes'.
    
% checks arguments
    arguments
        pic (1, 1) string {mustBeTextScalar}
        features (1, :) double {mustBeNumeric}
        options.originalPic string = 'no'
        options.newPic string = 'yes'
    end

    % begins SVD
    
    image2matrix = double(imread(pic));
    [U, S, V] = svd(image2matrix(:, :, 1));

    newPic = U(:, features)*S(features, features)*V(:, features)';

    % checks output options
    switch options.originalPic
        case 'yes'
            figure(1),
            imshow(pic(:, :, 1));
            colormap gray
    end

    switch options.newPic
        case 'yes'
            figure(2),
            imagesc(newPic);
            colormap gray
        otherwise
            fprintf('...calculating features\n')
            imageMatrix = newPic;
            assignin('base', 'imageMatrix', imageMatrix);
    end
end
            Error: MATLAB Kernel for Jupyter was unable to find the notebook server from which it was spawned!

            Resolution: Please relaunch kernel from JupyterLab or Classic Jupyter Notebook.
            

Using the first 10 features#

funWithSVD('files/teddy.jpg', 1:10)

function funWithSVD(pic, features, options)
% FUNWITHSVD demonstrating how different features change image
% pic -- image you wish to analyze
% features -- (double) number of features to include in analyzed image (e.g., 1:4)

% Optional
    % 'originalPic' -- ('yes' | 'no') display original picture after SVD. Default 'no'.
    % 'newPic' -- ('yes' | 'no') Display new pic. Default 'yes'.
    
% checks arguments
    arguments
        pic (1, 1) string {mustBeTextScalar}
        features (1, :) double {mustBeNumeric}
        options.originalPic string = 'no'
        options.newPic string = 'yes'
    end

    % begins SVD
    
    image2matrix = double(imread(pic));
    [U, S, V] = svd(image2matrix(:, :, 1));

    newPic = U(:, features)*S(features, features)*V(:, features)';

    % checks output options
    switch options.originalPic
        case 'yes'
            figure(1),
            imshow(pic(:, :, 1));
            colormap gray
    end

    switch options.newPic
        case 'yes'
            figure(2),
            imagesc(newPic);
            colormap gray
        otherwise
            fprintf('...calculating features\n')
            imageMatrix = newPic;
            assignin('base', 'imageMatrix', imageMatrix);
    end
end
            Error: MATLAB Kernel for Jupyter was unable to find the notebook server from which it was spawned!

            Resolution: Please relaunch kernel from JupyterLab or Classic Jupyter Notebook.
            

Using the first 100 features#

funWithSVD('files/teddy.jpg', 1:100)

function funWithSVD(pic, features, options)
% FUNWITHSVD demonstrating how different features change image
% pic -- image you wish to analyze
% features -- (double) number of features to include in analyzed image (e.g., 1:4)

% Optional
    % 'originalPic' -- ('yes' | 'no') display original picture after SVD. Default 'no'.
    % 'newPic' -- ('yes' | 'no') Display new pic. Default 'yes'.
    
% checks arguments
    arguments
        pic (1, 1) string {mustBeTextScalar}
        features (1, :) double {mustBeNumeric}
        options.originalPic string = 'no'
        options.newPic string = 'yes'
    end

    % begins SVD
    
    image2matrix = double(imread(pic));
    [U, S, V] = svd(image2matrix(:, :, 1));

    newPic = U(:, features)*S(features, features)*V(:, features)';

    % checks output options
    switch options.originalPic
        case 'yes'
            figure(1),
            imshow(pic(:, :, 1));
            colormap gray
    end

    switch options.newPic
        case 'yes'
            figure(2),
            imagesc(newPic);
            colormap gray
        otherwise
            fprintf('...calculating features\n')
            imageMatrix = newPic;
            assignin('base', 'imageMatrix', imageMatrix);
    end
end
            Error: MATLAB Kernel for Jupyter was unable to find the notebook server from which it was spawned!

            Resolution: Please relaunch kernel from JupyterLab or Classic Jupyter Notebook.
            

Using features in the middle#

funWithSVD('files/teddy.jpg', 20:50)

function funWithSVD(pic, features, options)
% FUNWITHSVD demonstrating how different features change image
% pic -- image you wish to analyze
% features -- (double) number of features to include in analyzed image (e.g., 1:4)

% Optional
    % 'originalPic' -- ('yes' | 'no') display original picture after SVD. Default 'no'.
    % 'newPic' -- ('yes' | 'no') Display new pic. Default 'yes'.
    
% checks arguments
    arguments
        pic (1, 1) string {mustBeTextScalar}
        features (1, :) double {mustBeNumeric}
        options.originalPic string = 'no'
        options.newPic string = 'yes'
    end

    % begins SVD
    
    image2matrix = double(imread(pic));
    [U, S, V] = svd(image2matrix(:, :, 1));

    newPic = U(:, features)*S(features, features)*V(:, features)';

    % checks output options
    switch options.originalPic
        case 'yes'
            figure(1),
            imshow(pic(:, :, 1));
            colormap gray
    end

    switch options.newPic
        case 'yes'
            figure(2),
            imagesc(newPic);
            colormap gray
        otherwise
            fprintf('...calculating features\n')
            imageMatrix = newPic;
            assignin('base', 'imageMatrix', imageMatrix);
    end
end
            Error: MATLAB Kernel for Jupyter was unable to find the notebook server from which it was spawned!

            Resolution: Please relaunch kernel from JupyterLab or Classic Jupyter Notebook.
            

Finishing up#

I hope that you have been able to see how the arguments end method for validating and organizing function inputs works as well as had the ability to play around with the funWithSVD() function. You can see which components make up the spatial features. The first components from the SVD computation are the most importatant while the later ones are least important.