フィルターのクリア

Why are the variables declared in this WHILE loop not getting modified in the FOR loop?

3 ビュー (過去 30 日間)
So, I'm helping a friend put together a function that essentially carries out a tour-de-wino style random walk. What it should do is run "walks" number of random walks, and in each walk, take "steps" number of steps of step size "step" until it hits the boundaries (the lines that form a square that starts at (0,0) and ends at (1,1). Unfortunately, it does not do this--in fact, it doesn't seem to modify the coordinates of the wino at all! Why is that?
the code is as follows (slightly reformatted to display properly in the post):
function [count] = random_walk( step, walks, steps )
% Only works for domains from 0 to 1, in steps of powers of 10
count = zeros(1/step, 4);
fail = 0;
j = 0;
while j < walks
locumx = 0.5;
locumy = 0.5;
directions = randi(4,1, steps);
for i = [1:steps+1]
if (i == (steps+1)) && ((locumx ~= 1) || (locumx ~= 0)) || ((locumy ~= 1) || (locumy ~= 0))
%j = j-1;
fail = fail +1;
break
elseif (i == (steps+1)) && ((locumx == 1) || (locumx == 0)) || ((locumy == 1) || (locumy == 0))
display(num2str(j+1), 'th walk completed successfully')
break
else
if directions(i) == 1
locumy = locumy + step;
if locumy == 1
count(locumx/step,1) = count(locumx/step,1) + 1;
break
end
elseif directions(i) == 2
locumy = locumy - step;
if locumy == 0
count(locumx/step,2) = count(locumx/step,2) + 1;
break
end
elseif directions(i) == 3
locumx = locumx + step;
if locumx == 1
count(locumy/step,3) = count(locumy/step,3) + 1;
break
end
elseif directions(i) == 4;
locumx = locumx - step;
if locumx == 0
count(locumy/step,4) = count(locumy/step,4) + 1;
break
end
else
display('drats')
end
end
end
j = j+1;
end
dumb = num2str(fail);
display(strcat('This function failed this many walks: ', dumb))
display(locumx, 'x')
display(locumy,'y')
end
  2 件のコメント
Image Analyst
Image Analyst 2015 年 4 月 4 日
Interesting program flow/output if directions(i) == 5.
Jan
Jan 2015 年 4 月 6 日
count = zeros(1/step, 4);
This works only if step|is smaller equal 1 and if |1/step is an integer without rounding.
for i = [1:steps+1]
This loop has 1 iteration only with i==1, because step must be smaller then 1.

サインインしてコメントする。

採用された回答

Stephen23
Stephen23 2015 年 4 月 4 日
編集済み: Stephen23 2015 年 4 月 6 日
Based on the comment given to my first answer: "take steps in 1 of 4 directions", it seems that the direction should be limited to orthogonal directions only:
mxS = 20;
wlk = 10;
stp = 2.5 - randi(4,mxS,wlk);
drn = abs(stp)>1;
poX = cumsum([zeros(1,wlk); drn.*sign(stp)]);
poY = cumsum([zeros(1,wlk);~drn.*sign(stp)]);
plot(poX,poY,'x-')
axis equal
Produces this figure:
And of course we can still find out which steps are inside the boundary:
>> box = 5;
>> idx = abs(poX)<box & abs(poY)<box
>> idx(~cumprod(+idx,1)) = false
and which walks reached the boundary:
>> any(~idx)
ans =
1 0 0 0 0 0 0 1 0 0
and in how many steps:
>> sum(idx,1)
ans =
15 21 21 21 21 21 21 12 21 21
Which tells us that only two of the ten walks reached the boundary, and the shortest walk was twelve steps. And of course we can easily print summaries, etc:
>> fprintf('%i paths did not reach the boundary\n',sum(any(~idx)))
2 paths did not reach the boundary
No loops: Faster, Neater, Easier!

その他の回答 (2 件)

