Assigning values of an array in a loop - arrays

In my code:
DO i=1,numJog,1
IF(val(i) .EQV. .TRUE.)THEN
DO j=1,contVenc,1
result(j) = i
END DO
END IF
END DO
Where val is a logical array, and result is a integer array.
For example, if val is:
F
T
F
T
Then, i=2 and i=4.
But the result array just write 4 twice. For example:
DO i=1,contVenc,1
WRITE(*,*) result(i)
END DO
The result is:
4
4
Instead of
2
4
If I make some changes in my code like:
DO i=1,numJog,1
IF(val(i) .EQV. .TRUE.)THEN
WRITE(*,*) i
END IF
END DO
The result is:
2
4
As I wanted.
Conclusion, I think this second loop is causing this problem.

Yes, your second loop is at fault here. You haven't said what contVenc is, but it crucially doesn't change at any point in the fragment you have there. That just means that the same elements of result are being assigned to whenever you have a .TRUE. in val.
In your case they are both set to 2 for the first .TRUE. and are then both set to 4 for the second.
You are more likely to mean something like (with extra tidying):
j = 0
DO i=1,numJog
IF (val(i)) THEN
j = j+1 ! Test this as a bound
result(j) = i
END IF
END DO
But then, I'd just use PACK. Your intended loop has the same effect as
result(1:COUNT(val(1:numJog))) = PACK([(i,i=1,numJog)], val(1:numJog))
Again hoping that result is large enough.
That said, if numJog is just the size of the array val (that is, you aren't just doing this on a sub-array) then, as High Performance Mark comments,
result(1:COUNT(val)) = PACK([(i,i=1,SIZE(val))], val)
avoids tracking this size separately.
Finally, with result an allocatable (Fortran 2003) array you needn't even (but still can) worry about counting the number of wanted indices and that the array is sufficiently large:
result = PACK([(i,i=1,SIZE(val))], val)

Related

Filling a row and columns of a ndarray with a loop

I'm starting with Python and I have a basic question with "for" loop
I have two array which contains a values of a same variables:
A = data_lac[:,0]
In the first array, I have values of area and in the second on, values of mean depth.
I would like to find a way to automatize my calculation with different value of a parameter. The equation is the following one:
g= (np.sqrt(A/pi))/n
Here I can calculte my "g" for each row. Now I want to have a loop with differents values of "n". I did this:
i=0
while i <= len(A)-1:
for n in range(2,6):
g[i] = (np.sqrt(A[i]/pi))/n
i += 1
break
In this case, I just have one column with the calculation for n = 2 but not the following one. I tried to add a second dimension to my array but I have an error message saying that I have too many indices for array.
In other, I would like this array:
g[len(A),5]
g has 5 columns each one calculating with a different "n"
Any tips would be very helpful,
Thanks
Update of the code:
data_lac=np.zeros((106,7))
data_lac[:,0:2]=np.loadtxt("/home...", delimiter=';', skiprows=1, usecols=(0,1))
data_lac[:,1]=data_lac[:,1]*0.001
#Initialisation
A = data_lac[:,0]
#example for A with 4 elements
A=[2.1, 32.0, 4.6, 25]
g = np.zeros((len(A),))
I believe you share the indexes within both loops. You were increasing the i (index for the upper while loop) inside the inner for loop (which index with n).
I guess you have A (1 dim array) and you want to produce G (2 dim array) with size of (Len(A, 5))
I am not sure I'm fully understand your require output but I believe you want something like:
i=0
while i <= len(A)-1:
for n in range(2,6):
g[i][n-2] = (np.sqrt(A[i]/pi))/n # n-2 is to get first index as 0 and last as 4
i += 1 # notice the increace of the i is for the upper while loop
break
Important - remember that in python indentation means a lot -> so make sure the i +=1 is under the while scope and not indent to be inside the for loop
Notice - G definition should be as:
g = np.zeros((len(A),4), dtype=float)
The way you define it (without the 4) cause it to be 1 dim array and not 2-dim

Adding odd numbers in an array not providing the correct output

one of my ruby programs that detects odd numbers in an array and adds them together does not provide the correct output. Given that I am learning ruby and this is a logic mistake, I can't easily deduct where I make a mistake.
Here is the Code:
def odd_sum(numbers)
index = 0
result = 0
while index < numbers.length
if (numbers[index] % 2 != 0)
result += 1
end
index +=1
return result
end
end
puts odd_sum([1,2,4,5,7,9]) currently my output is 1 should be 22
puts odd_sum([0,6,4,4]) currently output 0
puts odd_sum([1,2,1]) currently output 1 should be 2
Question: Why is my output wrong? Any way to make this cleaner or better?
I'm running all this in a program called oddball.rb on cloud9.
return result will cause the code to exit right then and there... it will only ever add up the first number, then exit the whole method forever... it will never look at the other elements of the array.
Having now indented your code properly you can see that this line is inside the while loop...
probably you want that to be outside the while loop... it is much easier to see this kind of bug when you properly indent your code. You should always indent your code... it seems unimportant until you come across a bug like this... it's always important. it's a good habit to start now. ;)
have a look at your if-statement: result+=1, don't add 1 but add the the number you are currently testing: result += numbers[index]
SiS
def odd_sum(numbers)
index = 0
result = 0
while index < numbers.length
if (numbers[index] % 2 != 0)
result += 1
end
index +=1
return result
end
end
puts odd_sum([1,2,4,5,7,9]) currently my output is 1 should be 22
puts odd_sum([0,6,4,4]) currently output 0
puts odd_sum([1,2,1]) currently output 1 should be 2
On the line result += 1, you are adding 1 each time there is an odd number, so it's not a sum, but rather a count.
On the line return result, the program will immediately end when it hits the return. So, since the first number in the first array is odd, the program increments result by 1, and then returned result.
What you want to do is result += numbers[index], and return the result at the end of the while loop.
In Ruby, there's often a better way to do things, while loops are meant for when you don't know how many times you are looping. In this case, you know exactly how many times, so I would suggest using an iterator.
def odd_sum(numbers)
result = 0
numbers.each do |num|
result += num if num.odd?
end
end
Or even better
def odd_sum(numbers)
numbers.select(&:odd?).reduce(&:+)
end

