Population of vector with matrix elements column by column - fortran

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

Related

I have an array of zeros and I want to add 1's to some array elements

I tried this in fortran.
The initial array is zeros, for example:
InitialMatrix = 0 0
0 0
0 0
0 0
And I want to add numbers 1 sequentially:
FinalMatrix = 0 0
0 1
1 0
1 1
As if adding one bit at a time.
I generated a matrix containing all elements equal to zero and tried to use ibset to change the zero element to 1, but without success.
The code I made was this one:
program test
implicit none
integer(1) numSitio
integer:: Comb
integer:: i, j
integer, dimension(10, 10)::MatrixZeros
integer, dimension(10, 10)::MatrixSpins
print*, "Set the number of sites: "
read(*,*)numSitio
Comb = 2**numSitio
MatrixZeros = 0
MatrixSpins = ibset(MatrixZeros, 1)
do i = 1, Comb
do j = 1, numSitio
MatrixSpins(i,j) = 0
end do
end do
do i = 1, Comb
write(*,*)(MatrixSpins(i,j), j= 1, numSitio)
end do
!write(*,*)MatrixZeros
end program test
I generated a matrix of zeros to be auxiliary, and then I created the matrix of spins that I want. I tried using the ibset command to add numbers 1 to zero array.
Note: I want to generate a matrix with n columns and 2^n rows, where the first row is all zero elements and starting from the second row, add a 1 bit in the last column. In the third line, the rightmost bit (last column, move to the left column and go on adding bits 1 until in the last line of the matrix, all elements are 1.
If you simply want to count in binary, then just
program test
implicit none
integer i, n
character fmt
print *, "Input number of bits: "; read *, n
write( fmt, "( i0 )" ) n
print "( b0." // fmt // " )", ( i, i = 0, 2 ** n - 1 )
end program test
If you absolutely have to store all the configurations in a matrix (an array of characters would be just as good) then you can just count up with traditional "carry" operations:
program test
implicit none
integer i, j, imx, jmx
integer n
integer, allocatable :: M(:,:)
print *, "Input number of bits: "; read *, n
imx = 2 ** n - 1; jmx = n - 1
allocate( M(0:imx, 0:jmx) )
M = 0
do i = 1, imx
M(i,:) = M(i-1,:)
M(i,jmx) = M(i,jmx) + 1
j = jmx
do while ( M(i,j) > 1 ) ! "carry" operations
M(i,j) = 0
j = j - 1
M(i,j) = M(i,j) + 1
end do
end do
do i = 0, imx
print "( *( i1, 1x ) )", M(i,:)
end do
end program test
or you could use bit operations:
program test
implicit none
integer i, j, imx, jmx, p
integer n
integer, allocatable :: M(:,:)
print *, "Input number of bits: "; read *, n
imx = 2 ** n - 1; jmx = n - 1
allocate( M(0:imx, 0:jmx) )
M = 0
p = 1
do j = 0, jmx
do i = 0, imx
if ( iand(i,p) > 0 ) M(i,jmx-j) = 1
end do
p = 2 * p
end do
do i = 0, imx
print "( *( i1, 1x ) )", M(i,:)
end do
end program test

Extract the minor matrix from a 3x3 based on input i,j

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

Value of variable for every single iteration

This is my code:
Program Arrays_0
Implicit none
Integer :: i , Read_number , Vig_Position , Vipg_Position , n_iter
Integer , parameter :: Br_gra = 12
Integer , parameter , dimension ( Br_gra ) :: Vig = [ ( i , i = 1 , Br_gra) ]
Integer , parameter , dimension ( Br_gra ) :: Vipg = [ 0 , 1 , 1 , 1 , 2 , 2 , 3 , 4 , 4 , 7 , 7 , 7 ]
Integer :: Result_of_calculation
Write(*,*)"Enter the number (From 1 to Br_gra):"
Read(*,*) Read_number
Vig_Position = Vig(Read_number)
Vipg_Position = Vipg(Vig_Position)
n_iter = 0
Result_of_calculation = Vig_Position
Do while( Vipg_Position .ne. Vipg(1) )
n_iter = n_iter + 1
Vig_Position = Vipg_Position
Result_of_calculation = Result_of_calculation + Vig_Position
Vipg_Position = Vipg(Vig_Position)
End Do
Write(*,'(a,1x,i0)')"The number of iteration is:",n_iter
Write(*,'(a,1x,i0)')"The result of calculation is:",Result_of_calculation
End Program Arrays_0
Intention is to get value in every iteration for a variables:
Vig_Position , Result_of_calculation and Vipg_position.
How to declare variables for that kind of calculation?
In general, is there other method for counting a number of iteration?
How to declare variables in function of number of iteration befoure the code set that number like result of calculation?
Now that the question has been clarified, here's a typical way of solving the problem in Fortran. It isn't the only possible way, but it is the most general. The strategy in routine resize to double the old size is reasonable - you want to minimize the number of times this is called. The data set in the sample program is small, so to show the effect I allocated the array very small to begin with. In reality, you would want a reasonably large initial allocation (say, 100 at least).
Note the use of an internal procedure that inherits the type vals_t from its host.
Program Arrays_0
Implicit none
Integer :: i , Read_number , Vig_Position , Vipg_Position , n_iter
Integer , parameter :: Br_gra = 12
Integer , parameter , dimension ( Br_gra ) :: Vig = [ ( i , i = 1 , Br_gra) ]
Integer , parameter , dimension ( Br_gra ) :: Vipg = [ 0 , 1 , 1 , 1 , 2 , 2 , 3 , 4 , 4 , 7 , 7 , 7 ]
Integer :: Result_of_calculation
! Declare a type that will hold one iteration's values
type vals_t
integer Vig_Position
integer Vipg_Position
integer Result_of_calculation
end type vals_t
! Declare an allocatable array to hold the values
! Initial size doesn't matter, but should be close
! to a lower limit of possible sizes
type(vals_t), allocatable :: vals(:)
allocate (vals(2))
Write(*,*)"Enter the number (From 1 to Br_gra):"
Read(*,*) Read_number
Vig_Position = Vig(Read_number)
Vipg_Position = Vipg(Vig_Position)
n_iter = 0
Result_of_calculation = Vig_Position
Do while( Vipg_Position .ne. Vipg(1) )
n_iter = n_iter + 1
Vig_Position = Vipg_Position
Result_of_calculation = Result_of_calculation + Vig_Position
Vipg_Position = Vipg(Vig_Position)
! Do we need to make vals bigger?
if (n_iter > size(vals)) call resize(vals)
vals(n_iter) = vals_t(Vig_Position,Vipg_Position,Result_of_calculation)
End Do
Write(*,'(a,1x,i0)')"The number of iteration is:",n_iter
Write(*,'(a,1x,i0)')"The result of calculation is:",Result_of_calculation
! Now vals is an array of size(vals) of the sets of values
! For demonstration, print the size of the array and the values
Write(*,'(a,1x,i0)')"Size of vals is:", size(vals)
Write(*,'(3i7)') vals(1:n_iter)
contains
! Subroutine resize reallocates the array passed to it
! with double the current size, copies the old data to
! the new array, and transfers the allocation to the
! input array
subroutine resize(old_array)
type(vals_t), allocatable, intent(inout) :: old_array(:)
type(vals_t), allocatable :: new_array(:)
! Allocate a new array at double the size
allocate (new_array(2*size(old_array)))
write (*,*) "Allocated new array of size ", size(new_array)
! Copy the data
new_array(1:size(old_array)) = old_array
! Transfer the allocation to old_array
call MOVE_ALLOC (FROM=new_array, TO=old_array)
! new_array is now deallocated
return
end subroutine resize
End Program Arrays_0
Sample output:
Enter the number (From 1 to Br_gra):
12
Allocated new array of size 4
The number of iteration is: 3
The result of calculation is: 23
Size of vals is: 4
7 3 19
3 1 22
1 0 23

Random sampling in fortran

I have the following data
X Y INFTIME
1 1 0
1 2 4
1 3 4
1 4 3
2 1 3
2 2 1
2 3 3
2 4 4
3 1 2
3 2 2
3 3 0
3 4 2
4 1 4
4 2 3
4 3 3
4 4 0
X and Y represent he X and Y components in the square grid of 4 by 4.
Here I want to sample randomly 10% from the population which are infected i.e, whose INFTIME is non zero. I did not get any idea of coding so could not start it.
Any suggestions and idea will be great for me.
Thanks
EDIT:
DO T = 1,10
DO i = 1, 625
IF(INFTIME(i)/=0 .AND. INFTIME(i) .LE. T)THEN
CALL RANDOM_NUMBER(u(i))
u(i) = 1+aint(u(i)*25)
CALL RANDOM_NUMBER(v(i))
v(i) = 1+aint(v(i)*25)
CALL RANDOM_NUMBER(w(i))
w(i) = 1+aint(w(i)*10)
ENDIF
ENDDO
ENDDO
do p = 1,625
WRITE(*,*) u(p),v(p),w(p)
enddo
This is my code what I tried but it only gives the random numbers, not the connection to the data. I used the data of 25 by 25 grids i.e, 625 individuals and time of infection 1 to 10
Follow what ja72 said. You have three 1D arrays of the same size (16). All you need to do is pick a number between 1 and 16, check to see if INFTIME is zero and accept the value as needed, then repeat until you've taken 10% of the samples (which would be 1.6 values, so I presume you'd just take 2? Or do you have more data than this 4x4 you presented?)
Edit You need to call the random number generator before the if statement:
do t=1,10
do i=1,625
ind = 1+int(624*rand(seed))
if(inftime(ind).neq.0 .and. inftime(ind).le.t) then
stuff
endif
enddo
enddo
The call ind=1+int(625*rand(seed)) will pick a random integer between 1 (when rand(seed)=0) and 625 (when rand(seed)=1). Then you can do what you need if the if statement is satisfied.
EDIT: program epimatrix
IMPLICIT NONE
INTEGER ::l, i,T,K
REAL, DIMENSION(1:625):: X,y,inftime
INTEGER::seed,my_cnt
INTEGER,DIMENSION(8) :: time1
CALL DATE_AND_TIME(values=time1)
seed = 1000*time1(7)+time1(8)
call srand(seed)
OPEN(10, FILE = 'epidemicSIR.txt', FORM = 'FORMATTED')
DO l = 1,625
READ(10,*,END = 200) X(l), Y(l), INFTIME(l)
! WRITE(*,*) X(l),Y(l), INFTIME(l)
! if you know how it was formatted, you should use
! read(10,20) X(l), Y(l), INFTIME(l)
! where 20 is the format
ENDDO
200 CONTINUE
CLOSE(10)
DO T = 1,10
my_cnt=0
write(*,*) "T=",T
DO while (my_cnt.le.63)
K = 1+int(624*rand())
IF(INFTIME(K)/=0 .AND. INFTIME(K) .LE. T)THEN
write(*,*) X(k),Y(k),INFTIME(k)
my_cnt=my_cnt+1
ENDIF
enddo
write(*,*) " "
ENDDO
end program
EDIT 2
I've adjusted the program to fix some of the issues. I've tried keeping my edits in lowercase so that you can see the difference. The do-while loop allows the code to continue running until the condition my_cnt.le.63 has been met (which means you have 63 lines of X, Y, inftime per T). I've added a line to output T and another line to add a space so that the data might be more clear when looking at the output.
This should take care of all the issues you've been running into. If not, I'll keep checking this page.

