Can anybody help me create a simple pseudo-random sequence of +-1 integers with length 1000 using Matlab?
I.e. a sequence such as
-1 -1 1 1 -1 -1 1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1 1
I tried using this code below but this is the RANGE -1 to 1, which includes 0 values. I only want -1 and 1. Thanks
x = randi([-1 1],1000,1);
You can try generating a random sequence of floating point numbers from [0,1] and any values less than 0.5 set to -1, and anything larger set to 1:
x = rand(1000,1);
ind = x >= 0.5;
x(ind) = 1;
x(~ind) = -1;
Another suggestion I have is to use the sign function combined with randn so that we can generate both positive and negative numbers. sign generates values that are either -1, 0, 1 depending on the sign of the input. If the input is negative, the output is -1, +1 when positive and 0 when 0. You could do an additional check where any values that are output to 0, set them to -1 or 1:
x = sign(randn(1000,1));
x(x == 0) = 1;
One more (inspired by Luis Mendo) would be to have a vector of [-1,1] and use randi to generate a sequence of either 1 or 2, then use this and sample into this vector:
vec = [-1 1];
x = vec(randi(numel(vec), 1000, 1));
This code can be extended where vec can be anything you want, and we can sample from any element in vec to produce a random sequence of values (observation made by Luis Mendo. Thanks!).
Some alternatives:
x = 2*randi(2, 1000, 1)-3; %// generate 1 and 2 values, and transform to -1 and 1
x = 2*(rand(1, 1000, 1)<=.5)-1; %// similar to Rayryeng's answer but in one step
x = randsample([-1 1], 1000, true); %// sample with replacement from the set [-1 1]
Simply user randsrc function.
It will generate random sequences of 1 and -1.
For example
out = randsrc(2,3)
out =
-1 -1 -1
1 -1 1
Thanks for these many helpful answers. I figure this topic might be general enough it may well deserve a comparison.
In my setup ( Windows8.4 x64 i74820k cpu and with R2014a) the fastest version is consistently:
x=2*round(rand(L,1))-1;
Being half an order of magnitude faster than the slowest solution. Hope this helps.
comparison:
figure comparing execution times for pseudo-random sign generation
code:
L=[];
for expon=0:6
for mant=1:9
L=cat(1,L,mant*power(10,expon));
end
end
clear expon mant
t1=zeros(length(L),1);
x=2*round(rand(L(1),1))-1;
for li=1:length(L)
tic,
x=2*round(rand(L(li),1))-1;
t1(li)=toc;
end
t2=zeros(length(L),1);
x=(rand(L(1),1)>0.5)*2-1;
for li=1:length(L)
tic,
x=(rand(L(li),1)>0.5)*2-1;
t2(li)=toc;
end
t3=zeros(length(L),1);
x=(randi([0,1],L(1),1)>0.5)*2-1;
for li=1:length(L)
tic,
x=(randi([0,1],L(li),1)>0.5)*2-1;
t3(li)=toc;
end
t4=zeros(length(L),1);
x=rand(L(1),1);ind=x>=0.5;x(ind)=1;x(~ind)=-1;
for li=1:length(L)
tic,
x=rand(L(li),1);
ind=x>=0.5;
x(ind)=1;
x(~ind)=-1;
t4(li)=toc;
end
t5=zeros(length(L),1);
x=sign(randn(L(1),1));
for li=1:length(L)
tic,
x=sign(randn(L(li),1));
x(x==0)=1;
t5(li)=toc;
end
t6=zeros(length(L),1);
vec = [-1 1];
x=vec(randi(numel(vec),L(1),1));
for li=1:length(L)
tic,
x=vec(randi(numel(vec),L(li),1));
t6(li)=toc;
end
t7=zeros(length(L),1);
x=2*randi(2,L(1),1)-3;
for li=1:length(L)
tic,
x=2*randi(2,L(li),1)-3;
t7(li)=toc;
end
t8=zeros(length(L),1);
x=randsample([-1 1],L(1),true);
for li=1:length(L)
tic,
x=randsample([-1 1],L(li),true);
t8(li)=toc;
end
clear x vec ind li
figure,
loglog(L,[t1 t2 t3 t4 t5 t6 t7 t8],'.-','linewidth',2)
grid on
grid minor
title('Generating pseudo-random sequence +1/-1')
ylabel('Exec. Time [s]')
xlabel('Output Vector Length')
T{1}='x=2*round(rand(L(1),1))-1';
T{2}='x=(rand(L(1),1)>0.5)*2-1';
T{3}='x=(randi([0,1],L(1),1)>0.5)*2-1';
T{4}='x=rand(L(1),1);ind=x>=0.5;x(ind)=1;x(~ind)=-1';
T{5}='x=sign(randn(L(1),1))';
T{6}='vec=[-1 1];x=vec(randi(numel(vec),L(1),1))';
T{7}='x=2*randi(2,L(1),1)-3';
T{8}='x=randsample([-1 1],L(1),true)';
legend(T,'location','northwest')
x = rand(N,1);
y = sign(x-0.5);
Related
This function in Matlab presents Box_Function:
output = 1 while sample n belongs to the range (-a, +a).
otherwise the output is 0 outside that range.
So how can I implement this function in Matlab in a better way to shift the plot in case of negative values of time, without assigning negative values to the array.
Thanks in Advance
function B_X = Box_Func(N,K,a)
if(N <= 0)||(K+a > N)
warning('Please Enter Valid Positive Integer !');
else
B_X = zeros([-N N]);
for i = -N : 1 : N
if (i >= K-a) && (i <= K+a)
B_X(i)=1;
end
end
end
end
Your question is unclear since it does not really explain what you want to do, and in one comment you state that you know where the error comes from. I suggest to read the docs (also in a comment), but here I'll show you my problems with your code, provide some simple ways of testing your code and I hope this helps to solve your problem and to understand how to ask better questions.
First, one remark to the lines
if(N <= 0)||(K+a > N) % if samples Number wrong, or shifting exceeds limit
% of Samples Print a warning.
warning('Please Enter Valid Positive Integer !');
I suggest to throw an error instead of a warning if the input parameters are wrong and will lead to an error anyway. Otherwise you could omit the test and let Matlab throw the respective error.
The next misunderstanding is
B_X = zeros([-N N])
What do you expect B_X to be after this line if, let's say, N=2? Test if the result is what you expect by simply entering this command in the command line directly:
>> zeros([-2 2])
ans =
0×2 empty double matrix
I guess that's not what you expect. As the docs state, zeros(N) will yield a square matrix with N rows and N columns; zeros(M,N) will yield a matrix with M rows and N columns. Look:
>> zeros(2)
ans =
0 0
0 0
>> zeros(2,1)
ans =
0
0
I do not know what you expect from zeros([-2 2]), but I guess that you are looking for one of the following:
>> N = 2;
>> zeros(2*N+1,1)
ans =
0
0
0
0
0
>> zeros(1,2*N+1)
ans =
0 0 0 0 0
>> zeros(2*N+1)
ans =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
My guess is that somehow you expect the function zeros to operate on some range of indices you provide. Your misunderstanding might be that you expect zeros([-2 2]) to provide a vector of zeros into which you can index using -2:2 (that is, one of -2,-1,0,+1,+2). If you assume this, your assumption is wrong.
I guess this from the line
for i = -N : 1 : N
in your code. Due to this line, I'll first thought that
>> B_X = zeros(1, 2*N+1)
B_X =
0 0 0 0 0
is what you expect. However, from the comment
% if samples Number wrong, or shifting exceeds limit
I guessed that N might be just the number of data points in the result. This would mean
>> B_X = zeros(1, N)
B_X =
0 0
(which would not make much sense for N=2). So, for the next question you ask (or an edit to this question): Clearly explain the meaning of the function inputs!
Since later, you set the limits of your x-axes to [-N N], I'll keep my first assumption, thus the number of data points (and therefore the argument to zeros) should be 2*N+1.
The next argument to your function is K, you call it the shift. k only occurs in combination with the third input of the function, a. You do not provide any inforamtion about a.
From this line I guess that a is something that specifies a width:
if (i >= K-a) && (i <= K+a)
Now, slowly, if one also considers
B_X(i)=1;
and the usage of the word box (and heaviside, which is still in the comments), one can get a clue of what you want to do. Together with your comment that you want your function
to appear on the plotting shifted on X Axis, so it looks like that the center of the Box Function is in the negative area of X axis
Might this be your goal: I want to plot a vector from -N to N (in steps of 1) with zero values except for the region of -K±a, where I want it to be one?
If this is the case, one attempt would be as follows (it remains to you to put it into a function):
>> N=15;
>> K=7;
>> a = 3;
Get the x-values:
>> x = -N:N;
(-15, -14, ... 14, 15). Next, allocate B_X:
>> B_X = zeros(1, 2*N+1);
Last, use logical indexing (this might help to understand this) to set the values around -K±a to one:
>> B_X(x>(-K-a) & x<(-K+a)) = 1;
Eventually, plot the result:
plot(x,B_X);
and adjust the axis limits:
>> ax=gca;
>> ax.YLim = [-.2 1.2];
Result is:
function B_X = Box_Func(N,K,a)
% Box_Func This Function takes Number of Samples N,Count of shift K, and
% half of Box width a then it stem Them ,
% Note it works only for positive shifting
% that means K should be positive or Zero
if(N <= 0)||(K+a > N) % if samples Number wrong, or shifting exceeds limit
% of Samples Print a warning.
warning('Please Enter Valid Positive Integer !');
else % if The inputs are fine , then :
B_X = zeros([1 2*N+1]);
x = -N:N;
B_X(x>=(K-a) & x<=(K+a)) = 1;
end
%===========================================
% Plotting the Results
%===========================================
figure('Name','Box Function','NumberTitle','off');
stem(x,B_X)
hold on
xlabel('Samples')
ylabel('Box Shifeted Function')
xlim([-N N]) ;
ylim([-1 2]);
grid on
hold off
end
Very new to Matlab, I usually use STATA.
I want to use the nchoosek fuction to get the sum of vectors in one matrix.
I have a 21x21 adjacency matrix, with either 0 or 1 as the inputs. I want to create a new matrix, that will give me a sum of inputs between all possible triads from the adjacency matrix.
The new matrix should look have four variables, indexes (i, j, k) - corresponding to each combination from the 21x21. And a final variable which is a sum of the inputs.
The code I have so far is:
C = nchoosek(21,3)
B = zeros(nchoosek(21,3), 4)
for i=1:C
for j=i+1:C
for k=j+1:C
B(?)=B(i, j, k, A(i)+A(j)+A(k)) #A is the 21x21 adj mat
end
end
end
I know my assignment statement is incorrect as I don't completed understand the indexing role of the ":" operator. Any help will be appreciated.
Thanks!
This might be what you want:
clear all
close all
clc
A = rand(21,21); % Replace this with actual A
rowNum = 0;
for i=1:21
for j=i+1:21
for k=j+1:21
rowNum = rowNum+1;
B(rowNum,:) = [i, j, k, sum(A(:,i)+A(:,j)+A(:,k))];
end
end
end
There are some points:
You loop for different combinations. the total number of combination is nchoosek(21,3) which you can check after 3 nested loop. Your code with for i=1:C was the first error since you're actually looping for different values of i and different values of j and k. So these just 21 values not more.
To avoid repeated combinations, it's enough to start new index after the previous one, which you've realized in your code.
There are other possible approaches such as vectorized format, but to stick to your approach, I used a counter: rowNum which is the loop counter and updated along the loop.
B(rowNum,:) means all element of rowNum'th row of the matrix B.
Below is an algorithm to find the triads in an adjacency matrix. It checks all possible triads and sums the values.
%basic adjacency matrix with two triads (1-2-5) (2-3-5)
A=[];
A(1,:) = [0 1 0 0 1];
A(2,:) = [1 0 1 0 1];
A(3,:) = [0 1 0 0 1];
A(4,:) = [0 0 0 0 1];
A(5,:) = [1 1 1 1 0];
A=A==1; %logical matrix
triads=nchoosek(1:5,3);
S=nan(size(triads,1),4);
for ct = 1:size(triads,1)
S(ct,1:3)=[A(triads(ct,1),triads(ct,2)),A(triads(ct,1),triads(ct,3)),A(triads(ct,2),triads(ct,3))];
S(ct,4)=sum(S(ct,1:3));
end
triads(find(S(:,4)==3),:)
ans =
1 2 5
2 3 5
I have a for-loop in which I want to set the matrix values either to +1 or -1
My code looks like this:
for n=1:512
for m=1:512
A(n,m)= randi([-1 1]);
end
end
But right now the values are either +1,0,-1 and not just +1 or -1.
Also there should be equal probability that it is +1 or -1.
Is there a function in Matlab where you can determine that?
first of all randi([imin,imax]) returns a integer drawn from the discrete uniform distribution on the interval [imin,imax], so, in other words, it return -1 or 0 or 1 so that is why you get 0 too.
second you can omit 0 by changing your code like this:
for n=1:512
for m=1:512
A(n,m)= randi([0 1])*2-1;
end
end
use randsample to sample from population (in your case [-1,1]):
% this is sampling from uniform distribution
k = 1;
y = randsample([-1 1],k,true);
and in your case:
k = 512*512;
A = reshape(randsample([-1 1],k,true), [512 512]);
you can use y = randsample([-1 1],k,true,w) to sample from arbitrary distribution:
% this is sampling from distribution where p(x=-1) = 0.2 and p(x=1) = 0.8
k = 1;
w = [0.2,0.8];
y = randsample([-1 1],k,true,w);
To generate a random number that equals -1 or 1 with equal probabilities:
Generate a number uniformly distributed on the interval (0,1) (using rand) and compare with 0.5. This gives false (0) or true (1) with the same probability.
Multiply by 2 and subtract 1 to convert 0, 1 to -1, 1.
So:
result = 2*(rand<0.5)-1;
Or, if you want to generate the whole matrix at once:
A = 2*(rand(512,512)<0.5)-1;
I am trying to create a single column vector (out), which is comprised of a sequence of ones and zeros. These should occur in sets of length B and C respectively, which are repeated A number of times. For example:
out=[1
0
0
1
0
0
1
0
0]
It is currently set up as:
out=[0]; %not ideal, but used to initially define 'out'
A=3;
B=1;
C=2;
for i = 1:length(A)
for ii = 1:length(B)
out(end+1,1) = ones(ii,1);
end
for iii = 1:length(C)
out(end+1,1) = zeros(iii,1);
end
end
This is not working - current output:
out=[0
1
0]
How can I correct these loops to get the desired output? Also, is there a better way of achieving this with the given the inputs?
Many thanks.
1) You do not need to use length as this returns the length of an array type, so A,B,C will all be length of 1.
2) Just directly use the values as shown below. Also you can initialize an empty array with empty brackets []
3) If you're using the zeros and ones commands, these generate whole arrays/matrices and do not need to be in a loop. If you want to keep your loop version, just use =1 or =0
out=[]; %--> you can use this instead
A=3;
B=1;
C=2;
for i = 1:A
out(end+1:end+B,1) = ones(B,1);
out(end+1:end+C,1) = zeros(C,1);
end
... or of course to be more "Matlaby" just do what David said in the comments repmat([ones(B,1);zeros(C,1)],A,1), but the above is there to help you on your way.
How about some modulo arithmetic?
result = double(mod(0:(B+C)*A-1, B+C)<B).';
Example:
>> B = 2; %// number of ones in each period
>> C = 4; %// number of zeros in each period
>> A = 3; %// number of periods
>> result = double(mod(0:(B+C)*A-1, B+C)<B).'
result =
1
1
0
0
0
0
1
1
0
0
0
0
1
1
0
0
0
0
I can suggest 2 ways:
a)Using for loop-
A=3;
B=2;
C=3;
OneVector=ones(1,B); % B is the length of ones.
zeroVector=zeros(1,C); % C is the length of zeros.
combinedVector=cat(2,OneVector,zeroVector);
Warehouse=[]; % to save data
for(i=1:A)
Warehouse=cat(2,Warehouse,combinedVector);
end
b)using repmat:
OneVector=ones(1,B); % B is the length of ones.
zeroVector=zeros(1,C); % C is the length of zeros.
combinedVector=cat(2,OneVector,zeroVector);
Warehouse=repmat(combinedVector, [A,1]);
I hope, this will solve your problem.
I'd like to find a vectorized way to calculate the cumulative sums of a vector, but with upper and lower limits.
In my case, the input only contains 1's and -1's. You can use this assumption in your answer. Of course, a more general solution is also welcome.
For example:
x = [1 1 1 1 -1 -1 -1 -1 -1 -1];
upper = 3;
lower = 0;
s = cumsum(x) %// Ordinary cumsum.
s =
1 2 3 4 3 2 1 0 -1 -2
y = cumsumlim(x, upper, lower) %// Cumsum with limits.
y =
1 2 3 3 2 1 0 0 0 0
^ ^
| |
upper limit lower limit
When the cumulative sum reaches the upper limit (at the 3rd element), it won't increase anymore. Likewise, when the cumulative sum reaches the lower limit (at the 7th element), it won't decrease anymore. A for-loop version would be like this:
function y = cumsumlim(x, upper, lower)
y = zeros(size(x));
y(1) = x(1);
for i = 2 : numel(x)
y(i) = y(i-1) + x(i);
y(i) = min(y(i), upper);
y(i) = max(y(i), lower);
end
end
Do you have any ideas?
This is a somewhat hackish solution, but perhaps worth mentioning.
You can do the sum using a signed integer data type, and exploit the inherent limits of that data type. For this to work, the input needs to be converted to that integer type and multiplied by the appropiate factor, and an initial offset needs to be applied. The factor and offset are chosen as a function of lower and upper. After cumsum, the multiplication and offset are undone to obtain the desired result.
In your example, data type int8 suffices; and the required factor and offset are 85 and -128 respectively:
x = [1 1 1 1 -1 -1 -1 -1 -1 -1];
result = cumsum([-128 int8(x)*85]); %// integer sum, with factor and initial offset
result = (double(result(2:end))+128)/85; %// undo factor and offset
which gives
result =
1 2 3 3 2 1 0 0 0 0
I won't provide you with a magic vectorized way to do this, but I'll provide you with some data that probably will help you get on with your work.
Your cumsumlim function is very fast!
tic
for ii = 1:100
y = cumsumlim(x,3,0);
end
t = toc;
disp(['Length of vector: ' num2str(numel(x))])
disp(['Total time for one execution: ' num2str(t*10), ' ms.'])
Length of vector: 65000
Total time for one execution: 1.7965 ms.
I really doubt this is your bottleneck. Have you tried profiling the code?