Different shape for array assignment in Fortran - fortran

This is my code:
Program Arrays
Implicit none
Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,3)::V_cvo
Complex,dimension(7,3)::V_cvo_temp
Do concurrent(i=0:7,j=1:3)
V_cvo(i,j)=cmplx(i+j,2*i-j)
End Do
V_cvo_temp=V_cvo(1:,:)
V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
Stop
End Program Arrays
After compiling I got a this message:
Error: Different shape for array assignment on dimension 1 (2 and 1)|
What is wrong here? If I want to find location of minimal element in some array in specific sector of that array how it is possible?
This could be one of the possible solution for the problem:
Program Arrays
Implicit none
Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,2)::V_cvo
Logical,dimension(0:7,2) :: lmask = .FALSE.
forall(i=2:5,j=1:2)lmask(i,j) = .TRUE.
Do concurrent(i=0:7,j=1:2)
V_cvo(i,j)=cmplx(i+j,2*i-j)
End Do
V_Max = Maxloc(abs(V_cvo),mask=lmask)-(/1,0/)
Open(1,File='Output.txt',Status='Unknown')
Write(1,'(2x,i0,2x,i0)') V_max
Write(1,*)
Do concurrent(i=2:5,j=1:2)
Write(1,'(1x,i0,1x,i0,2x,f7.4)')i,j,abs(V_cvo(i,j))
End Do
Close(1)
Stop
End Program Arrays
Output file is:
5 1
2 1 4.2426
3 1 6.4031
4 1 8.6023
5 1 10.8167
2 2 4.4721
3 2 6.4031
4 2 8.4853
5 2 10.6301
Opinions about this?