How to assign values to an array except certain elements in fortran?

I want to assign values to an array with a certain rule, except the 5th element due to divide-by-zero problem. The program is like follows:
program main
implicit none
real(8) :: a(10)
integer :: i
a(5) = 0d0
do i = 1, 10
if (i /= 5) then
a(i) = 1.0d0 / dble(i-5)
end if
write(*,*) a(i)
end do
stop
end program main
Is there a more smart/efficient way to do the same thing?
Thank you very much!
If you want to save the amount of source code:
program main
implicit none
integer, parameter :: dbl = kind(1.d0)
real(dbl) :: a(10)
integer :: i
do i = 1, 10
a(i) = 1._dbl / (i-5)
end do
a(5) = 0
! I expect you want to do something more than just this with the array
do i = 1, 10
write(*,*) a(i)
end do
end program
As francescalus points out this may cause your program to crash if floating point exceptions are enabled. Anyway, also notice other things I used, which can shorten your code. = 0 instead of = 0.d0, avoiding the dbl() (use real(x,dbl) instead if necessary) and so on.
If this code is repeated very often, you could also save some CPU time by avoiding the branch. In a typical initialization code it is irrelevant.

How does MATLAB assign values to a variable and print to file in a parfor loop

I have a parfor loop that loops over i = 1:250, gets three values from an array according to the index. Then a calculation is being made within the parfor loop using those 3 values. I then store the results in the variables theta1, theta2, and theta3, and immediately print them to a file. I am parallelizing because the calculations take too much time, and for each index, they can be done independently. I guess MATLAB wouldn't necessarily divide the work by having workers compute independent iterations, but it could divide a given iteration between workers. In either case, would the value assignment to the variables or the printing to the file be affected by the order in which the operations are done? Is it possible that the results be printed in a different order like:
theta1 from i = 1
theta1 from i = 2
theta2 from i = 2
theta3 from i = 2
theta2 from i = 1
...
instead of the desired order, which is:
theta1 from i = 1
theta2 from i = 1
theta3 from i = 1
theta1 from i = 2
theta2 from i = 2
...
Would it be healthier to collect all the results in a cell array and then print them at the very end?
Having the outer parfor loop means that the values of i the function looks at is not guaranteed to be 1, 2, 3, etc. However, the theta1, theta2, theta3 variables INSIDE the parfor loop will be calculated in their order inside their inner parfor loop. So the only thing you are guaranteed is that for a given value of i, theta1 will be done first, then theta2, then theta3. The workers themselves (the i loops) are interleaved, so it is completely possible that you get the result
theta1 from i = 1
theta1 from i = 2
theta2 from i = 2
theta3 from i = 2
theta2 from i = 1
...
In any case, printing to a file inside the parfor loop can cause problems, since it could be that two workers are trying to write to the file at the same time. This would mean that you'd "lose" results from some of your computations. The MATLAB way (if there is such a thing...) makes it better to save all the results from your parfor loops in an array or cell array (regular arrays are better for memory reasons, since not the entire cell array needs to be shared across all parfor loops; but cell arrays are easier to wrap your head around for prototyping) and print it to a file at the end.

