Input parser: one parameter dependent from another parameter - matlab

I am using the input parser functionality a lot but now I am facing the following issue:
I am coding an object that computes the rate-of-change of time series, i.e. one input argument is a matrix of doubles (timeSeries). A second input parameter is the time period used to compute the rate-of-change (lag). lag can be a vector wherby different rate-of-changes will be computed. A third input vector is called weightVector. weightVector will be used to compute an average of all rate-of-changes and applies the appropriate weights to the respective rate-of-change results.
Now, I always like to define some default values when using input parser. I would like to define weightVector to be an equal weighted vector. However, the length of the default weightVector is dependent on the length of lag. For example, if lag = [1,2,3], then weightVectorshould equal [1/3, 1/3, 1/3]. How am I supposed to code a situation like this? My current code for the constructor looks like this:
function obj = roc(timeSeries, varargin)
%% Input parser
% 1. Create input parser instance
p = inputParser;
% 2. Default values for input arguments
default_lag = 1;
default_weightVector = 1/length(lag); % This line is causing
% problems as LAG isn't
% defined, yet.
% 3. Validation of input arguments
valid_lag = {'vector', 'nonempty', 'integer', 'positive'};
check_lag = #(x) validateattributes(x, {'numeric'}, valid_lag);
valid_weightVector = {'vector', 'nonempty'};
check_weightVector = #(x) validateattributes(x, {'numeric'}, ...
valid_weightVector);
% 4. Add input arguments to input scheme
p.addRequired('timeSeries');
p.addParamater('lag', default_lag, check_lag);
p.addParameter('weightVector', default_weightVector, check_weightVector);
% 5. Parse input arguments
parse(p, timeSeries, varargin{:});
% 6. Assign results to variables
lag = p.Results.lag;
weightVector = p.Results.weightVector;
%% Main code
end % Constructor

function obj = roc(timeSeries, varargin)
%% Input parser
% 1. Create input parser instance
p = inputParser;
% 2. Default values for input arguments
default_lag = 1;
default_weightVector = 1;
% 3. Validation of input arguments
valid_lag = {'vector', 'nonempty', 'integer', 'positive'};
check_lag = #(x) validateattributes(x, {'numeric'}, valid_lag);
% 4. Add input arguments to input scheme
p.addRequired('timeSeries');
p.addParameter('lag', default_lag, check_lag);
p.addParameter('weightVector', default_weightVector);
% 5. Parse input arguments
parse(p, timeSeries, varargin{:});
% 6. Assign results to variables
lag = p.Results.lag;
if check_weightVector(p.Results.weightVector, lag) == true
weightVector = p.Results.weightVector;
end
function vout = check_weightVector(weightVector, lag) % validation function
if length(lag) ~= length(weightVector)
error('lengthWeightVector:WrongNumberOfElements', 'The number of elements in "weightVector" must correspond to the number of elements in "lag"');
elseif sum(weightVector) ~= 1
error('sumWeightVector:SumNotEqualToOne', 'The sum of elements in "weightVector" must equal 1');
end
vout = true;
end
%% Main code
end

Related

Conditional selection of all possible parameter combinations in MATLAB

