In the code below, I want to ensure that there is an even chance of theImageRand being equal to theImage or theImage2, but I realized that between 1 and 100 more numbers are equal to 2 mod 1 than 2 mod 0. So theImage is being chosen a disproportionate amount of the time.
This was the simplest idea that came to me, but maybe there is a function that can do this easier? I was also thinking that I could find a number that fits what I'm looking for and put that into randi(n).
xRand = randi(100);
if mod(xRand,2) == 1
theImageRand = theImage;
elseif mod(xRand,2) == 0
theImageRand = theImage2;
end
Please let me know if I can explain more clearly. Thanks in advance.
tl;dr
Your code does exactly what you want, but it can be simplified by using randi(2) and removing the calculation of mod. However, it is worth to address some more points...
mod(xRand,2) to reduce 1-100 to 0/1
For xRand between 1 and 100, the result of mod(xRand,2) will be distributed equally on 0 and 1 as you can see by executing the following code:
xRand = 1:100;
xMod = mod(xRand,2);
cnt1 = sum(xMod == 1) % results in 50
cnt0 = sum(xMod == 0) % results in 50 as well
Basically, your code works as expected because randi chooses uniformly distributed numbers from 1 to 100. Subsequently, mod reduces them into a binary representation which is still uniformly distributed since the mapping is done for equal bins.
Simplification using randi(2)
The whole process of generating these uniformly distributed binary numbers can be simplified by just generating a binary set from the beginning. To achieve this, you can use randi(2) which directly gives you 1 or 2 as rayryeng pointed out in his comment to the question.
That would give you the following code:
xRand = randi(2);
if xRand == 1
theImageRand = theImage;
elseif xRand == 2
theImageRand = theImage2;
end
Is it correct?
Now we have a look at the interesting part of this question: Is the result really uniformly distributed? To check that, we can run the code N times and then analyze how many times each image has been chosen. Therefore, we assign 1 to the first image and 2 to the second image and store the result in res. After the for-loop, we take the sum of the elements where they are 1 or 2.
N = 1000000;
theImage = 1;
theImage2 = 2;
res = zeros(N,1);
for n = 1:N
xRand = randi(2);
if xRand == 1
theImageRand = theImage;
elseif xRand == 2
theImageRand = theImage2;
end
% xRand = randi(100);
% if mod(xRand,2) == 1
% theImageRand = theImage;
% elseif mod(xRand,2) == 0
% theImageRand = theImage2;
% end
res(n) = theImageRand;
end
cnt1 = sum(res==1);
cnt2 = sum(res==2);
percentage1 = cnt1/N*100 % approximately 50
percentage2 = cnt2/N*100 % approximately 50 as well
As we can see, percentage1 and percentage2 are approximately 50 which means the two images get both chosen around 50% of the time. It can be misleading to count the difference between cnt1 and cnt2 because this number can be high if N is large. However, if we observe this difference for many realization, the overall mean will be approximately zero. Furthermore, we can observe that your code using mod(randi(100),2) gives a distribution of 50% as well. It is just not as efficient and straight-forward as the solution with randi(2), which performs approximately 15% faster on my machine using R2016a.
Bottomline: I would recommend to use randi(2) as proposed above since it is more intuitive and more efficient as well. The observed difference is attributed to the random process and equalizes itself with more realizations. It is important to consider the percentage and not the absolute difference of the two images.
You can generate a number between zero and two and then check if xRand equals zero or one, which has an even chance of happening; however larger numbers make the chance of getting one over the other vary more.
(I've said two because when declaring random values, always have one extra.)
Related
Trying to calculate the variance of a European option using repeated trial (instead of 1 trial). I want to compare the variance using the standard randn function and the sobolset. I'm not quite sure how to draw repeated samples from the latter.
Generating from randn is easy:
num_steps = 100;
num_paths = 10;
z = rand(num_steps, mum_paths); % 100 paths, for 10 trials
Once I have this, I can loop through all the 10 columns of the z matrix, and can also repeat the experiment many times, as the randn function will provide a new random variable set everytime.
for exp_num = 1: 20
for col = 1: 10
price_vec = z(:, col);
end
end
I'm not quite sure how to do this with the sobolset. I understand I can create a matrix of dimensions to start with (say 100* 10). I can loop through as above through all the columns for the first experiment. However, when I try the next experiment (#2), the loop starts from the beginning and all the numbers are the same. Meaning I don't get any variation in my pricing. It seems I will need to find a way to randomize the column selection at the start of every experiment number. Is there a better way to do this??
data1 = sobolset(1000, 'Skip', 1000, 'Leap', 100)
data2 = net(test1, 10)
for exp_num = 1: 20
% how do I change the start of the column selection here, so that the next data3 is different from %the one in the previous exp_num?
for col = 1:10
data3(:, col) = data(2:, col)
% perform calculations
end
end
I hope this is making sense....
Thanks for the help!
Update: 8/21
I tried the following:
num_runs = 100
num_samples = 1000
for j = 1: num_runs
for i = 1 : num_samples
sobol_set = sobolset(num_samples,'Skip',j*50,'Leap',1e2);
sobol_set = net(sobol_set, 5);
sobol_seq = sobol_set(:, i)';
z_uncorr = norminv(sobol_seq, 0, 1)
% do pricing with z_uncorr through some function F
end
end
After generating 100 prices (through some function F, mentioned above), I find that the variance of the 100 prices is higher than that I get from the standard pseudo random numbers. This should not be the case. I think I'm still not sampling correctly from the sobolset. Any advice would be appreciated.
I'm implementing some sort of flood fill algorithm in Matlab that, given a starting pixel in a binary image, will output a binary image containing only the pixels that can be directly connected to it.
Basically, let
foo =
1 1 1
1 0 0
1 0 1
calling flood_fill(foo,1,1) would yield
1 1 1
1 0 0
1 0 0
Now, I'm pretty new to Matlab. I initially implemented flood_fill in a recursive style, but the pass-by-value behaviour of Matlab made working with large images very inefficient. To fix this, I reimplemented flood_fill like this
function [outImage] = flood_fill(inImage,start_x,start_y)
width = size(inImage,2);
height = size(inImage,1);
outImage = zeros(height,width);
points = [];
points = [points; [start_x start_y]];
while size(points,1)>0
point = points(1,:);
points = points(2:end,:);
y=point(2);
x=point(1);
outImage(y,x)=1;
if (y>1 && (outImage(y-1,x)==0) && (inImage(y-1,x)==1))
points = [points; [x y-1]];
end
if (y<height && (outImage(y+1,x)==0) && (inImage(y+1,x)==1))
points = [points; [x y+1]];
end
if (x>1 && (outImage(y,x-1)==0) && (inImage(y,x-1)==1))
points = [points; [x-1 y]];
end
if (x<width && (outImage(y,x+1)==0) && (inImage(y,x+1)==1))
points = [points; [x+1 y]];
end
end
end
Now, this works on small matrices/images but takes forever on large images as well. I suspect the reason why is the large amount of array resizes going on. Normally (in C++ for example), I'd use an unordered linked list and use it as a stack (remove from and insert at the head) to avoid costly array resizes.
Is there an equivalent to such a data structure in Matlab? If not, what's a Matlab idiom I could use? Perhaps a built-in function?
The function that you search for called bwselect:
foo=[1 1 1; 1 0 0; 1 0 1]
b=bwselect(foo,1, 1)
Note that you can define also fourth input n (like that: bwselect(foo,1,1,n)), that can have a value of 4 to specify 4-connected region, or 8 to specify 8-connected region.
Adiel answered your second question "Perhaps a built-in function?". As for the first part:
I'm not familiar with linked lists in MATLAB. However, you can speed up your function significantly by initializing the size of the points-matrix and don't change the size after that. Pre-initialization should always be done in MATLAB. If the function won't work with matrices of fixed size, I would always recommend you to try to rewrite the function.
For your specific case:
function [outImage] = flood_fill(inImage,start_x,start_y)
width = size(inImage,2);
height = size(inImage,1);
outImage = zeros(height,width);
points = zeros(nnz(inImage),2); % I take it this is the maximum size
points(1,:) = [start_x start_y];
k = 1; % Increment row number in points
while size(points,1)>0
k = k + 1;
y=points(k, 2);
x=points(k, 1);
I understand it you have programming skills in general, so I believe you should be able to adapt the remaining code to the new format. (I don't have time to go through it and rewrite it). I'm quite sure it will run much faster!
So I have a list of 190 numbers ranging from 1:19 (each number is repeated 10 times) that I need to sample 10 at a time. Within each sample of 10, I don't want the numbers to repeat, I tried incorporating a while loop, but computation time was way too long. So far I'm at the point where I can generate the numbers and see if there are repetitions within each subset. Any ideas?
N=[];
for i=1:10
N=[N randperm(19)];
end
B=[];
for j=1:10
if length(unique(N(j*10-9:j*10)))<10
B=[B 1];
end
end
sum(B)
Below is an updated version of the code. this might be a little more clear in showing what I want. (19 targets taken 10 at a time without repetition until all 19 targets have been repeated 10 times)
nTargs = 19;
pairs = nchoosek(1:nTargs, 10);
nPairs = size(pairs, 1);
order = randperm(nPairs);
values=randsample(order,19);
targs=pairs(values,:);
Alltargs=false;
while ~Alltargs
targs=pairs(randsample(order,19),:);
B=[];
for i=1:19
G=length(find(targs==i))==10;
B=[B G];
end
if sum(B)==19
Alltargs=true;
end
end
Here are some very simple steps to do this, basically you just shuffle the vector once, and then you grab the last 10 unique values:
v = repmat(1:19,1,10);
v = v(randperm(numel(v)));
[a idx]=unique(v);
result = unique(v);
v(idx)=[];
The algorithm should be fairly efficient, if you want to do the next 10, just run the last part again and combine the results into a totalResult
You want to sample the numbers 1:19 randomly in blocks of 10 without repetitions. The Matlab function 'randsample' has an optional 'replacement' argument which you can set to 'false' if you do not want repetitions. For example:
N = [];
replacement = false;
for i = 1:19
N = [N randsample(19,10,replacement)];
end
This generates a 19 x 10 matrix of random integers in the range [1,..,19] without repetitions within each column.
Edit: Here is a solution that addresses the requirement that each of the integers [1,..,19] occurs exactly 10 times, in addition to no repetition within each column / sample:
nRange = 19; nRep = 10;
valueRep = true; % true while there are repetitions
nLoops = 0; % count the number of iterations
while valueRep
l = zeros(1,nRep);
v = [];
for m = 1:nRep
v = [v, randperm(nRange,nRange)];
end
m1 = reshape(v,nRep,nRange);
for n = 1:nRep
l(n) = length(unique(m1(:,n)));
end
if all(l == nRep)
valueRep = false;
end
nLoops = nLoops + 1;
end
result = m1;
For the parameters in the question it takes about 300 iterations to find a result.
I think you should approach this constructively.
It's easy to initially find a 19 groups that fulfill your conditions just by rearranging the series 1:19: series1 = repmat(1:19,1,10); and rearranged= reshape(series1,10,19)
then shuffle the values
I would select two random columns copy them and switch the values at two random positions
then make a test if it fulfills your condition - like: test = #(x) numel(unique(x))==10 - if yes replace your columns
just keep shuffling till your time runs out or you are happy
of course you might come up with more efficient shuffling or testing
I was given another solution through the MATLAB forum that works pretty well (Credit to Niklas Nylen over on the MATLAB forum). Computation time is pretty low too. It basically shuffles the numbers until there are no repetitions within every 10 values. Thanks all for your help.
y = repmat(1:19,1,10);
% Run enough iterations to get the output random enough, I selected 100000
for ii = 1:100000
% Select random index
index = randi(length(y)-1);
% Check if it is allowed to switch places
if y(index)~=y(min(index+10, length(y))) && y(index+1)~=y(max(1,index-9))
% Make the switch
yTmp = y(index);
y(index)=y(index+1);
y(index+1)=yTmp;
end
end
I have written the following piece of code:
M = [3 0 0; 0 2 0; 0 0 0.5] % mass matrix
i_vals = 1:1000:60e06; % values of k_12 from 1 to 600 million in steps of 1000
modes = zeros(3, length(i_vals));
for n=1:length(i_vals)
i = i_vals(n) % i is the value of k_12
K = [i+8e06 -i -2e06; -i i+2e06 -1e06; -2e06 -1e06 5e06]; % stiffness matrix
[V,L]=eig(K,M);
V(:,I)=V;
A = V(:, [1])
transpose(A)
modes(:, n) = A
end
loglog(i_vals, modes')
But the loop seems to go forever and I do now know what is wrong with it. The idea was to get the first column from matrix V, and see what happens to the 3 elements in this column when value of k_12 is changed.
I don't know how you make this run forever. To me it looks as if it won't run at all. This won't answer your question, but will hopefully help you on the way =)
What do you want to do with this line? V(:,I)=V; What is I? Was it supposed to be i? Btw, using i and j as variables in MATLAB is not recommended (however, if you don't use complex numbers in your field, you shouldn't care too much).
You have a loop that goes 60,000 times, with calculations of eigenvalues etc. That is bound to take time (although not forever, as you state it does). You should get the answer eventually (if only the rest of the code worked). The resolution of your plot would be more than accurate enough with 10,000 or even 100,000 steps at a time.
This part:
A = V(:, [1])
transpose(A)
modes(:, n) = A
could simply be written as:
modes(:,n) = V(:,1)';
assuming you want the transposed of A. transpose(A) does nothing in this context actually. You would have to do A = transpose(A) (or rather A = A') for it to work.
There are all kinds of problems with your code - some of which may contribute to your issue.
You are computing values of i on a linear scale, but ultimately will be plotting on a log scale. You are doing a huge amount of work towards the end, when there is nothing visible in the graph for your effort. Much better to use a log scale for i_vals:
i_vals = logspace(0, 7.778, 200); % to get 200 log spaced values from
% 1 to approx 60E6`
You are using a variable I that has not been defined (in the code snippet you provide). Depending on its size, you may find that V is growing...
You are using a variable name i - while that is legal, it overwrites a built in (sqrt(-1)) which I personally find troublesome.
Your transpose(A); line doesn't do anything (You would have to do A = transpose(A);).
You don't have ; after several lines - this is going to make Matlab want to print to the console. This will take a huge amount of resource. Suppress the output with ; after every statement.
EDIT the following program runs quickly:
M = [3 0 0.0;
0 2 0.0;
0 0 0.5]; % mass matrix
i_vals = logspace(0, 7.78, 200); % values of k_12 from 1 to 600 million in steps of 1000
modes = zeros(3, length(i_vals));
for n=1:length(i_vals)
i = i_vals(n); % i is the value of k_12
K = [i+8e06 -i -2e06; -i i+2e06 -1e06; -2e06 -1e06 5e06]; % stiffness matrix
[V,L]=eig(K,M);
modes(:, n) = V(:,1);
end
loglog(i_vals, modes')
Resulting graph:
If I didn't break anything (hard to know what you were doing with I), maybe this can be helpful.
I have some massive matrix computation to do in MATLAB. It's nothing complicated (see below). I'm having issues with making computation in MATLAB efficient. What I have below works but the time it takes simply isn't feasible because of the computation time.
for i = 1 : 100
for j = 1 : 20000
element = matrix{i}(j,1);
if element <= bigNum && element >= smallNum
count = count + 1;
end
end
end
Is there a way of making this faster? MATLAB is meant to be good at these problems so I would imagine so?
Thank you :).
count = 0
for i = 1:100
count = count + sum(matrix{i}(:,1) <= bigNum & matrix{i}(:,1) >= smallNum);
end
If your matrix is a matrix, then this will do:
count = sum(matrix(:) >= smallNum & matrix(:) <= bigNum);
If your matrix is really huge, use anyExceed. You can profile (check the running time) of both functions on matrix and decide.