MATLAB: Limit from n to infinity for power of a matrix - matlab

I am trying to compute lim(n->inf) for D^n, where D is a diagonal matrix:
D = [1.0000 0 0 0; 0 0.6730 0 0; 0 0 0.7600 0; 0 0 0 0.7370]
n = 1
L = limit(D^n,n,inf)
This returns the error:
Undefined function 'limit' for input arguments of type 'double'.
I am sure this should result in most entries except the upper-left entry going to zero, but I need to be able to present this with MATLAB results. Is there something else I need to include in my limit function?

If your problem is to compute the inf-limit of a diagonal matrix, you'd better create your own function and handle manually the possible cases :
function Mlim = get_diag_matrix_inf_limit(M)
% get the diagonal
M_diag = diag(M);
% All possible cases
I_nan = M_diag <= -1;
I_0 = abs(M_diag) < 1;
I_1 = M_diag == 1;
I_inf = M_diag > 1;
% Update diagonal
M_diag(I_nan) = nan;
M_diag(I_0) = 0;
M_diag(I_1) = 1;
M_diag(I_inf) = Inf;
% Generate new diagonal matrix
Mlim = diag(M_diag);
end

Related

Using 'fminunc', I receive Optimization completed because the size of the gradient is less than the value of the optimality tolerance