This is a follow-up of the question All possible combinations of many parameters MATLAB
In addition to all possible combinations of my parameter set, I also have a conditional parameter. For example, I need to include the parameter named 'lambda' only when the parameter 'corrAs' is set to 'objective'.
Do achieve this, right now I am doing the following
%% All posible parameters
params.corrAs = {'objective', 'constraint'};
params.size = {'small', 'medium', 'large'};
params.density = {'uniform', 'non-uniform'};
params.k = {3,4,5,6};
params.constraintP = {'identity', 'none'};
params.Npoints_perJ = {2, 3};
params.sampling = {'hks', 'fps'};
% If corrAs is 'objective', then also set lambda
params.lambda = {0.01, 0.1, 1, 10, 100};
%%%%%%%%%%%%% The solution posted on the link %%%%%%%%%%%
%% Get current parameter and evaluate
fields = fieldnames(params);
nFields = numel(fields);
sz = NaN(nFields, 1);
% Loop over all parameters to get sizes
for jj = 1:nFields
sz(jj) = numel( params.(fields{jj}) );
end
% Loop for every combination of parameters
idx = cell(1,nFields);
for ii = 1:prod(sz)
% Use ind2sub to switch from a linear index to the combination set
[idx{:}] = ind2sub( sz, ii );
% Create currentParam from the combination indices
currentParam = struct();
for jj = 1:nFields
%%%%%%%%%%% My addition for conditional parameter %%%%%%%%%%%
% lambda is valid only when corrAs is 'objective'
if isfield(currentParam, 'corrAs') && strcmp(fields{jj}, 'lambda') && ~strcmp(currentParam.corrAs, 'objective')
continue;
end
currentParam.(fields{jj}) = params.(fields{jj}){idx{jj}};
end
%% Do something with currentParam
end
It works but, the number of iterations for the main for loop also includes the lambda parameter even when corrAs is not 'objective'. So, I end up evaluating with the same currentParam many times than I am supposed to.
How can I do it more efficiently?
An easy way to think about this is by breaking the code up to be more function-based
In the below code, I've simply put the combination processing code into a function paramProcessing. This function is called twice -
When params.corrAs is 'constraint' only, all combinations will be processed, with no lambda field.
When params.corrAs is 'objective' only, all combinations will be processed with the additional lambda field.
You can have an output for the paramProcessing function if there is one from the looping.
This means you're only doing the combinations you want. From your question, it seems like each combination is independent, so it should be irrelevant that you're covering the combinations in separate loops. The function usage means you don't have to have the new condition in the loop, and the distinct possible values for params.corrAs each time ensure no overlap.
The paramProcessing function can be a local function in a main function file, as shown, local in a script (for newer MATLAB versions), or in its own .m file on your path.
Code:
function main()
%% All posible parameters, corrA is 'constraint' only.
params.corrAs = {'constraint'};
params.size = {'small', 'medium', 'large'};
params.density = {'uniform', 'non-uniform'};
params.k = {3,4,5,6};
params.constraintP = {'identity', 'none'};
params.Npoints_perJ = {2, 3};
params.sampling = {'hks', 'fps'};
% First processing call, no 'lambda' field exists in 'params'
paramProcessing( params );
% Cover the cases where corrAs is 'objective', with 'lambda' field
params.corrAs = {'objective'};
params.lambda = {0.01, 0.1, 1, 10, 100};
% Second processing call, with new settings
paramsProcessing( params );
end
function paramProcessing( params )
%% Get current parameter and evaluate
fields = fieldnames(params);
nFields = numel(fields);
sz = NaN(nFields, 1);
% Loop over all parameters to get sizes
for jj = 1:nFields
sz(jj) = numel( params.(fields{jj}) );
end
% Loop for every combination of parameters
idx = cell(1,nFields);
for ii = 1:prod(sz)
% Use ind2sub to switch from a linear index to the combination set
[idx{:}] = ind2sub( sz, ii );
% Create currentParam from the combination indices
currentParam = struct();
for jj = 1:nFields
currentParam.(fields{jj}) = params.(fields{jj}){idx{jj}};
end
%% Do something with currentParam
end
end

In Matlab I keep getting undefined variable or function error despite clearly defining the variable

I have this piece of code in Matlab which should take an Airfoil profile and increase the number of points so that when I plot the profile in another programme I will get a smoother curve.
clear
%reading an external data file
fid = fopen('NACA0015.txt');
a = fscanf(fid,'%g %g',[2 inf]); % It has two rows now.
a = a'; % matrix transpose
n = input('200') %e.g., n=35
for i=1:n
for j=1:2
fprintf('%12.7f',a(i,j)); %a(i,1) is first column, a(i,2) is 2nd col
end
fprintf('\n');
end
fclose(fid);
for i=1:n
x(i)=a(i,1); %x , y vectors
y(i)=a(i,2);
end
% use spline to create more points
xx=0:0.01:1 % e.g., step =0.01 (number of points = (1-0)/0.01=100)
yy = spline(x,y,xx); % xx and yy are new generated values of Naca0012
fprintf('\n print spline values \n');
plot(xx,yy,'ro')
hold on
plot(x,y,'*')
When I run this I get the error
Undefined function or variable 'x'.
Error in reading_external_data_and_spline (line 26)
yy = spline(x,y,xx); % xx and yy are new generated values of Naca0012
I am at a complete loss as to why this is not working when the x variable is clearly defined in the code, please could someone help me with this
It's how you're using input. The argument in input isn't the default value, it's the prompt text. If you type the command into the console and hit enter, you get this:
>> n = input('200')
200
n =
[]
>>
Input doesn't accept a default. If you really want to have an interactive prompt with a default answer, you want inputdlg:
answer = inputdlg('Enter a number of lines to parse', 'n', 1, '200');
n = str2double(answer);
note that inputdlg returns text always, so you need to convert to a number.

