In Matlab, I often have to work with matrices coming from another person's code, and there's not always a clear convention on the orientation of the matrices (transposed or not) and if a certain row/column is added. Therefore I spend much of my time debugging the following error
Error using *
Inner matrix dimensions must agree.
And similar errors for +,.*,-,etc.
It would save me a lot of time if I could modify this error message to include the dimensions, so that I know which one to switch, and potentially guess where the wrong dimension got into. Hence, I would like to somehow modify the error message to include the dimensions at hand:
Error using *
Inner matrix dimensions must agree: 243 x 23 and 98 x 23.
Is this possible, and if so, how can I do it? I currently spend a lot of time adding/removing/testing debug code that prints out this info, so any solution that brings this any closer would be helpful!
You can use a try-catch block:
a = rand(12);
b = rand(10);
try
c = a*b;
catch err
% Because err is read-only, generate new error structure
% We can copy most of old one
newerr.identifier = err.identifier;
newerr.cause = err.cause;
newerr.stack = err.stack;
newerr.message = sprintf('%s size(a): [%u, %u] size(b): [%u, %u]', err.message, size(a), size(b));
error(newerr) % Throw new error
end
Now we get:
Error using testcode (line 5)
Inner matrix dimensions must agree. size(a): [12, 12] size(b): [10, 10]
Each arithmetic operator in Matlab has an associated method that gets called when you invoke that operator. For example, the method corresponding to * (matrix multiplication) is called mtimes.
For each operator, you can define a method for variables of type double that shadows the builtin method and modifies its behaviour: in your case, include custom error checking and then call the builtin method.
The advantages of this approach are:
No modification in your code is neccessary: you will use *, *., + etc normally; but their (error-checking) behaviour will change.
When (you think) you're done debugging, you only need to remove your custom methods from the path. This will restore normal behaviour and thus avoid any speed penalty. Later, if you need to debug again, all you need to do is place the modified methods back on the path.
In the following I use * and its associated mtimes as an example. Your new mtimes method should be placed in Matlab's path, in an appropriate folder so that it has precedence over the bulitin mtimes. That means the folder should be up in Matlab's path. Or you can use the current folder, which has precedence over all others.
Within the selected folder create a folder called #double, and in it create a file called mtimes.m. This tells Matlab that your mtimes.m file should be used whenever the * is invoked with double inputs.
The contents of mtimes.m whould be something along the following lines:
function C = mtimes(A,B)
if ndims(A)~=2 || ndims(B)~=2
%// number of dimensions is incorrect
error('MATLAB:mtimes_modified:ndims', ...
'One of the arrays is not a matrix: numbers of dimensions are %i and %i',...
ndims(A), ndims(B));
elseif max(size(A))>1 & max(size(B))>1 size(A,2)~=size(B,1)
%// dimensions are not appropriate for matrix multiplication,
%// or for multiplying by a matrix by a scalar
error('MATLAB:plus_modified:dimagree',...
'Sizes do not match: %i x %i and %i x %i', ...
size(A,1), size(A,2), size(B,1), size(B,2));
else
C = builtin('mtimes', A, B); %// call actual mtimes to multiply matrices
end
Example results:
>> rand(3,4,5)*rand(6,7)
Error using * (line 3)
One of the arrays is not a matrix: numbers of dimensions are 3 and 2
>> rand(3,4)*rand(2,5)
Error using * (line 7)
Sizes do not match: 3 x 4 and 2 x 5
>> rand(3,4)*rand(4,2)
ans =
0.3162 0.3009
1.2628 0.7552
1.2488 0.8559
If you must do it with many calculations of matrices, then you can write functions like this for example:
function C = matproduct(A, B)
try
C = A * B;
catch ME
switch ME.identifier
case 'MATLAB:dimagree'
msg = [ME.message, ' Size of ', inputname(1), ' :', num2str(size(A)), '. Size of ', inputname(2), ' :', num2str(size(B)), '.'];
case 'MATLAB:innerdim'
msg = [ME.message, ' Size of ', inputname(1), ' :', num2str(size(A)), '. Size of ', inputname(2), ' :', num2str(size(B)), '.'];
% other cases and corresponding modified msg here
end
throw(MException(ME.identifier, msg));
end
end
However i'm not sure if it affects the speed ... And if you use it as matproduct(matproduct(a, b), c) for a * b * c for example, then name of the 1st input cannot be displayed.
Related
When trying to use the integral2 function, I get the following warning:
"Integrand function outputs did not match to the required tolerance when the same input values were supplied in two separate calls with different size input matrices. Check that the function is vectorized properly."
My code is:
z1=0; z2=5;
t1=0; t2=10;
a=1:500;
b=linspace(0.15,0.02,length(a));
c=[a;b];
d=4.9e-07;
func = #(z,t) my_func((z + t),c) .* exp(-d.*t);
int_x = integral2(func,z1,z2,t1,t2,'RelTol',1e-3,'AbsTol',1e-3) ./ (z2 - z1);
my_func is:
function out = my_func(z_in,c)
z=reshape(z_in,1,numel(z_in));
for i=1:length(z)
if (z(i)<0.0)
z(i)=0.0;
end
end
expfactor=exp(-z/150);
sB=5.5*0.9*4*expfactor;
mB=0.9*interpolate(c(1,:),c(2,:),z);
out=sB+mB;
out=reshape(out,size(z_in,1),size(z_in,2));
end
z1=0, z2=9.6, t1=0, t2=3000 (i.e. all have the size (1,1)), and I have used element-wise operations, so not sure what the problem is.
When debugging, my_func is called three times, with z and t having different sizes each time (although same as each other; (14,14), (2,3) and (14,14)). When sizes are (14,14), the values of z are unique for each column, but the same for each row (e.g. [3,2,1;3,2,1]), and vice versa for t (e.g. [4,4,4;5,5,5]). But when sizes are (2,3), all values in the z and t matrices are unique. The warning comes after the second and third call.
What could be the reasons for the warning?
Edit: to accommodate the dimension requirements in my_func, I've reshaped z to a vector at the start, then reshaped the output back to matrix at the end, copying a similar function I've seen. But this returns the warning:
"Non-finite result. The integration was unsuccessful. Singularity likely."
Thanks
I am trying to code something in Matlab and it involves a lot of accessing elements in vectors. Below is a snippet of code that I am working on:
x(1)=1;
for i=2:18
x(i)=0;
end
for i=1:18
y(i)=1;
end
for i = 0:262124
x(i+18+1) = x(i+7+1) + mod(x(i+1),2);
y(i+18+1) = y(i+10+1) + y(i+7+1) + y(i+5+1) + mod(y(i+1), 2);
end
% n can be = 0, 1, 2,..., 262142
n = 2;
for i = 0: 262142
z(i+1) = x(mod(i+n+1, 262143)); %error: Subscript indices must either be real positive integers or logicals.
end
In the last "for" loop where I am initialising vector z(), I get an error saying: "Subscript indices must either be real positive integers or logicals." However, when I do not suppres z(i+1) by ommiting the semi colon, the program is able to run, and I can see the values of z in the workspace. Why is this?
The code I am writing in Matlab is based upon the series of instructions shown in the image below. However, I can't seem to track down my error which leads to me not being able to access the elements of x() (without not suppressing the output of z()).
I appreciate any ideas :-) Thank you!
The code breaks at that loop last iteration because , for i=262140 you get
(mod(i+n+1, 262143)) = 0
so you cant access x(0) in matlab. the first elements of any variable is x(1).
In addition, and not related to your question, this code doesn't use the advantages matlab has, instead of
for i=2:18
x(i)=0;
end
you can just write:
x(2:18)=0;
etc
I've got some code to numerically solve for eigenvectors:
function[efun,V,D] = solveeig(n,xmax,i)
for j=1:i
%The first and second derivative matrices
dd = 1/(xmax/n)^2*(-2*diag(ones(n,1))+diag(ones(n-1,1),1)+...
diag(ones(n-1,1),-1));
d = 1/(xmax/n)*((-1*diag(ones(n,1)))+diag(ones(n-1,1),1));
%solve for the eigenvectors
[V,D] = eig(-dd-2*d);
%plot the eigenvectors (normalized) with the normalized calculated
%eigenfunctions
x = linspace(0,xmax,n);
subplot(i,1,j);
plot(x,V(:,j)/sum(V(:,j)),'*');
hold on
efun = exp(-x).*sin(j*pi*x/xmax);
plot(x,efun/(sum(efun)),'r');
shg
end
end
i is supposed to be the first i eigenvectors, n is the dimension of the
matrices (the number of pieces we discretize x into), xmax is the upper limit of the range on which the fxn is defined.
I'm trying to run this from the command line (as: "solveeig # # #", where the number signs correspond to i, n, and xmax) but no matter what I seem to put in for i, n, and xmax, I get "For colon operator with char operands, first and last operands must be char."
What should I be writing on the command line to get this to run?
Using the command syntax interprets the arguments as strings
For fuller details see the documentation but in short:
Calling
myFun myVar1 6 myVar2
is equivalent to calling
myFun('myVar1','6','myVar2')
and not the desired1
myFun(myVar1,6,myVar2)
In the first cases the function will receive 3 strings (text)
In the second the function will receive the data stored in myVar1 myVar2 and the number 6
The specific error you received is caused by line 2 for j=1:i here i is a string. This error is a merely consequence of the way the function has been called, the line itself is fine2.
How to get it to work
Use function syntax: in the command window something like:
solveeig(n,xmax,i)
If command syntax is absolutely required ( and I can't think why it would be) the much less favourable alternative would be to parse the strings inputted in command syntax. To convert the numbers into numeric formats and use evalin/assignin on the passed variable names to pull variables in from the caller
1As mentioned in comments by patrik
2meaning it won't error, however i and j as variable names is another matter
I am new to Matlab. I was reading this code snippet, but in some parts (marked with asterisks) I don't understand what it means, so if anybody could help would be very much appreciated
function [A1nmb] = moran(initsize, popsize)
% MORAN generates a trajectory of a Moran type process
% which gives the number of genes of allelic type A1 in a population
% of haploid individuals that can exist in either type A1 or type A2.
% The population size is popsize and the initial number of type A1
% individuals os initsize.
% Inputs: initsize - initial number of A1 genes
% popsize - the total population size (preserved)
if (nargin==0)
initsize=10;
popsize=30;
end
A1nmb=zeros(1,popsize);
A1nmb(1)=initsize;
**lambda = inline('(x-1).*(1-(x-1)./N)', 'x', 'N');
mu = inline('(x-1).*(1-(x-1)./N)', 'x', 'N');**
x=initsize;
i=1;
while (x>1 & x<popsize+1)
if (lambda(x,popsize)/(lambda(x,popsize)+mu(x,popsize))>rand)
x=x+1;
A1nmb(i)=x;
else
x=x-1;
A1nmb(i)=x;
end;
i=i+1;
end;
nmbsteps=length(A1nmb);
***rate = lambda(A1nmb(1:nmbsteps-1),popsize) ...
+mu(A1nmb(1:nmbsteps-1),popsize);***
**jumptimes=cumsum(-log(rand(1,nmbsteps-1))./rate);**
jumptimes=[0 jumptimes];
stairs(jumptimes,A1nmb);
axis([0 jumptimes(nmbsteps) 0 popsize+1]);
The first line you marked
lambda = inline('(x-1).*(1-(x-1)./N)', 'x', 'N');
creates something called an inline function. It is equivalent to defining a mathematical function. Example:
y = inline('x^2')
would allow you to do
>> y(2)
4
This immediately explains the second line you marked.
rate = lambda(A1nmb(1:nmbsteps-1),popsize) ...
+mu(A1nmb(1:nmbsteps-1),popsize);
will compute the value of the function lambda(x,N) at x = A1nmb(1:nmbsteps-1) and N = popsize.
I will say immediately here that you should take a look at anonymous functions, a different format used to accomplish the same as inline. Only, anonymous functions are generally better supported, and usually a lot faster than inline functions.
Then, for the final line,
jumptimes = cumsum(-log(rand(1,nmbsteps-1))./rate);
is a nested command. rand will create a matrix containing pseudorandom numbers, log is the natural logarithm ("ln"), and cumsum creates a new matrix, where all the elements in the new matrix are the cumulative sum of the elements in the input matrix.
You will find the commands doc and help very useful. Try typing
doc cumsum
or
help inline
on the Matlab command prompt. Try that again with the commands forming the previous statement.
As a general word of advice: spend an insane lot of time reading through the documentation. Really, for each new command you encounter, read about it and play with it in a sandbox until you feel you understand it. Matlab only becomes powerful if you know all its commands, and there are a lot to get to know.
It defines an inline function object. For example this
lambda = inline('(x-1).*(1-(x-1)./N)', 'x', 'N')
defines lambda as a function with 2 variables. When you call lambda(A,n) Matlab simply expands the function you define in the first string. Thus lambda(A,n) using the variables you provide in the function call. lambda(A,n) would will evaluate to:
(A-1).*(1-(A-1)./n)
it just expands the function using the parameters you supply. Take a look at this link for more specific details http://www.mathworks.co.uk/help/techdoc/ref/inline.html
The cumsum function just returns the cumulative sum of a matrix along a particular dimension. Say we call cumsum on a vector X, then the value at element i in the result is equal to the sum of elements in X from index 1 to i. For example X = [1 2 1 3] we would get
AA = cumsum(X);
we would have
AA = [1 3 5 8]
See this link for more details and examples http://www.mathworks.co.uk/help/techdoc/ref/cumsum.html
I used nlfilter for a test function of mine as follows:
function funct
clear all;
clc;
I = rand(11,11);
ld = input('Enter the lag = ') % prompt for lag distance
A = nlfilter(I, [7 7], #dirvar);
% Subfunction
function [h] = dirvar(I)
c = (size(I)+1)/2
EW = I(c(1),c(2):end)
h = length(EW) - ld
end
end
The function works fine but it is expected that nlfilter progresses element by element, but in first two iterations the values of EW will be same 0.2089 0.4162 0.9398 0.1058. But then onwards for all iterations the next element is selected, for 3rd it is 0.4162 0.9398 0.1058 0.1920, for 4th it is 0.9398 0.1058 0.1920 0.5201 and so on. Why is it so?
This is nothing to worry about. It happens because nlfilter needs to evaluate your function to know what kind of output to create. So it uses feval once before starting to move across the image. The output from this feval call is what you see the first time.
From the nlfilter code:
% Find out what output type to make.
rows = 0:(nhood(1)-1);
cols = 0:(nhood(2)-1);
b = mkconstarray(class(feval(fun,aa(1+rows,1+cols),params{:})), 0, size(a));
% Apply fun to each neighborhood of a
f = waitbar(0,'Applying neighborhood operation...');
for i=1:ma,
for j=1:na,
x = aa(i+rows,j+cols);
b(i,j) = feval(fun,x,params{:});
end
waitbar(i/ma)
end
The 4th line call to eval is what you observe as the first output from EW, but it is not used to anything other than making the b matrix the right class. All the proper iterations happen in the for loop below. This means that the "duplicate" values you observe does not affect your final output matrix, and you need not worry.
I hope you know what the length function does? It does not give you the Euclidean length of a vector, but rather the largest dimension of a vector (so in your case, that should be 4). If you want the Euclidean length (or 2-norm), use the function norm instead. If your code does the right thing, you might want to use something like:
sz = size(I,2);
h = sz - (sz+1)/2 - ld;
In your example, this means that depending on the lag you provide, the output should be constant. Also note that you might want to put semicolons after each line in your subfunction and that using clear all as the first line of a function is useless since a function will always be executed in its own workspace (that will however clear persistent or global variables, but you don't use them in your code).