Generate random matrix with eigenvalues - matlab

I am doing the following to generate random matrices with eigenvalues in a specific range:
function mat = randEig(dim, rReal)
D=diff(rReal).*rand(dim,1)+rReal(1);
P=rand(dim);
mat=P*diag(D)/P;
end
But I also want to be able to generate random real matrices with complex (conjugate) eigenvalues. How would one do that? The similarity transformation trick would return complex matrices.
EDIT: Okay I managed to do it by piggybacking on MATLAB's cdf2rdf function (which is basically the second function below).
function mat = randEig(dim, rangeEig, nComplex)
if 2*nComplex > dim
error('Cannot happen');
end
if nComplex
cMat=diff(rangeEig).*rand(dim-2*nComplex,1)+rangeEig(1);
for k=1:nComplex
rpart=(diff(rangeEig).*rand(1,1)+rangeEig(1))*ones(2,1);
ipart=(diff(rangeEig).*rand(1,1)+rangeEig(1))*i;
ipart=[ipart; -ipart];
cMat=[cMat; rpart+ipart];
end
else
cMat=diff(rangeEig).*rand(dim,1)+rangeEig(1);
end
D=cMat;
realDform = comp2rdf(diag(D));
P=rand(dim);
mat=P*realDform/P;
end
function dd = comp2rdf(d)
i = find(imag(diag(d))');
index = i(1:2:length(i));
if isempty(index)
dd=d;
else
if (max(index)==size(d,1)) | any(conj(d(index,index))~=d(index+1,index+1))
error(message('Complex conjugacy not satisfied'));
end
j = sqrt(-1);
t = eye(length(d));
twobytwo = [1 1;j -j];
for i=index
t(i:i+1,i:i+1) = twobytwo;
end
dd=t*d/t;
end
end
But the code is ugly, mainly the way rand is called multiple times is annoying). If someone wants to post an answer that calls rand once and manages to do the trick I will surely accept and upvote.