I use fminunc to find the value of B (2x4 matrix) that minimzes the difference between the corresponding elements in two vectors as indicated in the attached code. In other words, I want to find the B that makes the elements of beta_d (1x4 vector) which is a function of B matrix, equal to the corresponding ones of a "given" beta_u (1x4 vector), i.e. beta_d(1,1) = beta_u(1,1) && beta_d(1,2) = beta_u(1,2) && beta_d(1,3) = beta_u(1,3) && beta_d(1,4) = beta_u(1,4).
However, I usually receive the following message without getting any result and the program seems to go on an infinite loop!
Local minimum found.
Optimization completed because the size of the gradient is less than
the value of the optimality tolerance.
<stopping criteria details>
The code is as follows:
% System paramters:
N = 2;
K = 4;
C_l = 4;
H = [-0.3208 -0.9784; -1.5994 -1.4689; -1.5197 -0.4568; -0.0993 -0.7667]; % 4*2 matrix
A = [-1 1; 0 1]; % 2x2 matrix
C = [-0.20 0.4 0.6 -0.2; -0.2 0.4 0.6 -0.2; 0.4 0.2 -0.2 0.4; 0.4 0.2 -0.2 0.4]; % 4x4 matrix
P = [250000 0 0 0; 0 250000 0 0; 0 0 250000 0; 0 0 0 250000]; % 4x4 matrix
beta_u = [50.2207 50.2207 20.3433 20.3433]; % 1x4 vector
beta_d = zeros(1,4); % intial value
B = zeros(2,4); % intial value
% store inputs to a struct for shorter syntax
s = struct();
[s.H,s.A,s.C,s.P,s.C_l,s.N,s.K] = deal(H,A,C,P,C_l,N,K);
%fminunc optimization
while (sum(abs(beta_u-beta_d))>=0.1)
initial_guess = randn(2,4);
OLS = #(B_d,input_vars)sum((beta_u-myfun(B_d,input_vars)).^2); % ordinary least squares cost function
opts = optimoptions(#fminunc,'MaxIterations',10000,'MaxFunctionEvaluations',50000,'CheckGradients',true);
B = fminunc(OLS, initial_guess, opts,s);
input_vars = s;
[beta_d, D_d] = myfun(B,input_vars);
end
% calculate beta_d from B and the other inputs
function [beta_d, D_d] = myfun(B,input_vars)
% load parameters
s = input_vars;[H,A,C,P,C_l,N,K]=deal(s.H,s.A,s.C,s.P,s.C_l,s.N,s.K);
for j = 1:1:N
d(j) = (B(j,:)*P*B(j,:)')/((2^(2*C_l))-(norm(A(:,j))^2));
end
D_d = diag(d);
for i = 1:1:K
V_d(i) = C(i,:)*P*B'*H(i,:)'*inv(1+H(i,:)*(A'*D_d*A+B*P*B')*H(i,:)');
sigma_d(i) = norm((V_d(i)*H(i,:)*B-C(i,:))*(P^(1/2)))^2+(V_d(i)^2)*(1+H(i,:)*A'*D_d*A*H(i,:)');
beta_d(i) = ((P(i,i))/sigma_d(:,i));
end
end

Output 1, 0.5, or 0 depending if a matrix elements are prime, 1, or neither

I am sending a matrix to my function modifikuj, where I want to replace the elements of the matrix with:
1 if element is a prime number
0 if element is a composite number
0.5 if element is 1
I dont understand why it is not working. I just started with MATLAB, and I created this function:
function B = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j))
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
With
A = [1,2;3,4];
D = modifikuj(A);
D should be:
D=[0.5, 1; 1 0];
In MATLAB you'll find you can often avoid loops, and there's plenty of built in functions to ease your path. Unless this is a coding exercise where you have to use a prescribed method, I'd do the following one-liner to get your desired result:
D = isprime( A ) + 0.5*( A == 1 );
This relies on two simple tests:
isprime( A ) % 1 if prime, 0 if not prime
A == 1 % 1 if == 1, 0 otherwise
Multiplying the 2nd test by 0.5 gives your desired condition for when the value is 1, since it will also return 0 for the isprime test.
You are not returning anything from the function. The return value is supposed to be 'B' according to your code but this is not set. Change it to A.
You are looping k until A(i,j) which is always divisible by itself, loop to A(i,j)-1
With the code below I get [0.5,1;1,0].
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j)-1)
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
In addition to #EuanSmith's answer. You can also use the in built matlab function in order to determine if a number is prime or not.
The following code will give you the desired output:
A = [1,2;3,4];
A(A==1) = 0.5; %replace 1 number with 0.5
A(isprime(A)) = 1; %replace prime number with 1
A(~ismember(A,[0.5,1])) = 0; %replace composite number with 0
I've made the assumption that the matrice contains only integer.
If you only want to learn, you can also preserve the for loop with some improvement since the function mod can take more than 1 divisor as input:
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
k = A(i,j);
if (k == 1)
A(i,j) = 0.5;
else
if all(mod(k,2:k-1)) %check each modulo at the same time.
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
And you can still improve the prime detection:
2 is the only even number to test.
number bigger than A(i,j)/2 are useless
so instead of all(mod(k,2:k-1)) you can use all(mod(k,[2,3:2:k/2]))
Note also that the function isprime is a way more efficient primality test since it use the probabilistic Miller-Rabin algorithme.

Problem to add element to matrix in if-else condition in Matlab

I'm writing a simple program to implement Artificial Neural Network to recognize handwritten characters using Matlab. I used following code to set Target data according to different characters.
Here is a part of code:
load('dataset.mat')
Target_Set=zeros(2,400); %Initialize Target array with 0s
%Set dimensions to resize
h = 50;
w = 45;
imgSize = h*w;
for j=1:4
for i=1:10
for k=1:10
Temp_Struct = struct('im',imresize(handwriting(i,j,k).im,[h,w]));
n = 100*(j-1) + 10*(i-1) + k;
P_Set(1:imgSize,n) = reshape(Temp_Struct.im,[imgSize,1]);
%Set Target patterns...
if (j==1) %When character I % Target Patterns...
Line 19========>Target_Set(0,n) = 1; % I J K L
Target_Set(1,n) = 0; % 0 1 0 1
elseif(j==2) %When character J % 0 0 1 1
Target_Set(0,n) = 1;
Target_Set(1,n)=0;
elseif(j==3) %When character K
Target_Set(0,n) = 0;
Target_Set(1,n)=1;
else %When character L
Target_Set(0,n) = 1;
Target_Set(1,n)=1;
end;
end;
end;
end;
When I run this, I got some error like this.
I couldn't understand why that kind of error occur in line 19. Welcome for any help.
Arrays in Matlab start at index number 1. So it is complaining about your use of a 0 value as an array index.
It should be correct like this.
Target_Set(1,n) = 0;

