We are using MATLAB and we would like to generate a binary matrix, say x(i,j,k), where for every i, this condition is satisfied sum_{j} \ sum_{k} x_{ijk} = 1. Can anyone please help?
Generate random subscripts for j and k and use sub2ind to convert subscripts to indexes.
x = false(ni, nj, nk);
subi = 1:ni;
subj = randi(nj, 1, ni);
subk = randi(nk, 1, ni);
ind = sub2ind([ni, nj, nk], subi, subj, subk);
x(ind) = true;
To confirm the constraint you can use:
all(sum(sum(x, 3), 2) == 1)
Related
I wrote some code to display the prime numbers between 2 and a user-chosen number, following the pseudocode on wikipedia. I am not sure why this does not work, as I have the increments correct following Erastothenes' Sieve. Please help me.
I have tried changing the bounds but this did not work.
There are no errors, but it returns the wrong output. If I enter 10, it returns 2, 3, 4, 5, 6, 7, 8, 9, 10.
n=input("Enter an upper limit: ");
nums= 2:n;
p=2;
for i = p:sqrt(n)
for j = (i^2):i:sqrt(n)
nums(j) = 0;
end
end
for k = 1:n-1
if nums(k) ~= 0
disp(nums(k))
end
end
You can use the primes function in MATLAB for this
N = 10; % upper limit
p = primes(N); % List of all primes up to (and including) N
With one step less automation, you could use another in-built isprime
p = 1:N; % List of all numbers up to N
p( ~isprime( p ) ) = []; % Remove non-primes
Finally without using built-ins, we can address your code!
I assume you're referring to this pseudocode for the Sieve of Eratosthenes on Wikipedia.
Input: an integer n > 1.
Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
for i = 2, 3, 4, ..., not exceeding √n:
if A[i] is true:
for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n:
A[j] := false.
Output: all i such that A[i] is true.
I'll follow it step by step, pointing out differences to your code:
n = 10;
A = [false; true(n-1,1)]; % array of true Booleans, first element (1) is not prime
% But I've included a first element to make indexing easier.
% In your code, you were using index 'i' which was incorrect, as your array started at 2.
% Two options: (1) take my approach and pad the array
% (2) take your approach and using indices i-1 and j-1
for ii = 2:sqrt(n)
if A(ii) == true % YOU WERE MISSING THIS STEP!
for jj = ii^2:ii:n % YOU ONLY LOOPED UNTIL SQRT(n)!
A(jj) = false;
end
end
end
p = find(A);
disp(p)
This outputs the expected values.
Note that, at the end of the manual looping method, A is equivalent to isprime(1:n), mirroring my earlier suggestions.
There is two mistakes in your code:
The multiple should be check until n and not sqrt(n)
Since your nums vector start with 2 and not 1, if you want to
access the right value you need to use nums(j-1) = 0
So:
n=100
nums= 2:n;
p=2;
for i = p:sqrt(n)
for j = (i^2):i:n
nums(j-1) = 0;
end
end
for k = 1:n-1
if nums(k) ~= 0
disp(nums(k))
end
end
Noticed that you can skip one for loop using a modulo, it's probably not faster than the previous solution since this code create a logical index that include each prime that already been found.
n = 100
nums= 2:n;
for i = 2:sqrt(n)
nums(mod(nums,i)==0 & nums != i) = [];
end
nums.'
I simply delete the value in nums that can be divided by x but not x.
I've a matrix of order 100*5 . Now the objective is to fill each columns of the matrix with random integer within a specific range. Now the problem is for every column the range of the random number changes. For instance, for the first column, the range is 1 to 100 , for the second its -10 to 1 and so on till 5th column.
This is what I've tried:
b = [0,100;-10,1;0,1;-1,1;10,20]
range = b(:,2) - b(:,1)
offset = b(:,1)
A = round(rand(100,5) * range - offset)
which is from this question. However this generates an error,
Error using * Inner matrix dimensions must agree.
What's possibly causing this and how to resolve it ?
lets bsxfun this thing!
A = round(bsxfun(#minus,bsxfun(#times,rand(100,5) ,range'), offset'))
As an alternative solution, you could use repmat to complete what you already had:
b = [0, 100; -10, 1; 0, 1; -1, 1; 10, 20].';
rng = b(2, :) - b(1, :);
ofst = b(1, :);
A = round(rand(100,5) .* repmat(rng, 100, 1) + repmat(ofst, 100, 1));
You don't have to define rng or ofst, and this can be simply written as:
A = round(rand(10,5) .* repmat(diff(b), 10, 1) + repmat(b(1,:), 10, 1));
Out of curiousity I wrote this quick benchmark* to compare to Ander's bsxfun method. It appears that bsxfun has some initial overhead which means for 5 columns (test other cases yourself) and less than a few thousand rows, repmat is quicker. Above this, the creation of additional large arrays by repmat probably causes a slow down, and we see bsxfun is much quicker.
For future readers if this doesn't apply to you: with broadcasting introduced from R2016b you may find you can dodge using bsxfun and repmat entirely.
*benchmarking code. Tested on Windows 64-bit R2015b, your mileage may vary etc.
function benchie()
b = [0, 100; -10, 1; 0, 1; -1, 1; 10, 20].';
Tb = [];
Tr = [];
K = 20;
for k = 1:K
n = 2^k;
fb = #()bsxfunMethod(b,n);
fr = #()repmatMethod(b,n);
Tb(end+1) = timeit(fb);
Tr(end+1) = timeit(fr);
end
figure; plot(2.^(1:K), Tb, 2.^(1:K), Tr); legend('bsxfun', 'repmat');
end
function bsxfunMethod(b, n)
round(bsxfun(#minus,bsxfun(#times, rand(n,5), diff(b)), b(1,:)));
end
function repmatMethod(b, n)
round(rand(n,5) .* repmat(diff(b), n, 1) + repmat(b(1,:), n, 1));
end
You can use arrayfun, even though I don't see any harm in using loops and writing more readable code as in Steve's answer.
A = cell2mat(arrayfun(#(imin, imax) randi([imin, imax], 100, 1), b(:,1), b(:,2), 'uni', 0)')
You can do this with randi, passing in rows of b to its first argument:
b = [0,100;-10,1;0,1;-1,1;10,20];
A = zeros(100,5);
f=#(ii)randi(b(ii,:),100,1);
for ii = 1:size(A,2)
A(:,ii) = f(ii);
end
I suspect there is a way of doing this without looping through rows/columns, probably with bsxfun.
I've a matrix of order 100*10 . Now the objective is to fill each columns of the matrix with random integer within a specific range. Now the problem is for every column the range of the random number changes. For instance, for the first column, the range is [1,100] , for the second its -10 to 1 and so on till 10th column.
This is what I've tried:
b = [0,100;-10,1;0,1;-1,1;10,20]
a = []
for i=1 to 10
a[] = [(i:100)' randi(1,100)]
end
How do I generate a matrix of this form?
I don't have matlab installed right now, but i would do something like this.
m = 100;
n = size(b, 1);
range = b(:, 2) - b(:, 1);
offset = b(:, 1);
A = round(bsxfun(#minus, bsxfun(#times, rand(m, n), range), offset);
Without loop it would become:
M = 100;
N = size(b, 1);
A = zeros(m, n); % preallocate to avoid matrix expansion
for ii = 1:n
A(:, ii) = randi(b(ii,:), m, 1);
end
I have a vector n values and i want to split it into groups n groups of 3 adjacent values if it is considered to have a ring topology.
what i am trying to do is this:
vector = [some values];
groups = {};
for i = 1:size(vector)(2)
groups{i} = [vector(mod(i-1, size(vector)(2));
vector(i);
vector(mod(i+1, size(vector)(2))];
endfor
so if n = 10 and i = 1, groups should be [vector(10); vector(1); vector(2)]
it would be pretty straightforward in most programming languages to just use the mod operator, but i am having trouble working out how to do this using matlab as it doesnt use 0 as the initial index of a vector, so if i = 1, then mod(i-1) = 0 which is an illegal index value. Also i = n would be a problem as mod(n, n) = 0.
i have worked out a pretty hack-ish solution in:
vector = [some values];
groups = {};
for i = 1:size(vector)(2)
if i == 1
groups{i} = [vector(size(vector)(2));
vector(1);
vector(2)];
elseif i == size(vector)(2)
groups{i} = [vector(size(vector)(2)-1);
vector(size(vector)(2);
vector(1)];
else
groups{i} = [vector(i-1);
vector(i);
vector(i+1)];
endif
endfor
but it is pretty inelegant and i feel like there should be a better way to do it..
is there some operator that allows you to perform modular arithmetic over vector indexes?
Indeed, the 1-based indexing method of matlab can be quite irritating sometimes...
You can simply add 1 to your 0-based indices, though
n = numel(vector);
for ii = 1:n
idx0 = mod( ii + [-2, 1, 0], n ); % 0-based indices
group{ii} = vector( idx0 + 1 );
end
Now, good Matlab practices are about vectorization, here's one way to vectorize this for-loop
idx0 = mod( bsxfun( #plus, 1:n, [-2;1;0] ), n ); % all indices at once
group = mat2cell( vector( idx0+1 ).', ones(n,1), 3 );
You can lookup mat2cell in mathworks web site for more information. You can also read about bsxfun here at SO for more examples and information.
PS,
It is best not to use i as a variable name in Matlab.
I'm trying to take M images (say I) of d pixels each; convert them into a vector ImgVctr; and store them as arrays of an M x d matrix. How do i do it?
I tried the following
ImgVctr = I(:);
img_vctr_arr(i,:) = ImgVctr';
but it fails with the error :
Subscripted assignment dimension mismatch.
Any suggestions for a simple way to do this ?
All help will be appreciated !
Edit:
complete matlab code attached below:
img_vctr_arr = zeros (3, 38*28);
for i = 1:3
clearvars I;
fname = sprintf('a%d.png', i);
I = imread(fname);
I = rgb2gray (I);
ImgVctr = I(:);
img_vctr_arr(i,:) = ImgVctr';
figure (), imshow (I);
[x, y] = size(I);
fprintf ('%d, ', x);
fprintf ('%d\n', y);
end;
~ Thankyou
Pre-allocate the matrix like:
img_vctr_arr = zeros(M,d);
Then fill it:
img_vctr_arr(i,:) = I(:)'; % do not even need the '
Just ensure that numel(I) equals d.