Creating an array from an array - fortran

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.

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

Different shape for array assignment in 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.

Assigning variable number to complex array

I want to assign complex array as variable.
My code is like
complex indx(3,3)
integer i,j
do i=1,3
do j=1,3
indx(i,j) = (i,j)
write(*,*) indx(i,j)
end do
end do
and in this case I am getting an error like
A symbol must be a defined parameter in this context. [I]
indx(i,j) = (i,j)
You must use function cmplx to build a complex value you want to assign.
complex indx(3,3)
integer i,j
do i=1,3
do j=1,3
indx(i,j) = cmplx(i,j)
write(*,*) indx(i,j)
end do
end do
The syntax you tried is only valid for constant literals.
The answer by Vladimir F tells the important part: for (i,j) to be a complex literal constant i and j must be constants.1 As stated there, the intrinsic complex function cmplx can be used in more general cases.
For the sake of some variety and providing options, I'll look at other aspects of complex arrays. In the examples which follow I'll ignore the output statement and assume the declarations given.
We have, then, Vladimir F's correction:
do i=1,3
do j=1,3
indx(i,j) = CMPLX(i,j) ! Note that this isn't in array element order
end do
end do
We could note, though, that cmplx is an elemental function:
do i=1,3
indx(i,:) = CMPLX(i,[(j,j=1,3)])
end do
On top of that, we can consider
indx = RESHAPE(CMPLX([((i,i=1,3),j=1,3)],[((j,i=1,3),j=1,3)]),[3,3])
where this time the right-hand side is in array element order for indx.
Well, I certainly won't say that this last (or perhaps even the second) is better than the original loop, but it's an option. In some cases it could be more elegant.
But we've yet other options. If one has compiler support for complex part designators we have an alternative for the first form:
do i=1,3
do j=1,3
indx(i,j)%re = i
indx(i,j)%im = j
end do
end do
This doesn't really give us anything, but note that we can have the complex part of an array:
do i=1,3
indx(i,:)%re = [(i,j=1,3)]
indx(i,:)%im = [(j,j=1,3)]
end do
or
do i=1,3
indx(i,:)%re = i ! Using scalar to array assignment
indx(i,:)%im = [(j,j=1,3)]
end do
And we could go all the way to
indx%re = RESHAPE([((i,i=1,3),j=1,3))],[3,3])
indx%im = RESHAPE([((j,i=1,3),j=1,3))],[3,3])
Again, that's all in the name of variety or for other applications. There's even spread to consider in some of these. But don't hate the person reviewing your code.
1 That's constants not constant expresssions.

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.