This expression
minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
returns a rank-1 array with 1 element. The lhs of the assignments is a rank-1 array with 2 elements. Fortran won't assign incompatible arrays -- hence the compiler error message.
(#gdlmx's answer is subtly wrong in its diagnosis, if the expression returned a scalar Fortran would happily broadcast its value to every element of an array.)
If the expression did return a scalar it would still not return the location of the minimum element in that section of V_cvo. The sub-expression
(/((V_cvo_temp(i,j),j=1,3),i=2,5)/)
produces a rank-1 array containing the specified elements of V_cvo_temp, it essentially flattens the array into a vector and loses their locations along the way. This is why the first expression returns a rank-1 array with 1 element - it's the location of an element in a rank-1 array.
The problem with this solution
V_Min=minloc(abs(V_cvo(2:5,1:3)))
is that the expression abs(V_cvo(2:5,1:3)) will return a (temporary) array indexed, as Fortran arrays are by default, from 1 on each rank. When I try the code it returns the location (1,1) which appears to be outside the section considered. That's the location of the minimum element of the temporary array.
The problem with the 'clever' solutions I've tried has been that abs(V_cvo(2:5,1:3)) always returns, even if hidden from view, a temporary array indexed from 1 on each rank. Any application of minloc or similar functions uses those indices, not the indices that v_cvo uses. The best solution might be to make an explicit temporary array (suitably declared) like this:
allocate(abstemp(LBOUND(v_cvo,1):UBOUND(v_cvo,1),LBOUND(v_cvo,2):UBOUND(v_cvo,2)))
then
v_min = minloc(abstemp(2:5,1:3))
and
deallocate(abstemp)

It seems that the right side of
V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
returns a scalar instead of a vector of 2 components. What you need is array slicing: V_cvo_temp(1:3,2:5)
V_Min=minloc(abs(V_cvo_temp(2:5,1:3)))
or simpler
V_Min=minloc(abs(V_cvo(2:5,1:3))) ! without temp array
Also you don't need the stop at the end.
Edit1:
minloc returns the index relative to (1,1). To understand this behavior, try this example:
Program Hello
Implicit none
Integer,dimension(2)::V_Min
Complex,dimension(0:7,3)::V_cvo
V_cvo = cmplx(10,10)
V_cvo(3,2) = cmplx(0,0) ! the minimum index = [3,2]
V_Min=minloc(abs(V_cvo))
print *, 'minloc for whole array: ', V_Min
V_Min=minloc(abs(V_cvo(3:,2:)))
print *, 'minloc for sub-array: ', V_Min
End Program Hello
It outputs:
minloc for whole array: 4 2 ! base index=[-1,0]
minloc for sub-array: 1 1 ! base index=[2,2]
So if passing a sub-array to minloc, you need to add your base index to get the 'correct' answer.

This solution also works fine (best maybe):
forall(i=1:7,j=1:3) V_cvo_temp(i,j)=abs(V_cvo(i,j))
V_Min = MINLOC(V_cvo_temp(m:n,:))+(/m-1,0/)
Code are correct for every m and n if they are in interval 1:7 for this case or in some other interval.

Related

Reshaping Fortran arrays

I have a huge m by 1 array (m is very large) called X which is a result of Fortran matmul operation. My problem is to store this apparently 2D array into an 1D array Y of size m.
I tried with Y = reshape(X, [[2]]) and this result some elements NaN. Can anyone point me to Fortran commands to do it quickly. The elements of X may be zero or non-zero.
The second argument of reshape (or the one with keyword shape=) is the shape of the function's result. In your call, you have requested shape [2].
An array with shape [2] is a rank-1 array with two elements. You want a rank-1 array with m elements:
Y = RESHAPE(X, [m])
Now, in this case there's no need to use reshape:
Y = X(:,1)
where the right-hand side is the rank-1 array section of X.
When you have Y=reshape(X,[2]), if Y is not allocatable and not of size 2 then you have a problem which may indeed result in your compiler deciding---as it is quite entitled to do---to give you a few NaNs.
Note also that you may not need to reshape your array, depending on how you intend to later use it.

What exactly are scalar values in Fortran, and how can I convert from and to them

Some context. I have this piece of code :
function areeq(array1,array2) result(eq)
real :: array1(1:100,1:100), array2(1:100,1:100)
logical :: eq
integer :: x,y,f
do x=1,100
do y = 1,100
print *,array1(x:x,y:y)
print *,array2(x:x,y:y)
if(.not.(array1(x:x,y:y) == array2(x:x,y:y))) then
eq = .false.
return
end if
read *,f
end do
end do
eq = .true.
return
end function
However, when I try to run it, it throws this error message:
if(.not.(array1(x:x,y:y) == array2(x:x,y:y))) then
1
Error: IF clause at (1) requires a scalar LOGICAL expression
This is the second time that I've encountered trouble with something needing to be Scalar, and though I managed to hack together a makeshift work around for the last time, I really ought to, and need to, be able to handle them properly.
So, TL;DR: What is wrong with this piece of code, and what should I do in situations like this more generally?
Given
integer n
real x(5)
then, given appropriate definition of n
x(n)
is an array element of x, and
x(n:n)
is an array section of x.
The array element is a scalar whereas the array section is itself an array of size 1.
As Steve Lionel says, in the case of the question,
array1(x:x,y:y) == array2(x:x,y:y)
is an array-valued expression (albeit again of size 1) which can be reduced to a scalar expression with ALL. However
array1(x,y) == array2(x,y)
is a scalar expression, with both operands scalar array elements.
In the reference x(n) we have an array element for scalar n. With n an array we would instead have an array being a vector subscript of x.
What is wrong is, as the compiler complains, your expression has an array result, with one element for each comparison. What you want is to wrap the expression in ALL(). For example:
if(.not.(all(array1(x:x,y:y) == array2(x:x,y:y)))) then

Translating the following C++ code into Nim

I'm trying to learn Nim by converting different pieces of code, and I've stumbled upon something which I've never seen before.
#include<bits/stdc++.h>
...
for(int t=q&1?u+x:u+x>>1;t>1;)t/=p[++cnt]=sieve[t];
...
sort(p+1,p+cnt+1);
I understand what the ternary operator is and how it works, what I don't quite get is what's going on with the variables "t" and "cnt" (both integers) and the array "p" (an array of integers). How does using an increment as the index of "p" work?
Then there's the sort function, in which I completely gave up because I couldn't find any documentation on what it does (the fact that it's taking an integer added to an array obviously doesn't help).
Lets first start of by making the code a little more readable. A little bit of whitespace never hurt anybody.
for(int t = (q & 1? u + x: u + x >> 1); t > 1;)
{
t /= p[++cnt] = sieve[t];
}
what's going on with the variables "t" and "cnt" (both integers) and the array "p" (an array of integers)
So t is being set to either u + x or u + x >> 1 depending on what q & 1 is. Then inside the loop we are dividing t by whatever the value of sieve at the index of t is. We are also assign that value to the p array at the position of ++cnt. ++cnt is using the pre increment operator to increase the value of cnt by 1 and then using that value for the index of p.
Then there's the sort function, in which I completely gave up because I couldn't find any documentation on what it does
For this I am assuming they are using the std::sort() function. When dealing with arrays the name of the array is treated as a pointer to the first element of the array. So when we see sort(p+1,p+cnt+1); you can translate it to sort(one from the begining of the array, cnt + 1 elements from the begining of the array);. So this is going to sort all of the elements in the array from one from the begining of the array to one less than cnt + 1 elements from the begining of the array.
Are you trying to learn Nim as you said, or trying to learn C? Both things you asked about are pretty basic c:
++cnt has the side effect (cnt=cnt+1) combined with the value that cnt ends up with. That value is used as the index. The side effect is a side effect.
p+1 and p+cnt are each pointers. The name of an array is treated as a constant pointer to the first element of that array in most uses within C. A pointer plus an integer is another pointer, pointing that number of elements past the original.

Creating an array from an array

I want to resize an array. For example if I have an array with 10 elements, I want to exclude the first 5 elements, define another 5 elements from them, and assign the new ten to new array. Maybe I have the idea but I have a problem to define the new vector. Please find below what's in my mind.
Program test
Implicit None
Integer :: i,j,k,m,n
Real,Dimension(1:20) ::A
Real,Dimension(1:15) ::B
Do j=1,20
A(j)=j+3
End do
Do i=1,5
Do m=1,3
! here, i want to define new array with 15 elements
( A(i)+m*0.5*(A(i+1)-A(i)) )
End do
End Do
End Program test
The most straightforward extension of your code taking into account the information from the comment is the following, but your intention is really not that clear. It uses the first 6 elements of A, not 5.
Do i=1,5
Do m=1,3
B(3*(i-1)+m) = A(i)+m*0.5*(A(i+1)-A(i))
End do
End Do
This code will make these assignments:
B(1) <- A(1)+1*0.5*(A(2)-A(1))
B(2) <- A(1)+2*0.5*(A(2)-A(1))
...
B(4) <- A(2)+1*0.5*(A(3)-A(2))
Check if you really intended this order, it could also be 5*(m-1)+i.

Fortran - Maxval returns weird results when dimension is specified

I have a 3x2 array and have filled it with the numbers 1-6
so that it looks like
1 4
2 5
3 6
I then call maxval on it, and specify that I wish to find the max value along dimension 1. One would expect that it should return 3, no?
But for some reason my output is '3 6'
PROGRAM maxv
IMPLICIT None
INTEGER, DIMENSION(3,2) :: x
DATA x /1,2,3,4,5,6/
WRITE(*,*) maxval(x,dim=1)
ENDPROGRAM maxv
I used Gfortran 4.6.3 if the issue lies within my compiler
According to http://www.nsc.liu.se/~boein/f77to90/a5.html , maxval when you specify a dimension is supposed to supply the maxval in that dimension.
Or maybe I have overlooked some stuffs.
Yes, you overlooked some stuffs; maxval is behaving correctly.
When you write, for a rank-2 array x
maxval(x,dim=1)
the function returns a rank-1 array with the same number of elements as there are columns in x, each element being the maximum value of the corresponding column in x. Similarly
maxval(x,dim=2)
would, for your example, return the rank-1 array [4,5,6] -- the maximum value in each row of x.
The GNU documentation explains the function better than the source you cite, IBM explain it even better and include an example of the function's use.