matlab - is there a function which echo text of file ?

Since it is not possible to have a script and a function definition in the same file , I thought to echo the function which I want to attach in the script such that I get a script with function code and then some usage with this function .
For example -
func1.m
function [result] = func1(x)
result=sqrt(x) ;
end
script1.m
echo(func1.m) ;
display(func1(9))
Desire output for script1.m
function [result] = func1(x)
result=sqrt(x) ;
end
display(func1(9))
3
Have you any idea for that ?
Since a convoluted solution was already proposed, why not stating the obvious?
Matlab has a built-in command that does exactly what you want. It is called type:
>> type('mean')
will give you this:
function y = mean(x,dim)
%MEAN Average or mean value.
% For vectors, MEAN(X) is the mean value of the elements in X. For
% matrices, MEAN(X) is a row vector containing the mean value of
% each column. For N-D arrays, MEAN(X) is the mean value of the
% elements along the first non-singleton dimension of X.
%
% MEAN(X,DIM) takes the mean along the dimension DIM of X.
%
% Example: If X = [0 1 2
% 3 4 5]
%
% then mean(X,1) is [1.5 2.5 3.5] and mean(X,2) is [1
% 4]
%
% Class support for input X:
% float: double, single
%
% See also MEDIAN, STD, MIN, MAX, VAR, COV, MODE.
% Copyright 1984-2005 The MathWorks, Inc.
% $Revision: 5.17.4.3 $ $Date: 2005/05/31 16:30:46 $
if nargin==1,
% Determine which dimension SUM will use
dim = min(find(size(x)~=1));
if isempty(dim), dim = 1; end
y = sum(x)/size(x,dim);
else
y = sum(x,dim)/size(x,dim);
end
You could use this:
function echo(mfile)
filename=which(mfile);
if isempty(filename)
fprintf('Invalid input - check you are inputting a string.');
return;
end
fid=fopen(filename,'r');
if (fid<0)
fprintf('Couldn''t open file.');
end
file=fread(fid,Inf);
fclose(fid);
fprintf('%s',file);
end
This will open a file, read it, and print it. Note that you need to provide the input as a string, i.e. with single quotes around it, and need to have '.m' at the end:
echo('fread.m')
Not
echo(fread.m) % This won't work
echo('fread') % This won't work
Just for completeness, there's also dbtype which prepends line numbers.

define anonymous function as 2 of 4 outputs of m file function

