Does there exist a simple function in Matlab that will give more informative feedback when using assert with matrices than the simple application of the assert function?
My simple application is:
>> assert(all([1 2; 3 4] == [1 2; 3 5], 'all'))
Assertion failed.
In Python, with numpy.testing.assert_equal the feedback from a failed assertion shows the two arrays.
I guess it would be possible to define further the arguments to the assert function errmsg, value1 and value2.
assert is to validate intermediate values inside your code, so you get an error when something is not as you expect, and you can debug it. This is the “fail early” philosophy. You don’t need to get a detailed output here, it tells you that you need to break out the debugger.
Your use case seems closer to testing the output of a function, to verify it works as intended. This is a very different use case, for which MATLAB has the testing framework.
For example, your equality comparison would be implemented through verifyEqual:
testCase = matlab.unittest.TestCase.forInteractiveUse;
verifyEqual(testCase,A,B)
Here's one of the many ways assert can be used in conjunction with the try/catch and throw commands to catch errors and take specific actions (e.g. print a message and throw an exception that can be captured by the calling function:
function out = myfun(A, B)
out = 0;
try
assert(all(size(A)==size(B)), 'Matrix sizes do not match')
catch exc % contains the message passed by assert
fprintf('Size of A is: %d, %d\n',size(A)); % show the actual dimensions
fprintf('Size of B is: %d, %d\n',size(B));
out = 1;
throw(exc) % throws exc and returns control to the caller
end
try
assert(isequal(A,B), 'Matrix are not identical.')
catch exc % contains the message passed by assert
disp(A==B) % show 0 where elements don't match
out = 1;
throw(exc) % throws exc and returns control to the caller
end
end
Calling myfun with A=ones(4,4) and B=ones(4,5) produces the following output:
Calling myfun with A=ones(4,4) and B=2*ones(4,4) leads to:
As I mentioned at the very beginning, the function above represent one of the possible implementations.
Related
Please refer to the documentation for the testCase.verifyEqual method here. The documentation says that only one of the diagnostic features can be used. My requirement is I need two diagnostics at the same time - strings and function handle. The following is simple example of what I'm trying to achieve,
classdef testArrays < matlab.unittest.TestCase
methods (Test)
function testArraysEquality(testCase)
a = 1:10;
b = 1:10;
incrementFunc = #(x)x+1;
failureCount;
for i=1:length(a)
testCase.verifyEqual(a(i),b(i),'AbsTol',10e-3,['Test failed array element# ' num2str(i) ' failure count ' num2str(incrementFunc(failureCount))]);
end
disp([num2str(failureCount) ' out of ' num2str(length(a)) ' test cases failed']);
end
end
end
The problem is Anonymous function don't store values. On the other hand with the 'assignin' feature shown below, the value can be incremented and stored, but cannot be returned for use inside disp(). Is there any work around for this?
incrementFunc1 = #(x) assignin('caller', inputname(1), x+1);
You can include more than one (as well as more than one type) of diagnostic in the MATLAB Unit Test Framework by simply providing a diagnostic array to verifyEqual. You can actually do this explicitly as follows:
import matlab.unittest.diagnostics.StringDiagnostic;
import matlab.unittest.diagnostics.FunctionHandleDiagnostic;
testCase.verifyEqual(a,e, [StringDiagnostic('some string'), FunctionHandleDiagnostic(#() someFunction)]);
However, the Diagnostic.join method is provided to make that easier:
import matlab.unittest.diagnostics.Diagnostic;
testCase.verifyEqual(a,e, Diagnostic.join('some string', #() someFunction));
In order to do the increment call you are probably going to want to add a failed listener to the testCase in order to increment properly. Note that people/plugins can actually add listeners and execute these diagnostics in passing cases in addition to failing cases. As such your diagnostic messages should not assume that every time they are invoked it is in a failure condition. This not only applies to your incrementing code but also to just the message you are providing. I would suggest that instead of saying:
Test failed array element# 3 failure count 2
you should say:
Tested array element# 3 failure count 2
The framework diagnostic will let you know whether it failed or not. Anyway, takeaway, don't rely on invoking the diagnostics to determine failure count. What then? Take a look at the Events section here. You should listen explicitly for verification failed events in order to add that information to your diagnostics.
For the first solution, I am not sure why you need to provide the failure count for every failure. It seems like that would be very verbose. If you don't need that then you can do something like this:
classdef testArrays < matlab.unittest.TestCase
methods (Test)
function testArraysEquality(testCase)
a = 1:10;
b = 1:10;
failureCount = 0;
testCase.addlistener('VerificationFailed', #incrementFailureCount);
function incrementFailureCount(varargin)
% This is a nested function & has the scope and can see/modify
% the failureCount variable. This could also be done with a
% property on the class ans a method that increments it
failureCount = failureCount + 1;
end
for i=1:length(a)
testCase.verifyEqual(a(i),b(i),'AbsTol',10e-3,['Tested array element # ' num2str(i)]);
end
% I suggest using log instead of disp. If you want it to show up most of the time you can
% log it at Terse (1) verbosity. However, if you don't want to see it you can turn it off.
testCase.log(1, sprintf('%d out of %d test cases failed', failureCount, length(a)));
end
end
end
Is that good enough? If you really want to show the failure count in the diagnostics for each failure you can its just a bit more complicated and requires another nested function (or property access).
classdef testArrays < matlab.unittest.TestCase
methods (Test)
function testArraysEquality(testCase)
import matlab.unittest.diagnostics.Diagnostic;
a = 1:10;
b = 1:10;
failureCount = 0;
testCase.addlistener('VerificationFailed', #incrementFailureCount);
function incrementFailureCount(varargin)
failureCount = failureCount + 1;
end
function displayFailureCount
fprintf(1, 'Failure Count: %d', failureCount);
end
for i=1:length(a)
testCase.verifyEqual(a(i),b(i),'AbsTol',10e-3, ...
Diagnostic.join(...
['Tested array element #' num2str(i)], ...
#displayFailureCount));
end
testCase.log(1, sprintf('%d out of %d test cases failed', failureCount, length(a)));
end
end
end
Does that help you accomplish what you are trying to do?
function [ muln, varargout ] = my_mul( varargin )
%MY_MUL This function is used to multiply numbers.
% My_mul function multiplies array of entered numbers, and outputs single
% solution.
% For example: my_mul(12, 2, 3, 5) gives ans = 360
if nargout >=1
disp('Error, wrong number of output arguments');
varargout{1} = 0;
return
end
if nargin <= 1
disp('Error, small number of input argumnets');
return
else
muln = 1;
for i = 1:nargin
muln = muln*varargin{i};
end
end
end
Hi, everyone, I'm just doing my assignment for uni and have a qiuck question.
How can I make this function to give an error if it is called with more than one output.(It meant to give only one) Thanks!
In your function definition, you have defined your function to allow for an unlimited number of outputs. The keyword varargout is a place-holder for a variable number of outputs.
As you have stated in your question, you only want one possible output which in your case looks to be muln. So if you simply remove varargout from your function definition, MATLAB should automatically throw an error if too many outputs are requested
function muln = my_mul(varargin)
If you ever do need to use varargout but want to place constraints on how many outputs are provided for any given scenario, you can check the number of output arguments that were requested using nargout and then throw an error with the error function.
if nargout > 4
error('my_mul:TooManyOutputs', 'Too many outputs requested');
end
My opinion is that if a return value is expected the function needs to throw. Otherwise the caller (function calling this function) will expect everything to be ok. Note that disp('Error') gives information to the developer, but it does not give the program any indication on what happens. More importantly, the information does not give any indication of where the error occurs. This can force the developer to do heavy debugging just to find the error, which is completely unnecessary.
The use of variable output arguments should only be used in case a different number of output arguments should be expected. An example is some customized plot function
function varargout = myplot(varargin)
filename = '';
idx = find(strcmp(varargin,'filename'));
if (~isempty(idx) && length(varargin)<idx+1 && ~ischar(varargin{idx+1}))
error('filename property must be followed by a directory');
elseif(~isempty(idx))
filename = varargin{idx+1};
varargin([idx,idx+1]) = [];
end
h = plot(varargin{:});
varagout{1} = h;
if (~isempty(idx))
save(filename, h);
end
varagout{2} = filename;
This function works as plot except it saves the figure to file in case a filename is specified. In case the developer needs the handle it will be returned and in case the developer wants the save directory it can be returned as well. None of these arguments are necessary though. The developer may want to use this function as a standard plot function and this means that the user may want to call myplot as myplot(x,y);which does not return a value. Further note that even if 'filename' is not specified, the function can still return 2 outputs. The second output may be an empty array of char, but two outputs for the caller will never cause a crash.
Also, note that no further error handling is required. The only unchecked crashes are in plot and save. How this is handled may be different for different users and this means that it only is reasonable to let the user catch the error and handle it (as he would have done if save or plot would have thrown).
Apart from this you may also want to have a check so that the number of output variables are within the correct range (in this case 0,1 or 2 outputs).
I'm working with someone else's code and I am unfamiliar with try/catch so I made a small, similar example. On line 11, if I write error(''), it doesn't seem to catch the error and increase the index j. However, writing error(' ') or error('bad!') does.
So does having an error with an empty string ignore the error, or am I doing something wrong?
% Just a file to understand the Matlab command try/catch
M = 3;
j = 1;
k = [Inf, 5, 4];
while M>0
try
M = M-1
u = k(j)
if (isinf(u)||isnan(u)), error(''), end;
catch
j = j+1
end
end
Yes, error('') and error([]) and error(struct([])) all do not actually display an error message and abort running code. I personally consider the use of the single string argument version of error to be bad practice in any real code. You should use always use both a 'MSGID' and a 'ERRMSG' when writing errors for your functions, e.g.
error('FunctionName:SubFunctionName:ErrorMSGID','Error message to be printed.')
Alternatively, you can use MException objects in conjuction with throw, rethrow, and throwAsCaller, which allow you to reuse error information. More here.
It is odd, but it's in the documentation for error, for the error('msgString') syntax:
All string input arguments must be enclosed in single quotation marks. If msgString is an empty string, the error command has no effect.
Similarly, if using the error(msgStruct) syntax:
If msgStruct is an empty structure, no action is taken and error returns without exiting the function.
if you have a look to the try documentation you can have an example.
Else want you want for your code it :
M = 3;
j = 1;
k = [Inf, 5, 4];
while M>0
try
M = M-1
u = k(j)
if (isinf(u)||isnan(u)), error(''), end;
catch
disp('I catch an error!');
j = j+1
end
end
Because If you never get an error in your code, it will never go in the catch. So by including error('');, it just to say, go execute the statement in the catch.
But you can just modify your code by replacing the error() by the statements into your catch like this :
while M>0
M = M-1
u = k(j)
if (isinf(u)||isnan(u)), j = j+1, end;
end
EDIT
If you take a look in the documentation, you can found this :
% ERROR(MSGSTRUCT) reports the error using fields stored in the scalar
% structure MSGSTRUCT. This structure can contain these fields:
%
% message - Error message string
% identifier - See MESSAGE IDENTIFIERS, below
% stack - Struct similar to the output of the DBSTACK function
%
% If MSGSTRUCT is an empty structure, no action is taken and ERROR
% returns without exiting the program. If you do not specify the
% stack, the ERROR function determines it from the current file and line.
So no action is taken as you can read. And nothing, so catch don't get any informations.
Not sure why you need it, but here is how it works.
error function does not throw an error with empty string or empty vector ([]) as an argument.
If you don't specify argument at all the error function itself generates the error "Not enough arguments". So it will go to catch.
Another way is to specify an empty structure as an argument.
s = struct();
error(s)
In this case, the error will be generated, but the code will not stop and in general flow you will hear no beep. In your case it should go to catch.
I want to call a function in Matlab using another one, which has the same number of inputs and outputs. In fact, those inputs and outputs have the same name.
Example:
function [a,b] = gettwo(matrix,string,varargin)
[a,b] = getone(matrix,string,varargin{:});
end
This code produces the following error:
Error in getone(line 3)
aux = 'matrix(varargin{:})';
Output argument "b" (and maybe others) not assigned during
call to "C:\Users\baister\Documents\MATLAB\soft\getone.m>getone".
Error in results (line 4)
[a,b] = getone(matrix,string,varargin{:});
How should I wrap getone?
(The definitive function will have more lines than those shown in this post.)
Thanks.
The general wrapping for variable number of outputs should work like this:
function [varargout] = gettwo(matrix,string,varargin)
[varargout{1:nargout}] = getone(matrix,string,varargin{:});
end
You'll get the same error as above though, in case you do
[a,b] = gettwo(...);
and getone returns only 1 argument.
I am trying to write a minimal function that can be called with a variable number of arguments but that will not throw a wrong number of arguments error if miscalled.
Here is where I start from :
function varargout=fname(varargin)
% FNAME
% Usage: output=fname(input)
% Arguments check
if(nargin~=1 || nargout~=1)
disp('Function fname requires one input argument');
disp('and one output argument');
disp('Try `help fname`');
varargout(1:nargout)={0};
return;
end
input=varargin{1};
output=input;
varargout(1)={output};
end
However this does not work as I would like it to. Is there a way to write a function that :
never throw a "wrong number of arguments" error (so that the rest of the execution can continue)
accepts variable number of input and output arguments and checks them inside the function
(maybe more tricky) if the number of input / output arguments is not correct, does not replace the value of the provided output arguments (so that any misplaced call does not erase the previous value of the output argument)
I am open to any suggestions / other methods.
Thank you for your help.
UPDATE: thanks to #Amro for his answer, I guess what I miss here is either a call by address of reference for Matlab functions or a way to interrupt a function without returning anything and without stopping the rest of the execution.
Here is one way to implement your function:
function varargout = fname(input,varargin)
%# FNAME
%# Usage: output=fname(input)
%%# INPUT
if nargin<1
varargout(1:nargout) = {[]};
warning('Not enough input arguments.'), return
end
if ~isempty(varargin)
warning('Too many input arguments.')
end
%%# YOUR CODE: manipulate input, and compute output
output = input;
%%# OUTPUT
varargout{1} = output;
if nargout>1
warning('Too many output arguments.')
varargout(2:nargout) = {[]};
end
end
Obviously you can customize the warning messages to your liking...
Also, if you want your function to simply print the message instead of issuing warnings, replace all WARNING calls with simple DISP function calls.
Examples of function call:
fname()
fname(1)
fname(1,2)
x = fname()
x = fname(1)
x = fname(1,2)
[x,y] = fname()
[x,y] = fname(1)
[x,y] = fname(1,2)
The above calls execute as expected (showing warning messages when applicable). One caveat though, in the last three calls, if the variable y already existed in the workspace prior to the calls, it would be overwritten by the empty value y=[] in each...
If I understand your question correctly, then the answer is no. If a caller calls a function like this:
[a, b, c] = fname('foo');
then fname is required to return (at least) three outputs. There's no way to tell MATLAB that it should leave b and c alone if fname only returns one output.