I don't understand how I can implement the search for even elements using the section method.
I did a search for odd elements, but I need to find even ones
I need it to output 2 4 6 8, but my program outputs 1 3 5 7 9
program main
implicit none
integer, DIMENSION(3, 3) :: array = reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), shape(array))
integer :: i = 0
integer, allocatable :: B(:)
B = [(Array(::2,i), i=1, 3)]
print *, B
end program main
If you're interested in the elements with odd indices, you want
B = [(Array(modulo(i,2)+1::2, i), i=1, 3)]
modulo(i,2)+1 is 2 when i is odd, and 1 when i is even. This means that for columns with odd i you select every other element starting at the second element, and for columns with even i you select every other element starting at the first element.
If instead you're interested in selecting the odd values from an arbitrary array, you can't do this with a simple slice, and you instead need a conditional filter. For example,
B = [integer::]
do i=1,3
do j=1,3
if (modulo(Array(j,i),2)==0) then
B = [B, Array(j,i)]
endif
enddo
enddo
Related
Accelerating a Fortran code with OpenACC using the PGI compiler, I got problems with a matmul call in an accelerated loop.
In the simplified example, I apply the identity matrix on two vectors, so the input and the output values should be the same:
program test
implicit none
integer :: a(3, 3)
integer :: v1(3, 2), v2(3, 2)
integer :: i
a = reshape([1, 0, 0, 0, 1, 0, 0, 0, 1], [3, 3])
v1 = reshape([1, 2, 3, 4, 5, 6], [3, 2])
print *, v1
!$acc kernels copyin(a, v1) copyout(v2)
!$acc loop independent
do i = 1, 2
v2(:, i) = matmul(a, v1(:, i))
enddo
!$acc end kernels
print *, v2
endprogram
When compiling with the PGI compiler version 20.9, I got these information:
test:
12, Generating copyin(a(:,:),v1(:,:)) [if not already present]
Generating implicit copyout(z_a_0(:)) [if not already present]
Generating copyout(v2(:,:)) [if not already present]
14, Loop is parallelizable
Generating Tesla code
14, !$acc loop gang ! blockidx%x
15, !$acc loop vector(32) ! threadidx%x
15, Loop is parallelizable
Running the code gives the following values:
1 2 3 4 5 6
4 5 6 4 5 6
the second line should be like the first one, which is the case on sequential execution. What is wrong in the code?
Looks to be a compiler issue. The problem line being:
Generating implicit copyout(z_a_0(:))
"z_a_0" is compiler temp array being created to hold the intermediary result from the call to matmul. It's declaration is being hoisted out of the loop and then copied back in as shared array. Since it's shared, it then causes a race condition.
I've submitted a problem report (TPR #29482) and sent it to our engineers for further investigation.
#Mat Colgrove explained the reason of the incorrect behavior. The workaround I found was to write the matrix vector multiplication explicitly:
program test
implicit none
integer :: a(3, 3)
integer :: v1(3, 2), v2(3, 2)
integer :: i, j, k
a = reshape([1, 0, 0, 0, 1, 0, 0, 0, 1], [3, 3])
v1 = reshape([1, 2, 3, 4, 5, 6], [3, 2])
print *, v1
!$acc kernels copyin(a, v1) copyout(v2)
!$acc loop independent
do i = 1, 2
!$acc loop seq
do k = 1, 3
v2(k, i) = 0
!$acc loop seq
do j = 1, 3
v2(k, i) = v2(k, i) + a(j, k) * v1(j, i)
enddo
enddo
enddo
!$acc end kernels
print *, v2
endprogram
For a given 3x3 matrix, for example:
A = [3 1 -4 ; 2 5 6 ; 1 4 8]
If I need the minor matrix for entry (1,2)
Minor = [2 6 ; 1 8]
I already wrote a program to read in the matrix from a text file, and I am supposed to write a subroutine to extract the minor matrix from the main matrix A based on the user inputs for i,j. I am very new to Fortran and have no clue how to do that. I made some very desperate attempts but I am sure there is a cleaner way to do that.
I got so desperate I wrote 9 if functions for each possible combination of i and j but that clearly is not a smart way for doing this. Any help is appreciated!
One way to do this is, as #HighPerformanceMark said in the comment, with vector subscripts. You can declare an array with the rows you want to keep, and the same for columns, and pass them as indices to your matrix. Like this:
function minor(matrix, i, j)
integer, intent(in) :: matrix(:,:), i, j
integer :: minor(size(matrix, 1) - 1, size(matrix, 2) - 1)
integer :: rows(size(matrix, 1) - 1), cols(size(matrix, 2) - 1), k
rows = [(k, k = 1, i - 1), (k, k = i + 1, size(rows))]
cols = [(k, k = 1, j - 1), (k, k = j + 1, size(cols))]
minor = matrix(rows, cols)
end
(I didn't test it yet, so tell me if there is any error)
Another option would be constructing a new matrix from 4 assignments, one for each quadrant of the result (limited by the excluded row/column).
I like the first option more because it is more scalable. You could easily extend the function to remove multiple rows/columns by passing arrays as arguments, or adapt it to work on higher dimensions.
You can use an ac-implied-do and RESHAPE to construct a mask of the parts of the matrix you want to preserve and then zap the rest with pack and reassemble with RESHAPE.
program minor
implicit none
integer A(3,3)
integer, allocatable :: B(:,:)
character(20) fmt
integer i, j
A = reshape([ &
3, 1, -4, &
2, 5, 6, &
1, 4, 8], &
shape(A), order = [2,1])
write(fmt,'(*(g0))') '(a/',size(A,2),'(i3))'
write(*,fmt) 'A =',transpose(A)
B = reshape(pack(A,reshape([((all([i,j]/=[1,2]),i=1,size(A,1)), &
j=1,size(A,2))],shape(A))),shape(A)-1)
write(fmt,'(*(g0))') '(a/',size(B,2),'(i3))'
write(*,fmt) 'B =',transpose(B)
end program minor
Output:
A =
3 1 -4
2 5 6
1 4 8
B =
2 6
1 8
My IDE is CodeBlocks 16.01.
This is my code:
Program Matrix_To_Vector
Implicit none
Integer::i,j
Integer, parameter :: M = 3 , N = 2
Integer, dimension ( M , N ) :: Matrix_0
Integer, dimension ( M*N ) :: Vector_0
! Population of matrix
Do i = 1 , 3
Do j = 1 , 2
Matrix_0(i,j) = i+j
End Do
End Do
Open (15, File = 'Result.txt', Status = 'Unknown', Action = 'Write')
Do i = 1 , 3
Write(15,*) Matrix_0(i,:)
End Do
Write(15,*) ( Vector_0(i), i =1 , size(Vector_0))
Close (15)
End Program Matrix_To_Vector
The result of matrix population is:
2 3
3 4
4 5
My intention is to make vector Vector_0 with elements from matrix Matrix_0. The size of vector is M*N. First element of vector is (1,1) from matrix and last is (3,2) - i want to do that column by column.
Is there way for doing that with do loops?
The contetn of wanted vector is:
2 3 4 3 4 5
like this?
do j=1,2
vector_0(3*(j-1)+1:3*(j-1)+3)=Matrix_0(:,j)
enddo
of course you could just do
vector_0=reshape(matrix_0,shape(vector_0))
as well
Is there any way to run a loop for discrete values of a variable? What about in some latest version?
Something like
for i in 1 5 9 11 31 77
used in Unix shell script?
integer, dimension (5) :: indx = [5, 9, 11, 31, 71]
do i=1, size(indx)
j=indx(i)
....
end do
You can also use an implied do loop to accomplish this, but you'll have to define the array of values as above:
integer, dimension (5) :: indx = [5, 9, 11, 31, 71]
integer, dimension (5) :: rslt
integer, external :: func
rslt = (/ func(indx(j)), j=1,5 /)
I am not sure if this helps, but you can use arrays for indeces
program Console1
implicit none
! Variables
INTEGER :: X(4) = (/ 1, 3, 5, 7 /)
REAL :: Y(10) = 0.0
! Body of Console1
print *, X
! 1 3 5 7
Y(X) = 10.0/X
print *, Y
! 10.0 0.0 3.33 0.0 2.00 0.0 1.428 0.0 ...
end program Console1
I would like to do something like this in Fortran:
program where
real :: a(6) = (/ 4, 5, 6, 7, 8, 9 /)
print *, a(a>7)
end program
In Python I would typically do this with NumPy like this:
import numpy
a = numpy.array([ 4, 5, 6, 7, 8, 9])
print a[numpy.where(a>7)]
#or
print a[a>7]
I've played around, but nothing has worked thus far, but I'm guessing it is fairly simple.
I'll extend slightly the answer by #VladimirF as I suspect you don't want to limit yourself to the exact print example.
a>7 returns a logical array corresponding to a with .true. at index where the condition is met, .false. otherwise. The pack intrinsic takes such a mask and returns an array with those elements with .true. in the mask.
However, you can do other things with the mask which may fit under your numpy.where desire. For example, there is the where construct (and where statement) and the merge intrinsic. Further you can use pack again with the mask to get the indices and do more involved manipulations.
program where
real :: a(6) = (/ 4, 5, 6, 7, 8, 9 /)
print *, pack(a,a>7)
end program
You can find a related topic here: Better way to mask a Fortran array?
I think both where and merge can do the task.
In python, where has the ability to assign different value according to the mask, for example
a = np.array([4, 5, 6, 7, 8, 9])
b = np.where(a>7, 1, -1)
b will be array([-1, -1, -1, -1, 1, 1])
In Fortran, the equivalent of this is merge
real :: a(6) = (/ 4, 5, 6, 7, 8, 9 /)
real, allocatable :: b(:)
b = merge(1,-1,a>7)
print*, b
end
The MERGE function chooses alternative values based on the value of a mask. http://www.lahey.com/docs/lfpro78help/F95ARMERGEFn.htm
where can also do this, but it is slightly more complicated.
real :: a(6) = (/ 4, 5, 6, 7, 8, 9 /)
real, allocatable :: b(:)
b = a
where (a>7)
b = 1
else where
b = -1
end where
print*, b
end
a short version is this
b = a
b = -1
where (a>7) b = 1
You can find more information of where here: http://www.personal.psu.edu/jhm/f90/statements/where.html