I have an m-file function with 4 outputs. I would like to define an anonymous function that has the same inputs, but only produces 2 of the four outputs. Is this possible?
AFAIK, you can't do this with just an inline anonymous function, because that Matlab syntax doesn't provide a way of capturing and indexing in to multiple outputs of a function in a single expression. But you can write a couple reusable helper functions that do so, and then define anonymous functions using them.
Let's say your four argout function is named "f4".
function varargout = f4(x)
%F4 Dummy function that returns 4 argouts holding identifying indexes
varargout = num2cell(1:4);
Here's a reusable helper function that remaps outputs of a function call.
function varargout = callandmap(fcn, ix, varargin)
%CALLANDMAP Call a function and rearrange its output arguments
tmp = cell(1,max(ix)); % Capture up to the last argout used
[tmp{:}] = fcn(varargin{:}); % Call the original function
varargout = tmp(ix); % Remap the outputs
Now you can make anonymous, argout-remapping functions like this. Here, g holds an anonymous function that takes the same inputs as your original function, but just returns 2 of its original 4 outputs.
>> g = #(varargin) callandmap(#f4, [2 4], varargin{:})
g =
#(varargin)callandmap(#f4,[2,4],varargin{:})
>> [a,b] = g('dummy') % gets argouts 2 and 4 from original f4() function
a =
2
b =
4
>>
Using varargin allows you to omit trailing arguments when the resulting function handle is called. If you know all argins will always be provided, you can use named argins for readability if you want.
You can get even fancier and do this with a closure.
function fcn = mapargout(fcnIn, ixArgout)
%MAPARGOUT Create wrapper function that selects or reorders argouts
%
% fcn = argoutselector(fcnIn, ixArgout)
%
% Wraps a given function handle in a function that rearranges its argouts.
% This uses closures so it may have performance impacts.
%
% FcnIn is a function handle to wrap.
%
% IxArgout is a list of indexes in to the original functions argout list
% that should be used as the outputs of the new function.
%
% Returns a function handle to a new function.
fcn = #extractor;
function varargout = extractor(varargin)
n = max(ixArgout);
tmp = cell(1,n);
% Call the wrapped function, capturing all the original argouts
[tmp{:}] = fcnIn(varargin{:});
% And then select the ones you want
varargout = tmp(ixArgout);
end
end
This results in simpler code for creating the anonymous function. And you could compose it with other function wrapper calls.
>> g = mapargout(#f4, [2 4])
g =
#mapargout/extractor
>> [a,b] = g('dummy')
a =
2
b =
4
>>
But closures can be tricky to work with in Matlab and may have performance implications. The callandmap approach is probably preferable unless you need the extra power.
If the two outputs are #1 and #2, everything is fine, and you don't have to worry about the other two outputs.
If the two outputs are any two others, you have two options
(1) Create a wrapper function with two outputs (note that in newer versions of Matlab you can replace the unused outputs dummy by ~.
function [out1,out2] = wrapperFunction(in1,in2,in3)
[dummy,out1,dummy,out2] = mainFunction(in1,in2,in3);
(2) Add another input variable that allows you to switch your function's behavior
function varargout = mainFunction(in1,in2,in3,outputSwitch)
%# make output switch optional
if nargin < 4 || isempty(outputSwitch)
outputSwitch = 0;
end
%# calculation here that creates out1-4
if outputSwitch
%# the special case where we only want outputs 2 and 4
varargout = {out2,out4};
else
%# return all four outputs
varargout = {out1,out2,out3,out4}
end
Then you can create the anonymous function as usual.

How do I display strings and numbers together in MATLAB?

I have a 500-by-1 matrix of strings S and a 500-by-1 matrix of numbers N. I want to see them in the variable editor together like this:
S(1) N(1)
S(2) N(2)
...
S(500) N(500)
Is this possible?
The following should allow you to look at the variables together in the Command Window:
disp([char(S) blanks(numel(N))' num2str(N)]);
The array S (which I presume is a cell array) is converted to a character array using the function CHAR. It's then concatenated with a column vector of blanks (made using the function BLANKS) and then a string representation of the numeric array N (made using the function NUM2STR). This is then displayed using the function DISP.
Speaking narrowly to your question, just convert the numbers to cells. You'll have a single variable that the array editor can handle.
X = [ S num2cell(N) ];
More broadly, here's an array-oriented variant of sprintf that's useful for displaying records constructed from parallel arrays. You'd call it like this. I use something like this for displaying tabular data a lot.
sprintf2('%-*s %8g', max(cellfun('prodofsize',S)), S, N)
Here's the function.
function out = sprintf2(fmt, varargin)
%SPRINTF2 Quasi-"vectorized" sprintf
%
% out = sprintf2(fmt, varargin)
%
% Like sprintf, but takes arrays of arguments and returns cellstr. This
% lets you do formatted output on nonscalar arrays.
%
% Example:
% food = {'wine','cheese','fancy bread'};
% price = [10 6.38 8.5];
% sprintf2('%-12s %6.2f', food, price)
% % Fancier formatting with width detection
% sprintf2('%-*s %6.2f', max(cellfun('prodofsize',food)), food, price)
[args,n] = promote(varargin);
out = cell(n,1);
for i = 1:n
argsi = grab(args, i);
out{i} = sprintf(fmt, argsi{:});
end
% Convenience HACK for display to command line
if nargout == 0
disp(char(out));
clear out;
end
function [args,n] = promote(args)
%PROMOTE Munge inputs to get cellstrs
for i = 1:numel(args)
if ischar(args{i})
args{i} = cellstr(args{i});
end
end
n = cellfun('prodofsize', args);
if numel(unique(n(n > 1))) > 1
error('Inconsistent lengths in nonscalar inputs');
end
n = max(n);
function out = grab(args, k)
%GRAB Get the kth element of each arg, popping out cells
for i = 1:numel(args)
if isscalar(args{i})
% "Scalar expansion" case
if iscell(args{i})
out{i} = args{i}{1};
else
out{i} = args{i};
end
else
% General case - kth element of array
if iscell(args{i})
out{i} = args{i}{k};
else
out{i} = args{i}(k);
end
end
end