In fortran 2003, classes and OOP are defined in the standard. I would like to know how upcasting and downcasting is performed.
Actually you can do up-casting (but not down-casting) out-of-the-box using this approach:
PROGRAM main
IMPLICIT NONE
TYPE :: parent
INTEGER :: a
END TYPE parent
TYPE, EXTENDS(parent) :: child
INTEGER :: b
END TYPE child
CLASS(parent), ALLOCATABLE :: p
TYPE(child) :: c
ALLOCATE (p)
p%a = 5
c%a = 10
c%b = 15
PRINT *, p%a
! p = c
DEALLOCATE (p)
ALLOCATE (p, source=c)
PRINT *, p%a
DEALLOCATE (p)
END PROGRAM main
Note:
the variable of type to which you want to up-cast should be polymorphic (CLASS instead of TYPE);
you cannot use intrinsic assignment for polymorphic vars (ALLOCATE instead of =).
ALLOCATE with the source= clause still might be not supported by Intel compiler.
Or you can define an assignment from child type to parent:
MODULE types
IMPLICIT NONE
TYPE :: parent
INTEGER :: a
CONTAINS
PROCEDURE, PRIVATE :: parent_from_child
GENERIC :: ASSIGNMENT(=) => parent_from_child
END TYPE parent
TYPE, EXTENDS(parent) :: child
INTEGER :: b
END TYPE child
CONTAINS
SUBROUTINE parent_from_child(this, c)
CLASS(parent), INTENT(INOUT) :: this
CLASS(child), INTENT(IN) :: c
this%a = c%a
END SUBROUTINE parent_from_child
END MODULE types
In that case you do not need to use polymorphic entities and special form of ALLOCATABLE statement:
PROGRAM main
USE types
IMPLICIT NONE
TYPE(parent) :: p
TYPE(child) :: c
p%a = 5
c%a = 10
c%b = 15
PRINT *, p%a
p = c
PRINT *, p%a
END PROGRAM main
Down-casting... Hmmm... It's unsafe, it's against strong typing discipline. When I faced with down-casting I tsarted to think in the same way - using the same approach. You need to just define another assignment - from parent to child. The only problem will be that if you will use exactly the same scheme (GENERIC binding) child_from_parent will be not distinguishable from parent_from_child. However you can do it in another way:
MODULE types
IMPLICIT NONE
INTERFACE ASSIGNMENT(=)
MODULE PROCEDURE parent_from_child, child_from_parent
END INTERFACE
TYPE :: parent
INTEGER :: a
END TYPE parent
TYPE, EXTENDS(parent) :: child
INTEGER :: b
END TYPE child
CONTAINS
SUBROUTINE parent_from_child(this, c)
TYPE(parent), INTENT(INOUT) :: this
CLASS(child), INTENT(IN) :: c
this%a = c%a
END SUBROUTINE parent_from_child
SUBROUTINE child_from_parent(this, p)
TYPE(child), INTENT(INOUT) :: this
CLASS(parent), INTENT(IN) :: p
this%a = p%a
this%b = 0
END SUBROUTINE child_from_parent
END MODULE types
PROGRAM main
USE types
IMPLICIT NONE
CLASS(parent), ALLOCATABLE :: p
TYPE(child) :: c
c%a = 10
c%b = 15
ALLOCATE (p, source=c)
c%a = 5
PRINT *, c%a
c = p
PRINT *, c%a
END PROGRAM main
But this is not a down-casting. Down-casting is casting a reference to the base class to one of its derived classes. You need to check whether the type of the referenced object is indeed the one being cast to or a derived type of it, and thus issue an error if it is not the case.
Friday night... Good time to do some Fortran. =) Finally I ended up with:
MODULE types
IMPLICIT NONE
TYPE :: parent
INTEGER :: a
END TYPE parent
TYPE, EXTENDS(parent) :: child
INTEGER :: b
END TYPE child
CONTAINS
SUBROUTINE cast(from, to)
CLASS(parent), INTENT(IN) :: from
CLASS(parent), INTENT(INOUT) :: to
SELECT TYPE (to)
TYPE IS (parent)
SELECT TYPE (from)
TYPE IS (parent)
PRINT *, "ordinary assignment"
to = from
TYPE IS (child)
PRINT *, "up-casting"
to%a = from%a
END SELECT
TYPE IS (child)
SELECT TYPE (from)
TYPE IS (parent)
PRINT *, "No way!"
TYPE IS (child)
PRINT *, "down-casting"
to = from
END SELECT
END SELECT
END SUBROUTINE cast
END MODULE types
PROGRAM main
USE types
IMPLICIT NONE
CLASS(parent), ALLOCATABLE :: p1, p2
TYPE(child) :: c1, c2
ALLOCATE (p1, p2)
p1%a = 1
p2%a = 2
c1%a = 1
c1%b = 1
c2%a = 2
c2%b = 2
PRINT *, p1%a
! up-casting from c2 to p1
CALL cast(c2, p1)
PRINT *, p1%a
PRINT *, "----------"
DEALLOCATE (p2)
ALLOCATE (p2, source=c1)
PRINT *, c2%a, c2%b
! down-casting from p2 to c2
CALL cast(p2, c2)
PRINT *, c2%a, c2%b
DEALLOCATE (p1, p2)
END PROGRAM main
Related
I have a text file (S.txt) which contains a certain parameter with its amount in each interval. Something like this:
-
-
x=a
-
-
x=b
-
-
x=c
-
-
.
.
.
I want to write Fortran code to open the text file (S.txt) and read it in order to find each 'x' and read its amount into a parameter. something like this:
a
b
c
.
.
.
I have come up with this code but it does not work:
PROGRAM deter
IMPLICIT NONE
real,Dimension(2) :: value
open(unit=40,file='D:\S.txt',action='read')
READ(40,fmt='(2X,f3.3)') value
close(40)
END PROGRAM deter
when I run this program I get NO ERROR, but it doesn't work either.
any suggestion?
program extract_value
implicit none
integer :: ios
character(len=200), allocatable :: command(:)
character(len=200), allocatable :: word(:)
real, allocatable :: x(:), deter(:)
character(len=200) :: line
integer :: n, i, j, r
character (len=5), parameter :: sstr='x='
open(unit=50, file='D:\S.txt', iostat=ios)
if ( ios /= 0 ) stop "Error opening file S.txt"
n = 0
do
read(50, '(A)', iostat=ios) line
if (ios /= 0) exit
n = n + 1
end do
allocate(command(n))
allocate(word(n))
rewind(50)
j=0
do i = 1, n
read(50,'(A)') command(i)
read (command(i),'(a2)') word(i)
if (word(i)==sstr) then
j=j+1
end if
end do
allocate(x(n))
allocate(deter(j))
x=0
do i = 1, n
if (word(i)==sstr) then
read(command(i), fmt='(2X,f5.2)') x(i)
end if
end do
deter=0
deter=pack(x, x /= 0)
close(50)
open(unit=100, file='D:\R.txt', action="write",status="replace")
WRITE(100,fmt='(2X,f5.2)')(deter(r), r=1,j)
close(100)
end program extract_value
I've written a minimal implementation for the fast xoroshiro128plus pseudo-random number generator in Fortran to replace the intrinsic random_number. This implementation is quite fast (4X faster than random_number) and the quality is good enough for my purposes, I don't use it in cryptography applications.
My question is how can I optimize this subroutine to get the last drop of performance from my compiler, even 10% improvement is appreciated. This subroutine is to be used in tight loops inside long simulations. I'm interested more in generating a single random number at a time and not big vectors or nD arrays at once.
Here is a test program to give you some context about how my subroutine is used:
program test_xoroshiro128plus
implicit none
integer, parameter :: n = 10000
real*8 :: A(n,n)
integer :: i, j, t0, t1, count_rate, count_max
call system_clock(t0, count_rate, count_max)
do j = 1,n
do i = 1,n
call drand128(A(i,j))
end do
end do
! call drand128(A) ! works also with 2D
call system_clock(t1)
print *, "Time :", real(t1-t0)/count_rate
print *, "Mean :", sum(A)/size(A), char(10), A(1:2,1:3)
contains
impure elemental subroutine drand128(r)
real*8, intent(out) :: r
integer*8 :: s0 = 113, s1 = 19937
s1 = xor(s0,s1)
s0 = xor(xor(ior(ishft(s0,55), ishft(s0,-9)),s1), ishft(s1,14))
s1 = ior(ishft(s1,36), ishft(s1,-28))
r = ishft(s0+s1, -1) / 9223372036854775808.d0
end
end program
Only now I realized you are asking about this particular PRNG. I am using it in Fortran myself https://bitbucket.org/LadaF/elmm/src/eb5b54b9a8eb6af158a38038f72d07865fe23ee3/src/rng_par_zig.f90?at=master&fileviewer=file-view-default
My code in the link is slower than yours, because it calls several subroutines and aims to be more universal. Bet let's try to condense the code I use into a single subroutine.
So let's just compare the performance of your code and the optimized version by #SeverinPappadeux and my optimized code with Gfortran 4.8.5
> gfortran -cpp -O3 -mtune=native xoroshiro.f90
Time drand128 sub: 1.80900002
Time drand128 fun: 1.80900002
Time rng_uni: 1.32900000
the code is here, remember to let the CPU spin-up, the first iteration of the k loop is just garbage!!!
program test_xoroshiro128plus
use iso_fortran_env
implicit none
integer, parameter :: n = 30000
real*8 :: A(n,n)
real*4 :: B(n,n)
integer :: i, j, k, t0, t1, count_rate, count_max
integer(int64) :: s1 = int(Z'1DADBEEFBAADD0D0', int64), s2 = int(Z'5BADD0D0DEADBEEF', int64)
!let the CPU spin-up
do k = 1, 3
call system_clock(t0, count_rate, count_max)
do j = 1,n
do i = 1,n
call drand128(A(i,j))
end do
end do
! call drand128(A) ! works also with 2D
call system_clock(t1)
print *, "Time drand128 sub:", real(t1-t0)/count_rate
call system_clock(t0, count_rate, count_max)
do j = 1,n
do i = 1,n
A(i,j) = drand128_fun()
end do
end do
! call drand128(A) ! works also with 2D
call system_clock(t1)
print *, "Time drand128 fun:", real(t1-t0)/count_rate
call system_clock(t0, count_rate, count_max)
do j = 1,n
do i = 1,n
call rng_uni(A(i,j))
end do
end do
call system_clock(t1)
print *, "Time rng_uni:", real(t1-t0)/count_rate
end do
print *, "Mean :", sum(A)/size(A), char(10), A(1:2,1:3)
contains
impure elemental subroutine drand128(r)
real*8, intent(out) :: r
integer*8 :: s0 = 113, s1 = 19937
s1 = xor(s0,s1)
s0 = xor(xor(ior(ishft(s0,55), ishft(s0,-9)),s1), ishft(s1,14))
s1 = ior(ishft(s1,36), ishft(s1,-28))
r = ishft(s0+s1, -1) / 9223372036854775808.d0
end
impure elemental real*8 function drand128_fun()
real*8, parameter :: c = 1.0d0/9223372036854775808.d0
integer*8 :: s0 = 113, s1 = 19937
s1 = xor(s0,s1)
s0 = xor(xor(ior(ishft(s0,55), ishft(s0,-9)),s1), ishft(s1,14))
s1 = ior(ishft(s1,36), ishft(s1,-28))
drand128_fun = ishft(s0+s1, -1) * c
end
impure elemental subroutine rng_uni(fn_val)
real(real64), intent(inout) :: fn_val
integer(int64) :: ival
ival = s1 + s2
s2 = ieor(s2, s1)
s1 = ieor( ieor(rotl(s1, 24), s2), shiftl(s2, 16))
s2 = rotl(s2, 37)
ival = ior(int(Z'3FF0000000000000',int64), shiftr(ival, 12))
fn_val = transfer(ival, 1.0_real64) - 1;
end subroutine
function rotl(x, k)
integer(int64) :: rotl
integer(int64) :: x
integer :: k
rotl = ior( shiftl(x, k), shiftr(x, 64-k))
end function
end program
The main difference should come from the faster and better way to convert from integers to reals http://experilous.com/1/blog/post/perfect-fast-random-floating-point-numbers#half-open-range
If you are bored, you could try to inline rotl() manually, but I trust the compiler here.
Ok, here is my attempt. First, I made it to function - in x64 or similar ABI function returning float value do in in register - much faster than parameter transfer. Second,
replaced final division by multiplication, though Intel compiler might do it for you.
Timing, Intel i7 6820, WSL, Ubuntu 18.04:
before - 0.850000024
after - 0.601000011
GNU Fortran 7.3.0, command line
gfortran -std=gnu -O3 -ffast-math -mavx2 /mnt/c/Users/kkk/Documents/CPP/a.for
Code
program test_xoroshiro128plus
implicit none
integer, parameter :: n = 10000
real*8 :: A(n,n)
integer :: i, j, t0, t1, count_rate, count_max
call system_clock(t0, count_rate, count_max)
do j = 1,n
do i = 1,n
A(i,j) = drand128()
end do
end do
A = drand128() ! works also with 2D
call system_clock(t1)
print *, "Time :", real(t1-t0)/count_rate
print *, "Mean :", sum(A)/size(A), char(10), A(1:2,1:3)
contains
impure elemental real*8 function drand128()
real*8, parameter :: c = 1.0d0/9223372036854775808.d0
integer*8 :: s0 = 113, s1 = 19937
s1 = xor(s0,s1)
s0 = xor(xor(ior(ishft(s0,55), ishft(s0,-9)),s1), ishft(s1,14))
s1 = ior(ishft(s1,36), ishft(s1,-28))
drand128 = ishft(s0+s1, -1) * c
end
end program
I was going through all the other threads about undefined reference and I was unable to figure out why this piece of codes is not working. I am basically trying to run a function from a module into a subroutine in the main program. But I keep getting an error
Main:
program main
use m1
implicit none
integer, dimension(:,:), allocatable :: A,AFun
integer :: n,i,j
print *, "enter value for n"
read *, n
do i=1,n
do j=1,n
A(i,j)=i**2-j**3
end do
end do
print *, "Matrix A: "
call prMat(A,n)
call matFun(A,AFun,n)
print *, "Matrix AFun:"
call prMat(AFun,n)
call fromAvg(AFun,n)
contains
subroutine prMat(x,n)
implicit none
integer, dimension(n,n) :: x
integer :: i,j,n
do i=1,n
write(*,*), (x(i,j))
end do
end subroutine prMat
subroutine matfun(x,y,n)
implicit none
integer, dimension(n,n) :: x,y
integer :: i,j,n,f1
do i = 1,n
do j=1,n
y(i,j)=f1(x,i,j,n)
end do
end do
end subroutine matFun
subroutine fromAvg(x,n)
integer, dimension(:,:) :: x
integer :: i,j,n
integer :: s,avg,g,b
s=0; g=0; b=0
do i=1,n
do j=1,n
s=s+x(i,j)
end do
end do
avg=s/(n*n)
do i = 1,n
do j = 1,n
if ( x(i,j) > avg ) then
g = g + 1
else
b = b + 1
end if
end do
end do
print *, "In from avg, average=", avg
print *, "Number of values greater than average is ",g
print *, "Number of values less than average is ",b
end subroutine fromAvg
integer, dimension(:,:), allocatable, intent(IN) :: x
integer :: i,j,n
integer :: s,avg,g,b
s=0; g=0; b=0
do i=1,n
do j=1,n
s=s+x(i,j)
end do
end do
avg=s/(n*n)
do i = 1,n
do j = 1,n
if ( x(i,j) > avg ) then
g = g + 1
elseif ( x(i,j) < avg ) then
b = b + 1
end if
end do
end do
print *, "In from avg, average=", avg
print *, "Number of values greater than average is ",g
print *, "Number of values less than average is ",b
end subroutine fromAvg
end program main
Module Function:
module m1
implicit none
private
public :: f1
contains
function f1(x,p,q,n)
integer, dimension(:,:) :: x
integer, intent(in) :: p,q,n
integer :: i,f1
f1=0
do i = 1,n
f1 = f1 + x(p,n)
end do
do i = 1,n
f1 = f1 + x(n,q)
end do
end function f1
end module m1
The error that I keep getting is as follows:
/tmp/ccKZHw7L.o: In function `matfun.1520':
lab4_b.f90:(.text+0x808): undefined reference to `__m1_MOD_f1'
collect2: ld returned 1 exit status
Am I missing something? I have use m1 in the beginning of my main program before the implicit none statement.
In the subroutine matfun f1 is (re-)declared to be an integer, in the line
integer :: i,j,n,f1
This effectively masks the module function from sight. Since the code is (correctly) using the module containing f1 it shouldn't also be declared inside the subroutine.
Then my compiler complains that there is no definition for fromavg but I guess you know that.
I am coding the Operator(+) used in a vector module , and getting the following error
Inside I am calling an operator which it picks up some other function in error.
gfortran -o build/lib/vectors.o -c -ffree-form -g -J./build/lib lib/vectors.f
lib/vectors.f:804.7:
vd = ud + scald
1
Error: Operands of binary numeric operator '+' at (1) are CLASS(vector)/REAL(4)
scons: *** [build/lib/vectors.o] Error 1
scons: building terminated because of errors.
Here is the code. I am unsure if the problem is due to a how the bindings are declared.
Module Vectors
Implicit None
Type :: Vector
Real :: x
Real :: y
Real :: z
Contains
Procedure :: vecp => vector_add
Procedure :: vecpscal => vector_plus_integer, &
vector_plus_real
Procedure, Pass (ub) :: integer_plus_vector
Procedure, Pass (ud) :: real_plus_vector
Generic :: Operator (+) => vecp, vecpscal, &
integer_plus_vector, &
real_plus_vector
End Type Vector
Contains
Function vector_add &
( &
u, v &
) &
Result (w)
!!$ In.
Class (Vector), Intent(in) :: u, v
!!$ Out.
Type (Vector) :: w
w% x = u% x + v% x
w% y = u% y + v% y
w% z = u% z + v% z
End Function vector_add
Function vector_plus_real &
( &
u, scal &
) &
Result (v)
!!$ In.
Class (Vector), Intent(in) :: u
Real, Intent (In) :: scal
!!$ Out.
Type (Vector) :: v
v% x = u% x + scal
v% y = u% y + scal
v% z = u% z + scal
End Function vector_plus_real
Function vector_plus_integer &
( &
ub, scalb &
) &
Result (vb)
!!$ In.
Class (Vector), Intent(in) :: ub
Integer, Intent (In) :: scalb
!!$ Out.
Type (Vector) :: vb
vb% x = ub% x + scalb
vb% y = ub% y + scalb
vb% z = ub% z + scalb
End Function vector_plus_integer
Function real_plus_vector &
( &
scalc, uc &
) &
Result (vc)
!!$ In.
Real, Intent (In) :: scalc
Class (Vector), Intent(in) :: uc
!!$ Out.
Type (Vector) :: vc
vc = uc + scalc
End Function real_plus_vector
Function integer_plus_vector &
( &
scald, ud &
) &
Result (vd)
!!$ In.
Integer, Intent (In) :: scald
Class (Vector), Intent(in) :: ud
!!$ Out.
Type (Vector) :: vd
vd = ud + scald
End Function integer_plus_vector
End Module Vectors
Your type declaration has a syntax error in the declaration of the vecpscal binding - you list two procedures as implementing the binding. I would expect the compiler to diagnose this.
The error you list is caused by the absence of a specific binding that corresponds to the vector plus real case (which is the second procedure in the erroneous type bound procedure statement).
I would like to solve a given equation of the following kind with Fortran:
1 ? 2 ? 3 = 7
In this equation only the arithmetic operators are missing and the solution would be '+' for the first question mark and '*' for the second one. I would like to write a short script that finds the correct operators by brute force. So in this case four times four cases would have to be checked. In order to do this I would like to store the operators in an array and use them in a nested do loop:
value1=1
value2=2
value3=3
result=7
op(1)=+
op(2)=-
op(3)=/
op(4)=*
do i=1,4
do j=1,4
if(value1 op(i) value2 op(j) value3 .eq. result) then
write(*,*)'Found solution: ' ,op(i), op(j)
else
j=j+1
endif
enddo
i=i+1
enddo
Apparently this doesn't work because of the wrong interpretation of the if-statement. Any ideas how to make this work?
As Vladimir pointed out, you can't do it directly that way in Fortran, unless you use function pointers. Below you find an according example.
I made it simple by using integer operations only. Also note, that I assumed that the operations in your expression are executed from left to right (no precedence rules), otherwise the algorithm would be much more complicated. If precedence matters, you should think about using an interpreted language for the task (unless execution speed is cruical).
Here is the module defining the operations and a type containing procedure pointers:
module myfuncs
implicit none
abstract interface
function binary(i1, i2)
integer, intent(in) :: i1, i2
integer :: binary
end function binary
end interface
type :: procptr
procedure(binary), pointer, nopass :: ptr
end type procptr
contains
function add(i1, i2) result(res)
integer, intent(in) :: i1, i2
integer :: res
res = i1 + i2
end function add
function mul(i1, i2) result(res)
integer, intent(in) :: i1, i2
integer :: res
res = i1 * i2
end function mul
function sub(i1, i2) result(res)
integer, intent(in) :: i1, i2
integer :: res
res = i1 - i2
end function sub
function div(i1, i2) result(res)
integer, intent(in) :: i1, i2
integer :: res
res = i1 / i2
end function div
end module myfuncs
Here is the main program with the brute force search:
program bruteforce
use myfuncs
type(procptr) :: ops(4)
character :: opnames(4)
integer :: val1, val2, val3, res, myres
val1 = 1
val2 = 2
val3 = 3
res = 7
ops(1)%ptr => add
ops(2)%ptr => sub
ops(3)%ptr => mul
ops(4)%ptr => div
opnames = [ "+", "-", "*", "/" ]
lpi: do ii = 1, 4
lpj: do jj = 1, 4
myres = ops(jj)%ptr(ops(ii)%ptr(val1, val2), val3)
write(*,"(3(I0,1X,A,1X),I0)") val1, opnames(ii), val2, &
&opnames(jj), val3, " = ", myres
if (myres == res) then
write(*,*) "Solution found."
exit lpi
end if
end do lpj
end do lpi
end program bruteforce
This cannot be done in Fortran. What type did you declare for op? There isn't any that would fit. One thing you could do is to define some functions and store function pointers to them.