So I am relatively new to MatLab and I was assigned the task to find the average of all of the elements in the first or last rows and first or last columns in an array. My function is below:
function [ myavg ] = avg_outer( array_in )
%UNTITLED2 Summary of this function goes here
% Detailed explanation goes here
[rowsin, colin]=size(array_in);
sum=0;
numelement=0;
currentpos=1;
currentrow=1;
j=1;
while currentpos>1 && currentpos<rowsin
sum=sum+array_in(currentrow,1)+array_in(currentrow,colin);
numelement=numelement+2;
currentrow=currentrow+1;
if currentrow==1
for j=1:1:colin
sum=sum+array_in(currentrow,j);
numelement=numelement+1;
end
elseif currentrow==rowsin
sum=sum+array_in(currentrow,j);
numelement=numelement+1;
end
end
myavg=sum/numelement;
end
When I run the function with a random array, I am not getting a result.
Any help or idea on where I went wrong?
Assuming I read the problem statement correctly, you can just create a mask that is true around the border, false in the middle, and take the mean of the masked version of A.
function [out_avg] = avg_outer(A)
mask = true(size(A));
mask(2:end-1,2:end-1) = false;
out_avg = mean(A(mask));
I couldn't really follow the logic in your posted code to debug it, sorry. Hopefully this answer shows you some of the advantages of vectorizing Matlab code.
The right way to do this is as per the answer from #kmac. But specifically related to your looping code, there are multiple issues.
currentpos starts at 1, which means that the while loop is never entered because currentpos > 1 is false. This is why you are getting NaN as the answer.
Even after fixing the above, you never increment currentpos so the while loop would never be exited (or more correctly would execute until an out of bounds error occurs).
Even after fixing the above, the first time into the while loop (in the 3rd line of the loop) you make currentrow = currentrow + 1;, which will be 2, means that the subsequent if statement is always false, and you will not be summing the first row of the matrix.
Even if you fix the above, the for loop adds all elements of the first row, but you've already accounted for the first and last elements of this row, so you're adding them into the sum twice.
Even if you fix the above, when currentrow == rowsin, i.e. the last row, you don't have a for loop to do the actual summation of the elements of the row. Noting that you don't want the first and last element because you've already added them in.
Related
I'm trying to change the number of items in array, over which a for loop is running, during the for loop, with the objective that this changes the number of loops. In a very simplified version, the code would look something like this:
var loopArray: [Int] = []
loopArray.append(1)
loopArray.append(2)
loopArray.append(3)
loopArray.append(4)
loopArray.append(5)
for x in 0..<Int(loopArray.count) {
print(x)
if x == 4 {
loopArray.append(6)
}
}
When running this code, 5 numbers are printed, and while the number 6 is added to the Array, the loopArray.count does not seem to update. How can I make the .count dynamic?
This is a very simplified example, in the project I'm working on, appending numbers to the array depends on conditions that may or may not be met.
I have looked for examples online, but have not been able to find any similar cases. Any help or guidance is much appreciated.
sfung3 gives the correct way to do what you want, but I think there needs to be a bit of explanation as to why your solution doesn't work
The line
for x in 0..<Int(loopArray.count)
only evaluates loopArray.count once, the first time it is hit. This is because of the way for works. Conceptually a for loop iterates through the elements of a sequence. The syntax is something like
for x in s
where
s is a sequence, give it type S
x is a let constant (you can also make it a var but that is not relevant to the current discussion) with type S.Element
So the bit after the in is a sequence - any sequence. There's nothing special about the use of ..< here, it's just a convenient way to construct a sequence of consecutive integers. In fact, it constructs a Range (btw, you don't need the cast to Int, Array.count is already an Int).
The range is only constructed when you first hit the loop and it's effectively a constant because Range is a value type.
If you don't want to use Joakim's answer, you could create your own reference type (class) that conforms to Sequence and whose elements are Int and update the upper bound each time through the loop, but that seems like a lot of work to avoid a while loop.
you can use a while loop instead of a for loop.
var i = 0
while i < loopArray.count {
print(i)
if i == 4 {
loopArray.append(6)
}
i += 1
}
which prints
0 1 2 3 4 5
I'm writing a program which will move a particle about a cube, either left,right,up,down, back or forward depending on the value randomly generator by the program. The particle is able to move with cube of dimensions LxLxL. I wish the program to stop when the particle has been to all possible sites and the number of jumps taken output.
Currently I am doing this using an array[i][j][k] and when the particle has been to a position, changing the value of the array at that corresponding point to 0. However, in my IF loop I have to type out every possible combination of i,j and k in order to say if they are all equal to 0 the program should end. Would there be a better way to do this?
Thanks,
Beth
Yes. I'm assuming the if in question is the one contained within the triple nested loop who's body sets finish=1;. The better way of doing this is to set a your flag before the loop, beginning with a true value then setting it to false and breaking if you encounter a value other then zero. Your if statement becomes much simpler, like this;
int finish =1; // start with a true value
//loops are untouched so still got the for i and for j above this
for(k = 0; k < 15; k++)
{
if (list[i][j][k] != 0)
{
finish = 0;
break;
}
}
// outside all the loops
return finish;
I think this is what you're asking for but if not please edit your question to clarify. I'm not sure if there is some technical name for this concept but the idea is to choose your initial truth value based on what's most efficient. Given you have a 15x15x15 array and a single non-zero value means false, it's much better to begin with true and break as soon as you encounter a value that makes your statement false. Trying to go in the other direction is far more complicated and far less efficient.
Maybe you can add your list[i][j][k] to a collection every time list[i][j][k]=0. Then at the end of your program, check for the collection's length. If it's of the right length, then terminate..
I have a loop that internally unrolls a sparse matrix vector multiplication. We calculate this using a diagonal approach for the upper right matrix with leads to a different length for each diagonal.
The unrolling then happens linewise, i.e. I calculate several diagonals at once, until the shortest diagonal reaches the end of the matrix. Then I want to calculate the remaining diagonals with another loop with decreased unrolling length.
This leads to the problem that the second loop needs to start where the first loop has ended. I'm now stumbling upon a construct like the following (very simplified):
do diag=1, nDiagonals-3, 4
! here be dragons
end do
do diag=diag, nDiagonals-2, 3
! here be smaller dragons
end do
In Fortran the do index has to be set in the control clause, in contrast to C where for(;n<m;==n) is a possible loop control clause. But is the construct above with do index=index, upperbound valid? Or are there better approaches for this kind of loop index handling?
I can't see anything syntactically wrong with your code, nor do I think you are doing anything dangerous if legal.
After the end of the first loop diag will have the value it would have if the loop continued for one more iteration. This behaviour is defined by the standard. Given the snippet
do diag = start, stop, stride
! do stuff
end do
at the end of the loop diag has value equal to (start + n*stride) where n is the smallest integer such that (start + n*stride)>stop
So, for a loop such as
do diag = 1,10,3
! do stuff
end do
! now diag == 13
and you can carry on using it to start the next loop as you outline.
What you can't do, in Fortran, is adjust the value of the do-variable inside the loop, the compiler behaves as if it establishes the loop limits at the first encounter with the do statement.
I have a function that gets questions from an array called quizQuestions, displays the choosed question, splice it from the array and pushes the question and correct answer to a new array to be used later in the results screen:
// The questions are stored in an array called "quizQuestions"
function makeQuestion()
var randNum:Number = Math.round(1 + (quizQuestions.length - 1) * Math.random());
mc_quiz.question.text = quizQuestions[randNum][0];
answer = quizQuestions[randNum][1];
quizQuestions.splice(randNum,1);
printQuestions.push(new Array(mc_quiz.question.text, answer));
}
It runs fine but time to time, a question is asked twice. You can continue with the test but the result doesn't show the info. In fact, it only shows the results for the questions answered before the duplication. I have checked visually and with a "duplicated elements finder" and there are no duplicated questions in the array.
Could the splice non being executed time to time? Can you see any "bug" in the function? Could it happen due to hardwer issue?
Thanks in advance.
Your random number generation is not only mathematically wrong (i.e. it won't generate truly random items), it will also from time to time generate a number that is beyond the array's bounds. To explain this: 1+(array.length-1) * Math.random() will generate any number greater or equal to 1 (this will also result in the first item of the array never to be returned, because arrays are 0-based), up to a fraction less than the actual length of the array. If you Math.round() the highest possible result, it will round up to the next highest integer, which is the full length again - and if you access array[array.length], an error is thrown, which is probably responsible for the weird behavior you are seeing.
Here's a possible solution:
Math.round() creates random number bias, anyway (see #OmerHassans link), so you're better off using int() or Math.floor(). Also, Math.random() is defined as 0 <= n < 1, so it will never return 1. Therefore, you can simplify your random index generator to int(Math.random()*array.length) => any integer smaller than the length of the array.
splice(), then, returns an array of the items that were removed, so you can pass its first item, instead of creating a new array.
function getRandomItem( arr:Array ):* {
var rand:int = Math.random()*arr.length;
return arr.splice( rand, 1 )[0];
}
function makeQuestion():void {
var q:Array = getRandomItem( quizQuestions );
mc_quiz.question.text = q[0];
answer=q[1];
printQuestions[printQuestions.length] = q;
}
FYI: It won't matter much in this context, but you get much faster performance by replacing array.push(item) with array[array.length]=item;.
I am familiar with iterative methods on paper, but MATLAB coding is relatively new to me and I cannot seem to find a way to code this.
In code language...
This is essentially what I have:
A = { [1;1] [2;1] [3;1] ... [33;1]
[1;2] [2;2] [3;2] ... [33;2]
... ... ... ... ....
[1;29] [2;29] [3;29] ... [33;29] }
... a 29x33 cell array of 2x1 column vectors, which I got from:
[X,Y] = meshgrid([1:33],[1:29])
A = squeeze(num2cell(permute(cat(3,X,Y),[3,1,2]),1))
[ Thanks to members of stackOverflow who helped me do this ]
I have a function that calls each of these column vectors and returns a single value. I want to institute a 2-D 5-point stencil method that evaluates a column vector and its 4 neighbors and finds the maximum value attained through the function out of those 5 column vectors.
i.e. if I was starting from the middle, the points evaluated would be :
1.
A{15,17}(1)
A{15,17}(2)
2.
A{14,17}(1)
A{14,17}(2)
3.
A{15,16}(1)
A{15,16}(2)
4.
A{16,17}(1)
A{16,17}(2)
5.
A{15,18}(1)
A{15,18}(2)
Out of these 5 points, the method would choose the one with the largest returned value from the function, move to that point, and rerun the method. This would continue on until a global maximum is reached. It's basically an iterative optimization method (albeit a primitive one). Note: I don't have access to the optimization toolbox.
Thanks a lot guys.
EDIT: sorry I didn't read the iterative part of your Q properly. Maybe someone else wants to use this as a template for a real answer, I'm too busy to do so now.
One solution using for loops (there might be a more elegant one):
overallmax=0;
for v=2:size(A,1)-1
for w=2:size(A,2)-1
% temp is the horizontal part of the "plus" stencil
temp=A((v-1):(v+1),w);
tmpmax=max(cat(1,temp{:}));
temp2=A(v,(w-1):(w+1));
% temp2 is the vertical part of the "plus" stencil
tmpmax2=max(cat(1,temp2{:}));
mxmx=max(tmpmax,tmpmax2);
if mxmx>overallmax
overallmax=mxmx;
end
end
end
But if you're just looking for max value, this is equivalent to:
maxoverall=max(cat(1,A{:}));