Operating elementwise on an array

I'm trying to check if my arrays are returning nonsense by accessing out of bounds elements, in fortran. And I want to check these values are less than one, and if they are, change them to one.
This is the piece of my code causing issues:
lastNeighLabel=(/clusterLabel(jj-1,kk,ll), clusterLabel(jj,kk-1,ll), clusterLabel(jj,kk,ll-1)/)
LastNeighLabel contains the cluster label (between 1 and n, where n isthe total number of unique seperate clusters found) for the last neighbour in the x,y,z direction respectively.
When jj or kk or ll are 1, they try and access the 0th element in the array, and as FORTRAN counts from 1 in arrays, it tries to destroy the universe. I'm currently in a tangled mess of about 8 if/elseif statements trying to code for every eventuality. But I was hoping there was a way of operating on each element. So basically I'd like to say where((/jj-1,kk-1,ll-1/).lt.1) do clusterLabel(jj-1,kk,ll)=0 etc depending on which element is causing the problem.
But I can't think of a way to do that because where will only manipulate the variables passed to it, not a different array at the same index. Or am I wrong?
Will gladly edit if this doesn't make sense.
It is not obligatory that Fortran accesses arrays starting from one. Any starting value is allowed. If it more convenient to you to have a zero indexed array, declare the array as:
real, dimension (0:N-1, 0:M-1) :: array
Or
real, dimension (0:N, 0:M) :: array
and have the 0 indices be extra to catch special cases.
This might be another solution to your problem, since zero index values would be legal.
Another possible way to approach this, is to create an extended cluster label array (with index bounds starting at 0), which is equal to the cluster label array with a layer of zeroes tacked on the outside. You can then let your loop run safely over all values of jj, kk, and ll. It depends on the size of the array if this is a feasible solution.
integer :: extended_cluster_label(0:size(cluster_label,1), &
0:size(cluster_label,2), &
0:size(cluster_label,3) &
)
extended_cluster_label(0,:,:) = 0
extended_cluster_label(:,0,:) = 0
extended_cluster_label(:,:,0) = 0
extended_cluster_label(1:, 1:, 1:) = cluster_label
Maybe you could use a function?
real function f(A,i,j,k)
real :: A(:,:,:)
integer :: i,j,k
if (i==0.or.j==0.or.k==0) then
f=0
else
f=A(i,j,k)
endif
end function f
and then use f(clusterLabel,jj-1,kk,ll) etc.

Resources