I made it either a single call or two calls with this:
function mat = randEig(dim, rangeEig, nComplex)
if 2*nComplex > dim
error('Cannot happen');
end
if nComplex
cMat=diff(rangeEig).*rand(2*nComplex,1)+rangeEig(1);
cPart=cMat(1:nComplex)*i;
cMat(1:nComplex)=[];
cPart=upsample(cPart,2);
cPart=cPart+circshift(-cPart,1);
cMat=upsample(cMat,2);
cMat=cMat+circshift(cMat,1);
cMat=cMat+cPart;
cMat=[diff(rangeEig).*rand(dim-2*nComplex,1)+rangeEig(1); cMat];
else
cMat=diff(rangeEig).*rand(dim,1)+rangeEig(1);
end
D=cMat;
realDform = comp2rdf(diag(D));
P=rand(dim);
mat=P*realDform/P;
end
function dd = comp2rdf(d)
i = find(imag(diag(d))');
index = i(1:2:length(i));
if isempty(index)
dd=d;
else
if (max(index)==size(d,1)) | any(conj(d(index,index))~=d(index+1,index+1))
error(message('Complex conjugacy not satisfied'));
end
j = sqrt(-1);
t = eye(length(d));
twobytwo = [1 1;j -j];
for i=index
t(i:i+1,i:i+1) = twobytwo;
end
dd=t*d/t;
end
end
If someone can make it a single call or shorter/more elegant code they are welcome to post an answer.

Related

Fill matrix with function values in Matlab

I've got 3 functions, oe1(n), oe2(n) and oe3(n).
I want to create a matrix representing the function values.
The structure of the matrix should be like this:
A = [oe1(0) oe2(0) oe3(0); oe1(1) oe2(1) od3(1); ...... ; oe1(N-1), oe2(N-1), oe3(N-1)];
I've tried filling it with a for loop, but it does not work.
Is there a standard Matlab operation for this? I really can't figure out how to do it.
Anders.
oe1(n1) = sin(2*pi*F*n1+phi)
oe2(n1) = ones(length(n1),1);
oe3(n1) = n1*Ts
pol = (oe2)'
vector_x = [a; b; c];
vector_veardier = [oe1(n1), 1, oe3(n1)]
xi = 1:N-1;
for i = 2:N-1;
for j = 1:3
vector_veardier(i, j) = oe1(j);
end
end
Do your functions accept vectors? If so you can use:
A = [oe1((1:N)'), oe2((1:N)'), oe3((1:N)')];
but otherwise you might have to use arrayfun:
A = [arrayfun(#oe1, (1:N)'), arrayfun(#oe2, (1:N)'), arrayfun(#oe3, (1:N)')];
Note that in your provided code you have not defined oeN as functions, but as some kind of array with a value inserted at position n1.
One way to do it with a for loop would however be:
A = zeros(N,3);
for i = 1:N,
A(i,:) = [oe1(i), oe2(i) oe3(i)];
end

Building a vector of multiple structure values in MATLAB

I'm trying to create a function that reads in a field of a structure to create a vector of fields. I have a structure of the form:
subject(i).stride(j).strideLength
and there are 10 subjects, about 10 strides per subject. I can create a long vector of the strideLength of all subjects, all strides with code like this:
k = 1;
for i=1:10
for j=1:size(subject(i).stride, 2)
varVector(k) = subject(i).stride(j).strideLength;
k = k + 1;
end
end
however, there are a lot of different fields I want to do this with, and I'd like to do it with a function that I can call like this:
x(1) = groupData(strideLength);
but I can't figure out the syntax to append strideLength to subject(i).stride(j). within the above loop in a function. This is what I hoped would work and didn't:
function [varVector] = groupData(var)
%groupData returns a concatenated vector of a given variable (speed, etc.)
k = 1;
for i=1:10
for j=1:size(subject(i).stride, 2)
varVector(k) = subject(i).stride(j).var;
k = k + 1;
end
end
end
Any thoughts on how to do this right? Thanks in advance!
In your groupData function, pass in the field/variable name as a string
x(1) = groupData('strideLength');
Then in the body of the code, access this field as follows
varVector(k) = subject(i).stride(j).(var);
Try the above and see what happens!

For loop for storing value in many different matrix

I have written a code that stores data in a matrix, but I want to shorten it so it iterates over itself.
The number of matrices created is the known variable. If it was 3, the code would be:
for i = 1:31
if idx(i) == 1
C1 = [C1; Output2(i,:)];
end
if idx(i) == 2
C2 = [C2; Output2(i,:)];
end
if idx(i) == 3
C3 = [C3; Output2(i,:)];
end
end
If I understand correctly, you want to extract rows from Output2 into new variables based on idx values? If so, you can do as follows:
Output2 = rand(5, 10); % example
idx = [1,1,2,2,3];
% get rows from Output which numbers correspond to those in idx with given value
C1 = Output2(find(idx==1),:);
C2 = Output2(find(idx==2),:);
C3 = Output2(find(idx==3),:);
Similar to Marcin i have another solution. Here i predefine my_C as a cell array. Output2 and idx are random generated and instead of find i just use logical adressing. You have to convert the data to type cell {}
Output2 = round(rand(31,15)*10);
idx = uint8(round(1+rand(1,31)*2));
my_C = cell(1,3);
my_C(1,1) = {Output2(idx==1,:)};
my_C(1,2) = {Output2(idx==2,:)};
my_C(1,3) = {Output2(idx==3,:)};
If you want to get your data back just use e.g. my_C{1,1} for the first group.
If you have not 3 but n resulting matrices you can use:
Output2 = round(rand(31,15)*10);
idx = uint8(round(1+rand(1,31)*(n-1)));
my_C = cell(1,n);
for k=1:n
my_C(1,k) = {Output2(idx==k,:)};
end
Where n is a positive integer number
I would recommend a slighty different approach. Except for making the rest of the code more maintainable it may also slightly speed up the execution. This due to that matlab uses a JIT compiler and eval must be recompiled every time. Try this:
nMatrices = 3
for k = 1:nMatrices
C{k} = Output2(idx==k,:);
end
As patrik said in the comments, naming variables like this is poor practice. You would be better off using cell arrays M{1}=C1, or if all the Ci are the same size, even just a 3D array M, for example, where M(:,:,1)=C1.
If you really want to use C1, C2, ... as you variable names, I think you will have to use eval, as arielnmz mentioned. One way to do this in matlab is
for i=1:3
eval(['C' num2str(idx(i)) '=[C' num2str(idx(i)) ';Output2(' num2str(i) ',:)];'])
end
Edited to add test code:
idx=[2 1 3 2 2 3];
Output2=rand(6,4);
C1a=[];
C2a=[];
C3a=[];
for i = 1:length(idx)
if idx(i) == 1
C1a = [C1a; Output2(i,:)];
end
if idx(i) == 2
C2a = [C2a; Output2(i,:)];
end
if idx(i) == 3
C3a = [C3a; Output2(i,:)];
end
end
C1=[];
C2=[];
C3=[];
for i=1:length(idx)
eval(['C' num2str(idx(i)) '=[C' num2str(idx(i)) ';Output2(' num2str(i) ',:)];'])
end
all(C1a(:)==C1(:))
all(C2a(:)==C2(:))
all(C3a(:)==C3(:))

Saving intermediate variable values of a recursive function

I'm trying to code a function calculating difference quotients. I need to this for polynomial interpolation. Given nodes x = linspace(a,b,n+1), function values at the nodes y = func(x) I want to find the values of difference quotients f[x0], f[x_0,x_1], ..., f[x_0,x_1,...,x_n]. To calculate f[x_0,x_1,...,x_n] I will need f[x_0,x_1,...,x_(n-1)], etc., thus it would be a good idea save the intermediate steps on my way to f[x_0,x_1,...,x_n], so that on my way to f[x_0,x_1,...,x_n] I will save the preceding difference quotients as elements of a vector.
Could someone tell me how to correct my code in order to save appropriate difference quotient values? Here's the code:
function [fx, all_fx] = ilo2(a,b,x,y,fx,all_fx)
if a == b
fx(end+1) = y(a);
if a == 1
all_fx(end+1) = fx(end);
end
return
end
a;
b;
[c, all_fx] = ilo2(a+1,b,x,y,fx,all_fx);
[d, all_fx] = ilo2(a,b-1,x,y,fx,all_fx);
fx(end+1) = (c-d)/(b-a);
if a == 1
all_fx(end+1) = fx(end);
end
end
The difference quotients I need are under 'if a == 1' condition.
Ok, I think I fixed it:
function [all_fx,fx] = ilo(a,b,x,y,all_fx,fx)
if a == b
fx(end+1) = y(a);
if a == 1
all_fx(end+1) = fx(end);
end
return
end
[all_fx,c] = ilo(a+1,b,x,y,all_fx,fx);
[all_fx,d] = ilo(a,b-1,x,y,all_fx,fx);
fx(end+1) = (c-d)/(b-a);
if a == 1
all_fx(end+1) = fx(end);
end
end

Whats wrong with my function code (MATLAB/OCTAVE)

I am trying to make my program work. It is for prime numbers.
Below is my function then my main program
I believe this is the right formatting, (obviously I'm probably wrong cause its not working) and I have been trying to fix it to no avail. Any help will be most appreciated and an explanation of what I am doing wrong (I am pretty sure it has to do with subtle formatting) would be great too.
function [answer,primefactors ] = primey1 (N)
for i=2:(N-1)
A(i-1)=rem(N,i);
end
A;
if(all(A)==1)
answer=['Yes']
primefactors=[1,N]
elseif(all(A)==0)
answer=['No']
fac=[]
for i=2:N
q=0;
while N/i==floor(N/i)
N=N/i;
q=q+1;
end
if q>0
fac=[fac,i]
if N==1
break
primefactors=[fac]
end
end
end
end
endfunction
As noted by Magla, MATLAB comes with the primes and factor functions, which you can at least use to compare your implementation with and/or check your outcomes.
Anyway, as for your code, try this:
function [answer, primefactors] = primey1(N)
% Use vectorization for simple cases such as these:
A = rem(N,2:N-1);
if all(A)
answer = 'Yes';
primefactors = [1,N];
% Re-wrote this entire section. There were a bunch of things wrong with it:
% the order of commands was wrong, variables were not assigned for some N,
% etc. Just compare the two implementations
else
answer = 'No';
primefactors = [];
for ii = 2:N
q = 0;
while N/ii == floor(N/ii)
N = N/ii;
q = q+1;
end
if q > 0
primefactors = [primefactors,ii]; %#ok<AGROW>
if N==1
break;
end
end
end
end
end
Matlab has a factor function that does what your code is trying to do
p = factor(10)
returns 2, 5
and
p = factor(11)
returns 11.
All you have is to test for length
if length(p) == 1
is true for prime numbers.
The solution as offered by #Rody should do the job, in theory even more efficient than this, however to illustrate the concept of initialization, I would recommend you to initialize the output variables of your function right after the function start. In your case this would mean that I recommend starting the code like this:
function [answer, primefactors] = primey1(N)
% Function to determine whether a number is prime and which prime factors it has
% Assign default values
answer = 'No';
primefactors = [];