Michael Haderlein
Michael Haderlein 2015 年 4 月 1 日
編集済み: Michael Haderlein 2015 年 4 月 1 日
Check line 11:
if (i == (steps+1)) && ((locumx ~= 1) || (locumx ~= 0)) || ((locumy ~= 1) || (locumy ~= 0))
You have 5 conditions here which group to 3 conditions:
(i == (steps+1))
&&
((locumx ~= 1) || (locumx ~= 0))
||
((locumy ~= 1) || (locumy ~= 0))
Of course, conditions 2 and 3 are always true (locumx cannot be both 1 and 0). So you have something like false && true | | true. Such statements are evaluated left to right, thus you have
false && true -> false;
false | | true -> true.
Therefore, it will always fail in the very first step. I guess you wanted to have the brackets a bit different.
Another remark, you always compare the positions locumx/locumy with zero and one. However, most likely the step will not exactly hit zero/one. Better compare with >=1 and <=0.
  3 件のコメント
Michael Haderlein
Michael Haderlein 2015 年 4 月 1 日
Well, I doubt it will ever hit 0 or 1. See my following example:
>> stepsize=1e-4;
>> pos=.5;
>> while pos(end)<=1
pos(end+1)=pos(end)+stepsize;
end
>> pos([end-2:end])
ans =
0.9999 1.0000 1.0001
>> 1-pos(end-1)
ans =
5.5067e-14
>> any(pos==1)
ans =
0
(Please don't take this as good programming style, I just want to keep the example simple as possible)
You see, I just add 1e-4 in a loop and store all positions. Also, the second-last value seems to be 1. However, it's not and none of the pos is exactly 1. In floating point arithmetics, you better don't compare with equality. If equality is necessary, use a domain (x>1-1e-4 && x<1+1e-4 for instance).
Keane Sanders
Keane Sanders 2015 年 4 月 4 日
Ah, I had forgotten about floating point error. I still can't use just "> 1"--I need it to stop at 1, so I guess I'll have to have something like "> 1 && < 1.01"
But until I can figure out why locumx et locumy aren't being modified and stored, we'll never know.

サインインしてコメントする。


Stephen23
Stephen23 2015 年 4 月 1 日
編集済み: Stephen23 2015 年 5 月 22 日
Rather than doing this in a loop, which will be very slow and inefficient use of MATLAB, you should learn how to write vectorized code, which will be much faster, neater, and less buggy than doing this in a loop.
For example this is the complete code needed to generate and plot some random walks with a constant step-size and a random direction:
mxS = 20;
wlk = 10;
ang = 2*pi*rand(mxS,wlk);
poX = cumsum([zeros(1,wlk);cos(ang)]);
poY = cumsum([zeros(1,wlk);sin(ang)]);
plot(poX,poY,'x-')
axis equal
Where each column of poX and poY are the x and y positions for one walk. The plot look like this:
This has a step-size of one and the walks all start at the origin: doing this makes detecting the bounding box-intersection much easier as the bounding box can then be a simple positive value allowing a basic logical conditional to detect that the path is still inside the bounding box:
>> box = 5;
>> idx = abs(poX)<box & abs(poY)<box;
>> idx(~cumprod(+idx,1)) = false;
where the values of idx indicate whether the step is inside the box, and again each column corresponds to one walk. We can then use any to check which walks reached the bounding box:
>> any(~idx,1)
ans =
1 1 0 0 0 0 1 1 0 1
This tell shows clearly that five of these ten random trials trials reached the box. You can count how many steps were required by summing these indices:
>> sum(idx,1)
ans =
12 11 21 21 21 21 15 20 21 18
The shortest path to the boundary was only eleven steps. Note how the values correspond to the logical values above.
No loops: Faster, Neater, Easier!
  4 件のコメント
Keane Sanders
Keane Sanders 2015 年 4 月 4 日
Not to sound ungrateful, but your code doesn't do what I need it to do, and at the moment, I'm not seeing a good way to vectorize the code I have to both A) take steps in 1 of 4 directions, and B) stop at the specified boundaries. It's a useful suggestion, but it doesn't seem to help me with the problem I have
Stephen23
Stephen23 2015 年 4 月 4 日
編集済み: Stephen23 2015 年 4 月 4 日
@Keane Sanders: as you only provided some non-functioning code and no specifications I had to make some assumptions about what you were actually trying to achieve. If you provided some clear specifications then it would be possible to show you a neat and robust way to code this problem. Saying that it "doesn't do what I need it to do" is fine, but in order to be able to give you the best advice we also need a description of what your aim is: you know what the code is supposed to do, but we don't (as we can't read minds).
Your comment indicates that you only wish to consider directions parallel to the axes, in this case you could consider my second answer...

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeGraphics Performance についてさらに検索

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by