How to call each 4 values out of 40 values in fortran

I have a column matrix with 40 values. Say,
1
4
5
2
4
1
9
.
.
.
2
How can I call every four values and average them until it reaches 40th? I managed to do in the following way but is there a better way? Beste!
i = 1, 4
avg1 = avg + avg(i)
i = 5,8
avg2 = avg + avg(i)
i = 9,12
avg3 = avg + avg(i)
.......
i = 37,40
avg10 = avg + avg(i)
It took me a couple of iterations to get the syntax right, but how about this?
integer, parameter, dimension(*) :: a = [ 1, 4, 5, ..., 2 ]
integer :: i
real, dimension(10) :: avg
avg = [ (sum(a(i * 4 + 1 : (i + 1) * 4)) / 4., i = 0, 9) ]
print *, avg
end
How about that?
program testing
implicit none
integer, dimension(40) :: array
real, dimension(10) :: averages
integer :: i, j, k, aux
array(:) = (/(i, i=1,40)/) ! just values 1 to 40
averages(:) = 0.0
k = 1 ! to keep track of where to store the next average
do i=1,40,4 ! iterate over the entire array in steps of 4
aux = 0 ! just a little helper variable, not really required, but neater I think
do j=i,i+3 ! iterating over 4 consecutive values
aux = aux + array(j)
end do
averages(k) = aux / 4.0
k = k + 1
end do
print *, averages
end program testing
This is the output:
2.500000 6.500000 10.50000 14.50000 18.50000
22.50000 26.50000 30.50000 34.50000 38.50000
Is this what you were looking for?