Accelerate Matlab nested for loop with bsxfun

I have a graph n x n graph W described as its adjacency matrix and a n vector of group labels (integers) of every node.
I need to count the number of links (edges) between nodes in group c and nodes in group d for every pair of groups. Do to this I wrote a nested for loop but I'm sure that this is not the fastest way to compute the matrix that in the code I call mcd, i.e. the matrix that counts the number of edges betweeen group c and d.
Is it possible through the bsxfun to make this operation faster?
function mcd = interlinks(W,ci)
%// W is the adjacency matrix of a simple undirected graph
%// ci are the group labels of every node in the graph, can be from 1 to |C|
n = length(W); %// number of nodes in the graph
m = sum(nonzeros(triu(W))); %// number of edges in the graph
ncomms = length(unique(ci)); %// number of groups of ci
mcd = zeros(ncomms); %// this is the matrix that counts the number of edges between group c and group d, twice the number of it if c==d
for c=1:ncomms
nodesc = find(ci==c); %// nodes in group c
for d=1:ncomms
nodesd = find(ci==d); %// nodes in group d
M = W(nodesc,nodesd); %// submatrix of edges between c and d
mcd(c,d) = sum(sum(M)); %// count of edges between c and d
end
end
%// Divide diagonal half because counted twice
mcd(1:ncomms+1:ncomms*ncomms)=mcd(1:ncomms+1:ncomms*ncomms)/2;
For example in the picture here the adjacency matrix is
W=[0 1 1 0 0 0;
1 0 1 1 0 0;
1 1 0 0 1 1;
0 1 0 0 1 0;
0 0 1 1 0 1;
0 0 1 0 1 0];
the group label vector is ci=[ 1 1 1 2 2 3] and the resulting matrix mcd is:
mcd=[3 2 1;
2 1 1;
1 1 0];
It means for example that group 1 has 3 links with itself, 2 links with group 2 and 1 link with group 3.
How about this?
C = bsxfun(#eq, ci,unique(ci)');
mcd = C*W*C'
mcd(logical(eye(size(mcd)))) = mcd(logical(eye(size(mcd))))./2;
I think it is what you wanted.
IIUC and assuming ci as an sorted array, it seems you are basically doing blockwise summations, but with irregular block sizes. Thus, you can use an approach using cumsum along the rows and columns and then differentiating at the shift positions in ci, which will basically give you blockwise summations.
The implementation would look like this -
%// Get cumulative sums row-wise and column-wise
csums = cumsum(cumsum(W,1),2)
%/ Get IDs of shifts and thus get cumsums at those positions
[~,idx] = unique(ci) %// OR find(diff([ci numel(ci)]))
csums_indexed = csums(idx,idx)
%// Get the blockwise summations by differentiations on csums at shifts
col1 = diff(csums_indexed(:,1),[],1)
row1 = diff(csums_indexed(1,:),[],2)
rest2D = diff(diff(csums_indexed,[],2),[],1)
out = [[csums_indexed(1,1) ; col1] [row1 ; rest2D]]
If you're not opposed to a mex function, you can use my code below.
testing code
n = 2000;
n_labels = 800;
W = rand(n, n);
W = W * W' > .5; % generate symmetric adjacency matrix of logicals
Wd = double(W);
ci = floor(rand(n, 1) * n_labels ) + 1; % generate ids from 1 to 251
[C, IA, IC] = unique(ci);
disp(sprintf('base avg fun time = %g ',timeit(#() interlinks(W, IC))));
disp(sprintf('mex avg fun time = %g ',timeit(#() interlink_mex(W, IC))));
%note this function requires symmetric (function from #aarbelle)
disp(sprintf('bsx avg fun time = %g ',timeit(#() interlinks_bsx(Wd, IC'))));
x1 = interlinks(W, IC);
x2 = interlink_mex(W, IC);
x3 = interlinks_bsx(Wd, IC');
disp(sprintf('norm(x1 - x2) = %g', norm(x1 - x2)));
disp(sprintf('norm(x1 - x3) = %g', norm(x1 - x3)));
testing results
Testing results with these settings:
base avg fun time = 4.94275
mex avg fun time = 0.0373092
bsx avg fun time = 0.126406
norm(x1 - x2) = 0
norm(x1 - x3) = 0
Basically, for small n_labels, the bsx function does very well but you can make it large enough so that the mex function is faster.
c++ code
throw it into some file like interlink_mex.cpp and compile with mex interlink_mex.cpp. You need a c++ compiler on your machine etc...
#include "mex.h"
#include "matrix.h"
#include <math.h>
// Author: Matthew Gunn
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
if(nrhs != 2)
mexErrMsgTxt("Invalid number of inputs. Shoudl be 2 input argument.");
if(nlhs != 1)
mexErrMsgTxt("Invalid number of outputs. Should be 1 output arguments.");
if(!mxIsLogical(prhs[0])) {
mexErrMsgTxt("First argument should be a logical array (i.e. type logical)");
}
if(!mxIsDouble(prhs[1])) {
mexErrMsgTxt("Second argument should be an array of type double");
}
const mxArray *W = prhs[0];
const mxArray *ci = prhs[1];
size_t W_m = mxGetM(W);
size_t W_n = mxGetN(W);
if(W_m != W_n)
mexErrMsgTxt("Rows and columns of W are not equal");
// size_t ci_m = mxGetM(ci);
size_t ci_n = mxGetNumberOfElements(ci);
mxLogical *W_data = mxGetLogicals(W);
// double *W_data = mxGetPr(W);
double *ci_data = mxGetPr(ci);
size_t *ci_data_size_t = (size_t*) mxCalloc(ci_n, sizeof(size_t));
size_t ncomms = 0;
double intpart;
for(size_t i = 0; i < ci_n; i++) {
double x = ci_data[i];
if(x < 1 || x > 65536 || modf(x, &intpart) != 0.0) {
mexErrMsgTxt("Input ci is not all integers from 1 to a maximum value of 65536 (can edit source code to change this)");
}
size_t xx = (size_t) x;
if(xx > ncomms)
ncomms = xx;
ci_data_size_t[i] = xx - 1;
}
mxArray *mcd = mxCreateDoubleMatrix(ncomms, ncomms, mxREAL);
double *mcd_data = mxGetPr(mcd);
for(size_t i = 0; i < W_n; i++) {
size_t ii = ci_data_size_t[i];
for(size_t j = 0; j < W_n; j++) {
size_t jj = ci_data_size_t[j];
mcd_data[ii + jj * ncomms] += (W_data[i + j * W_m] != 0);
}
}
for(size_t i = 0; i < ncomms * ncomms; i+= ncomms + 1) //go along diagonal
mcd_data[i]/=2; //divide by 2
mxFree(ci_data_size_t);
plhs[0] = mcd;
}

Don't know how to Correct : "In an assignment A(I) = B, the number of elements in B and I must be the same."

I saw other topics about this error but I couldn't figure it out. The error "In an assignment A(I) = B, the number of elements in B and I must be the same" occurs at the second for loop. How can I change my code to avoid this error?
h1 = [70 31.859 15 5.774 3.199 2.15 1.626];
h2 = [31.859 15 5.774 3.199 2.15 1.626 1.415];
b = [1253 1253 1253 1253 1253 1253 1253];
R = [455.4 425.6 377.6 374.9 371.3 273.7 268.3];
r = [0.5448714286 0.5291754292 0.6150666667 0.4459646692 0.3279149734 0.2437209302 0.1297662977];
k = [200 200 200 200 200 200 200];
s = sqrt(r/(1-r));
v2 = [20 0 0 0 0 0 0];
v1 = [0 0 0 0 0 0 0];
Ch1 = [0 0 0 0 0 0 0];
Ch2 = [0 0 0 0 0 0 0];
C = [100 100 100 100 100 100 100];
F = b .* k .* sqrt(R-(h1-h2))- R.*sin((acos((R-((h1-h2)./2))./R))) .* (pi/2) .* (1./sqrt(r./(1-r))) .* (atan(sqrt(r./(1-r))))-(pi/4) - (1./(sqrt(r./(1-r)) .* sqrt(h2./R))).* log((h2+R.*((sqrt(h1./R).*tan(1/2 .* atan(sqrt(r./(1-r)).*sqrt(h1./r).*log(1./(1-k))))).^2).*sqrt(1-r))./h2)
M = -R.*R.*(k./2).*(.2*(sqrt(h2./R)*tan(0.5*(atan(s)))-(pi/8).*sqrt(h2./R).*log(1./1-r)))-(acos((R-((h1-h2)./2))./R))
for i=1:6
v1(i) = ((v2(i)*h2)/h1);
v2(i+1) = v1(i);
end
vr = ((v1.*h1)./h2)./(((tan(0.5.*((atan(s)))-(pi/8).*sqrt(h2./R).*log(1./(1-r)))).^(2))+1)
%--------------------------------------------------------------------------
% Calculating E
w = (((2.*R.*h2).^(3/2))./(300.*(b.^2)))
if (w <= (3*10^-4));
E = ((0.0821.*((log(w))^2))+(1.25.*log(w))+4.89)
end
if ((3*10^-4)<= w <= (2.27*10^-3));
E = ((0.0172.*((log(w)).^2))+(0.175.*log(w))+0.438)
end
if (w > (2.27*10^-3))
E = 0.01
end
%--------------------------------------------------------------------------
% Calculating Ch:
y = ((((2.*R).^(0.5)).*((h2).^(1.5)))./(b.^2))
N1 = (0.5-(1/pi).*atan((log(y)+8.1938)./(1.1044)))
N = ((h2./h1).*N1)
for i=1:1;7
Ch2(i) = (h2.*((N.*((Ch1(i)./h2)-(C./h2)))+(C/h2)))
Ch1(i+1) = Ch2(i)
end
DeltaStrain = (E.*((Ch2./h2)-(Ch1./h1)))
if DeltaStrain > 0;
Stepp = ((2/pi).*(sqrt(DeltaStrain))))
Control = 2;
else
Stepp = ((2/pi).*(sqrt(-DeltaStrain))
Control = 0;
end
In the line
Ch2(i) = (h2.*((N.*((Ch1(i)./h2)-(C./h2)))+(C/h2)))
h2 is a vector, and Ch2(i) is a scalar. You cannot assign the value of a vector to a scalar. I suspect you want to replace the entire for loop. Right now you have
for i=1:1;7
Ch2(i) = (h2.*((N.*((Ch1(i)./h2)-(C./h2)))+(C/h2)))
Ch1(i+1) = Ch2(i)
end
(?? what is the meaning of 1:1;7? Is that a typo? I am thinking you want 1:7...
Since you seem to be using the result of one loop to change the value of Ch1 which you are using again in the next loop, it may be tricky to vectorize; but I wonder what you are expecting the output to be, since you really do have a vector as the result of the RHS of the equation. I can't be sure if you want to compute the result for one element at a time, or whether you want to compute vectors (and end up appending results to Ch1 and Ch2). The following line would run without throwing an error - but it may not be the calculation you want. Please clarify what you are hoping to achieve if this is an incorrect guess.
for i = 1:7
Ch2(i) = h2.*(N.*((Ch1(i) - C(i))./h2(i))) + C(i)./h2(i);
Ch1(i+1) = Ch2(i);
end