Segmentation fault with deferred functions and non_overridable keyword - oop

I am developing an object-oriented Fortran code for numerical optimization with polymorphism supported by abstract types. Because it is a good TDD practice, I'm trying to write all optimization tests in the abstract type class(generic_optimizer), which then should be run by each instantiated class, e.g., by type(newton_raphson).
All the optimization tests feature a call to call my_problem%solve(...), which is defined as deferred in the abstract type and of course features a different implementation in each derived type.
The issue is: if in each non-abstract class I define the deferred function as non_overridable, I get segmentation fault such as:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) where
#0 0x0000000000000000 in ?? ()
#1 0x0000000000913efe in __newton_raphson_MOD_nr_solve ()
#2 0x00000000008cfafa in MAIN__ ()
#3 0x00000000008cfb2b in main ()
#4 0x0000003a3c81ed5d in __libc_start_main () from /lib64/libc.so.6
#5 0x00000000004048f9 in _start ()
After some trial-and-error, I've noticed that I can avoid the error if I remove the non_overridable declaration. In this case it is not an issue, but I wanted to enforce that since two levels of polymorphism are unlikely for this code. Was I violating any requirements from the standard, instead?
Here is a sample code that reproduces the error. I've been testing it with gfortran 5.3.0 and 6.1.0.
module generic_type_module
implicit none
private
type, abstract, public :: generic_type
real(8) :: some_data
contains
procedure (sqrt_interface), deferred :: square_root
procedure, non_overridable :: sqrt_test
end type generic_type
abstract interface
real(8) function sqrt_interface(this,x) result(sqrtx)
import generic_type
class(generic_type), intent(in) :: this
real(8), intent(in) :: x
end function sqrt_interface
end interface
contains
subroutine sqrt_test(this,x)
class(generic_type), intent(in) :: this
real(8), intent(in) :: x
print *, 'sqrt(',x,') = ',this%square_root(x)
end subroutine sqrt_test
end module generic_type_module
module actual_types_module
use generic_type_module
implicit none
private
type, public, extends(generic_type) :: crashing
real(8) :: other_data
contains
procedure, non_overridable :: square_root => crashing_square_root
end type crashing
type, public, extends(generic_type) :: working
real(8) :: other_data
contains
procedure :: square_root => working_square_root
end type working
contains
real(8) function crashing_square_root(this,x) result(sqrtx)
class(crashing), intent(in) :: this
real(8), intent(in) :: x
sqrtx = sqrt(x)
end function crashing_square_root
real(8) function working_square_root(this,x) result(sqrtx)
class(working), intent(in) :: this
real(8), intent(in) :: x
sqrtx = sqrt(x)
end function working_square_root
end module actual_types_module
program deferred_test
use actual_types_module
implicit none
type(crashing) :: crashes
type(working) :: works
call works%sqrt_test(2.0_8)
call crashes%sqrt_test(2.0_8)
end program

To narrow down the problem, I removed the abstract attribute and data members from the OP's code such that
module types
implicit none
type :: Type1
contains
procedure :: test
procedure :: square => Type1_square
endtype
type, extends(Type1) :: Type2
contains
procedure, non_overridable :: square => Type2_square
endtype
contains
subroutine test( this, x )
class(Type1) :: this
real :: x
print *, "square(", x, ") = ",this % square( x )
end subroutine
function Type1_square( this, x ) result( y )
class(Type1) :: this
real :: x, y
y = -100 ! dummy
end function
function Type2_square( this, x ) result( y )
class(Type2) :: this
real :: x, y
y = x**2
end function
end module
program main
use types
implicit none
type(Type1) :: t1
type(Type2) :: t2
call t1 % test( 2.0 )
call t2 % test( 2.0 )
end program
With this code, gfortran-6 gives
square( 2.00000000 ) = -100.000000
square( 2.00000000 ) = -100.000000
while ifort-{14,16} and Oracle fortran 12.5 give
square( 2.000000 ) = -100.0000
square( 2.000000 ) = 4.000000
I also tried replacing the functions with subroutines (to print which routines are actually called):
subroutine test( this, x )
class(Type1) :: this
real :: x, y
call this % square( x, y )
print *, "square(", x, ") = ", y
end subroutine
subroutine Type1_square( this, x, y )
class(Type1) :: this
real :: x, y
print *, "Type1_square:"
y = -100 ! dummy
end subroutine
subroutine Type2_square( this, x, y )
class(Type2) :: this
real :: x, y
print *, "Type2_square:"
y = x**2
end subroutine
with all the other parts kept the same. Then, gfortran-6 gives
Type1_square:
square( 2.00000000 ) = -100.000000
Type1_square:
square( 2.00000000 ) = -100.000000
while ifort-{14,16} and Oracle fortran 12.5 give
Type1_square:
square( 2.000000 ) = -100.0000
Type2_square:
square( 2.000000 ) = 4.000000
If I remove non_overridable from the above codes, gfortran gives the same result as the other compilers. So, this may be a specific issue to gfortran + non_overridable (if the above code is standard-conforming)...
(The reason why OP got segmentation fault may be that gfortran accessed the deferred procedure in the parent type (generic_type) having null pointer; if this is the case, the story becomes consistent.)
Edit
The same exceptional behavior of gfortran occurs also when we declare Type1 as abstract. Specifically, if we change the definition of Type1 as
type, abstract :: Type1 ! now an abstract type (cannot be instantiated)
contains
procedure :: test
procedure :: square => Type1_square
endtype
and the main program as
program main
use types
implicit none
type(Type2) :: t2
call t2 % test( 2.0 )
end program
we get
ifort-16 : square( 2.000000 ) = 4.000000
oracle-12.5 : square( 2.0 ) = 4.0
gfortran-6 : square( 2.00000000 ) = -100.000000
If we further make square() in Type1 to be deferred (i.e., no implementation given) and so make the code almost equivalent to the OP's case,
type, abstract :: Type1 ! now an abstract type (cannot be instantiated)
contains
procedure :: test
procedure(Type1_square), deferred :: square ! has no implementation yet
endtype
abstract interface
function Type1_square( this, x ) result( y )
import
class(Type1) :: this
real :: x, y
end function
end interface
then ifort-16 and Oracle-12.5 gives 4.0 with call t2 % test( 2.0 ), while gfortran-6 results in segmentation fault. Indeed, if we compile as
$ gfortran -fsanitize=address test.f90 # on Linux x86_64
we get
ASAN:SIGSEGV (<-- or "ASAN:DEADLYSIGNAL" on OSX 10.9)
=================================================================
==22045==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000
(pc 0x000000000000 bp 0x7fff1d23ecd0 sp 0x7fff1d23eac8 T0)
==22045==Hint: pc points to the zero page.
So overall, it seems as if the binding name square() in Type1 (which has no implementation) is called erroneously by gfortran (possibly with null pointer). And more importantly, if we drop non_overridable from the definition of Type2, gfortran also gives 4.0 (with no segmentation fault).

Related

Fortran "undefined reference to [function]" error that goes away by compiling the .f90 files directly

Before someone closes the question, yes, there are many questions that seem similar, but so far I haven't found one with this exact weird problem that seems to go away only sometimes.
I had an odd Fortran error while trying to make a module for linear regression.
The module is named "LSQregression" and the main program "LSQAdvertising". Compiling it using the following gfortran command works:
gfortran ../LSQregression.f90 LinearAdvertising.f90 -llapack -o LinAd
However, I'd like to be able to turn my module into a .o file and link it with whatever program I may need instead of compiling again every time. So I tried to do that:
gfortran -c ../LSQregression.f90
And then link it with my program file like that:
gfortran ../LSQregression.o LinearAdvertising.f90 -llapack -o LinAd
I also tried also turning the program into a .o file. Neither works, they both return the following error:
/usr/bin/ld: /tmp/ccf7T1aj.o: in function `MAIN__':
LinearAdvertising.f90:(.text+0x1f8b): undefined reference to `__lsqregression_MOD_lsqestimate_simple'
collect2: error: ld returned 1 exit status
It refers to the following function in the module that is being called here inside the program:
print *, LSQestimate(test,LSQbeta(inputs,sales,(/1,2/)) )
The function itself is defined as part of an interface:
interface LSQestimate
procedure LSQestimate_simple, LSQestimate_using
end interface LSQestimate
real(8) function LSQestimate_simple(X, beta)
implicit none
real(8), dimension(:,:) :: X, beta
real(8) :: boundary, Y
integer :: i, Xlen, betalen
Xlen = size(X, 1)
betalen = size(beta, 1)
if (Xlen + 1 .ne. betalen) stop "incompatible beta and X"
Y = beta(1,1)
do i = 1, Xlen
Y = Y + beta(i+1, 1)*X(i,1)
end do
LSQestimate_simple = Y
end function LSQestimate_simple
It's very odd because I've done the same thing with another function and it seems to work fine, and the problem only happens when I turn the module into a .o file first, and goes away if I try to directly compile the .f90 file... I can't figure out why one works and the other doesn't.
EDIT: Someone told me to do nm ../LSQregression.o | grep -i regression . I have no idea what that does but I did it so here are the results if it helps at all:
0000000000002768 T __lsqregression_MOD_inv
0000000000000b85 T __lsqregression_MOD_lsqbeta_simple
000000000000035c T __lsqregression_MOD_lsqbeta_using
0000000000000000 T __lsqregression_MOD_lsqdecision
Oddly enough the name of the function in question doesn't even appear here.
EDIT 2: Decided to post the entire code of the module:
module LSQregression
implicit none
public :: LSQbeta, LSQestimate
interface LSQbeta
procedure LSQbeta_simple, LSQbeta_using
end interface LSQbeta
interface LSQestimate
procedure LSQestimate_simple, LSQestimate_using
end interface LSQestimate
contains
function inv(A) result(Ainv)
implicit none
real(8), dimension(:,:), intent(in) :: A
real(8), dimension(size(A,1),size(A,2)) :: Ainv
real(8), dimension(size(A,1)) :: work ! work array for LAPACK
integer, dimension(size(A,1)) :: ipiv ! pivot indices
integer :: n, info
! External procedures defined in LAPACK
external DGETRF
external DGETRI
! Store A in Ainv to prevent it from being overwritten by LAPACK
Ainv = A
n = size(A,1)
! DGETRF computes an LU factorization of a general M-by-N matrix A
! using partial pivoting with row interchanges.
call DGETRF(n, n, Ainv, n, ipiv, info)
if (info /= 0) then
stop 'Matrix is numerically singular!'
end if
! DGETRI computes the inverse of a matrix using the LU factorization
! computed by DGETRF.
call DGETRI(n, Ainv, n, ipiv, work, n, info)
if (info /= 0) then
stop 'Matrix inversion failed!'
end if
end function inv
!----------------------------------------------------------------------
function LSQbeta_simple(Xold, Y) result(beta)
real(8), dimension(:,:) :: Xold, Y
real(8), dimension(size(Xold,1), size(Xold,2)+1) :: X
real(8), dimension(:,:), allocatable :: beta, XTX, IXTX, pinv
integer :: rowsX, colsX, rowsY, colsY,i
rowsX = size(X(:,1))
colsX = size(X(1,:))
rowsY = size(Y(:,1))
colsY = size(Y(1,:))
if (colsY .ne. 1) stop 'Inappropriate y'
if (rowsY .ne. rowsX) stop "Y and X rows don't match"
!---X-ify-----------
X(:,1) = 1.0 !includes 1 in the first column
do i = 2, colsX
X(:,i) = Xold(:,i-1)
end do
!--------------------
allocate(XTX(colsX,colsX))
allocate(IXTX(colsX,colsX))
allocate(pinv(colsX,rowsY))
allocate(beta(colsX,1))
XTX = matmul(transpose(X),X)
IXTX = inv(XTX)
pinv = matmul(IXTX, transpose(X))
beta = matmul(pinv, Y)
deallocate(pinv)
deallocate(XTX)
deallocate(IXTX)
return
deallocate(beta)
end function LSQbeta_simple
!--------------------------------------------
function LSQbeta_using(Xold, Y, indexes) result(beta)
implicit none
real(8), dimension(:,:) :: Xold, Y
integer, dimension(:) :: indexes
real(8), dimension(size(indexes)+1,1) :: beta
real(8), dimension(size(Xold,1),size(indexes)) :: X
integer :: indLen,i
indLen = size(indexes)
do i = 1, indLen
X(:,i) = Xold(:,indexes(i))
end do
beta = LSQbeta_simple(X,Y)
end function LSQbeta_using
real(8) function LSQestimate_simple(X, beta)
implicit none
real(8), dimension(:,:) :: X, beta
real(8) :: boundary, Y
integer :: i, Xlen, betalen
Xlen = size(X, 1)
betalen = size(beta, 1)
if (Xlen + 1 .ne. betalen) stop "incompatible beta and X"
Y = beta(1,1)
do i = 1, Xlen
Y = Y + beta(i+1, 1)*X(i,1)
end do
LSQestimate_simple = Y
end function LSQestimate_simple
real(8) function LSQestimate_using()
LSQestimate_using = 1.0D0
end function LSQestimate_using
logical function LSQdecision(X, beta, boundary)
implicit none
real(8), dimension(:,:) :: X, beta
real(8) :: boundary
LSQdecision = LSQestimate(X, beta) > boundary
end function LSQdecision
end module LSQregression

Definition of operator(+) with multiple addends in Fortran with derived type. An issue with allocatable array

I am trying to define the (+) operator between Fortran derived types that describe matrices (linear operators).
My goal is to implicitly define a matrix M = M1 + M2 + M3 such that, given a vector x, Mx = M1x + M2x + M3x.
First, I defined an abstract type (abs_linop) with the abstract interface for a matrix vector multiplication (y = M *x).
Then, I built an derived type (add_linop), extending the abstract type (abs_linop).
The operator (+) is defined for the type (add_linop). I then create an example of concrete type (eye) extending the abstract type (abs_linop) that describes the identity matrix. This type is used in the main program. This is the source code
module LinearOperator
implicit none
private
public :: abs_linop,multiplication
type, abstract :: abs_linop
integer :: nrow=0
integer :: ncol=0
character(len=20) :: name='empty'
contains
!> Procedure for computation of (matrix) times (vector)
procedure(multiplication), deferred :: Mxv
end type abs_linop
abstract interface
!>-------------------------------------------------------------
!> Abstract procedure defining the interface for a general
!<-------------------------------------------------------------
subroutine multiplication(this,vec_in,vec_out,info,lun_err)
import abs_linop
implicit none
class(abs_linop), intent(inout) :: this
real(kind=8), intent(in ) :: vec_in(this%ncol)
real(kind=8), intent(inout) :: vec_out(this%nrow)
integer, optional, intent(inout) :: info
integer, optional, intent(in ) :: lun_err
end subroutine multiplication
end interface
!>---------------------------------------------------------
!> Structure variable for Identity matrix
!> (rectangular case included)
!>---------------------------------------------------------
type, extends(abs_linop), public :: eye
contains
!> Static constructor
procedure, public, pass :: init => init_eye
!> Compute matrix times vector operatoration
procedure, public, pass :: Mxv => apply_eye
end type eye
!>----------------------------------------------------------------
!> Structure variable to build implicit matrix defined
!> as composition and sum of linear operator
!>----------------------------------------------------------------
public :: add_linop, operator(+)
type, extends(abs_linop) :: add_linop
class(abs_linop) , pointer :: matrix_1
class(abs_linop) , pointer :: matrix_2
real(kind=8), allocatable :: scr(:)
contains
procedure, public , pass:: Mxv => add_Mxv
end type add_linop
INTERFACE OPERATOR (+)
module PROCEDURE mmsum
END INTERFACE OPERATOR (+)
contains
!>------------------------------------------------------
!> Function that give two linear operator A1 and A2
!> defines, implicitely, the linear operator
!> A=A1+A2
!> (public procedure for class add_linop)
!>
!> usage:
!> 'var' = A1 + A2
!<-------------------------------------------------------------
function mmsum(matrix_1,matrix_2) result(this)
implicit none
class(abs_linop), target, intent(in) :: matrix_1
class(abs_linop), target, intent(in) :: matrix_2
type(add_linop) :: this
! local
integer :: res
character(len=20) :: n1,n2
if (matrix_1%nrow .ne. matrix_2%nrow) &
write(*,*) 'Error mmproc dimension must agree '
if (matrix_1%ncol .ne. matrix_2%ncol) &
write(*,*) 'Error mmproc dimension must agree '
this%matrix_1 => matrix_1
this%matrix_2 => matrix_2
this%nrow = matrix_1%nrow
this%ncol = matrix_2%ncol
this%name=etb(matrix_1%name)//'+'//etb(matrix_2%name)
write(*,*) 'Sum Matrix initialization '
write(*,*) 'M1 : ',this%matrix_1%name
write(*,*) 'M2 : ',this%matrix_2%name
write(*,*) 'sum : ',this%name
allocate(this%scr(this%nrow),stat=res)
contains
function etb(strIn) result(strOut)
implicit none
! vars
character(len=*), intent(in) :: strIn
character(len=len_trim(adjustl(strIn))) :: strOut
strOut=trim(adjustl(strIn))
end function etb
end function mmsum
recursive subroutine add_Mxv(this,vec_in,vec_out,info,lun_err)
implicit none
class(add_linop), intent(inout) :: this
real(kind=8), intent(in ) :: vec_in(this%ncol)
real(kind=8), intent(inout) :: vec_out(this%nrow)
integer, optional, intent(inout) :: info
integer, optional, intent(in ) :: lun_err
write(*,*) 'Matrix vector multipliction',&
'matrix:',this%name,&
'M1: ',this%matrix_1%name,&
'M2: ',this%matrix_2%name
select type (mat=>this%matrix_1)
type is (add_linop)
write(*,*) 'is allocated(mat%scr) ?', allocated(mat%scr)
end select
call this%matrix_1%Mxv(vec_in,this%scr,info=info,lun_err=lun_err)
call this%matrix_2%Mxv(vec_in,vec_out,info=info,lun_err=lun_err)
vec_out = this%scr + vec_out
end subroutine add_Mxv
subroutine init_eye(this,nrow)
implicit none
class(eye), intent(inout) :: this
integer, intent(in ) :: nrow
this%nrow = nrow
this%ncol = nrow
end subroutine init_eye
subroutine apply_eye(this,vec_in,vec_out,info,lun_err)
class(eye), intent(inout) :: this
real(kind=8), intent(in ) :: vec_in(this%ncol)
real(kind=8), intent(inout) :: vec_out(this%nrow)
integer, optional, intent(inout) :: info
integer, optional, intent(in ) :: lun_err
! local
integer :: mindim
vec_out = vec_in
if (present(info)) info=0
end subroutine apply_eye
end module LinearOperator
program main
use LinearOperator
implicit none
real(kind=8) :: x(2),y(2),z(2),t(2)
type(eye) :: id1,id2,id3
type(add_linop) :: sum12,sum23,sum123_ok,sum123_ko
integer :: i
call id1%init(2)
id1%name='I1'
call id2%init(2)
id2%name='I2'
call id3%init(2)
id3%name='I3'
x=1.0d0
y=1.0d0
z=1.0d0
write(*,*) ' Vector x =', x
call id1%Mxv(x,t)
write(*,*) ' Vector t = I1 *x', t
write(*,*) ' '
sum12 = id1 + id2
call sum12%Mxv(x,t)
write(*,*) ' Vector t = (I1 +I2) *x', t
write(*,*) ' '
sum23 = id2 + id3
sum123_ok = id1 + sum23
call sum123_ok%Mxv(x,t)
write(*,*) ' Vector t = ( I1 + (I2 + I3) )*x', t
write(*,*) ' '
sum123_ko = id1 + id2 + id3
call sum123_ko%Mxv(x,t)
write(*,*) ' Vector t = ( I1 +I2 + I3) *x', t
end program main
I compile this code with gfortran version 7.5.0 and flags
"-g -C -Wall -fcheck=all -O -ffree-line-length-none -mcmodel=medium "
and this is what I get
Vector x = 1.0000000000000000 1.0000000000000000
Vector t = I1 *x 1.0000000000000000 1.0000000000000000
Sum Matrix initialization
M1 : I1
M2 : I2
sum : I1+I2
Matrix vector multiplictionmatrix:I1+I2 M1: I1 M2: I2
Vector t = (I1 +I2) *x 2.0000000000000000 2.0000000000000000
Sum Matrix initialization
M1 : I2
M2 : I3
sum : I2+I3
Sum Matrix initialization
M1 : I1
M2 : I2+I3
sum : I1+I2+I3
Matrix vector multiplictionmatrix:I1+I2+I3 M1: I1 M2: I2+I3
Matrix vector multiplictionmatrix:I2+I3 M1: I2 M2: I3
Vector t = ( I1 + (I2 + I3) )*x 3.0000000000000000 3.0000000000000000
Sum Matrix initialization
M1 : I1
M2 : I2
sum : I1+I2
Sum Matrix initialization
M1 : I1+I2
M2 : I3
sum : I1+I2+I3
Matrix vector multiplictionmatrix:I1+I2+I3 M1: I1+I2 M2: I3
is allocated(mat%scr) ? F
Matrix vector multiplictionmatrix:I1+I2 M1: I1 M2: I2
At line 126 of file LinearOperator.f90
Fortran runtime error: Allocatable actual argument &apos;this&apos; is not allocated
Everthing works fine when I use the (+) operator with 2 terms. But when 3 terms are used there is an issue with the allocatable array scr, member of type (add_linop), that is not allocated.
Does anybody knows the reason of this issue and how to solve it?
I include the Makefile used for compiling the code.
#Gfortran compiler
FC = gfortran
OPENMP = -fopenmp
MODEL = -mcmodel=medium
OFLAGS = -O5 -ffree-line-length-none
DFLAGS = -g -C -Wall -fcheck=all -O -ffree-line-length-none
#DFLAGS = -g -C -Wall -ffree-line-length-none -fcheck=all
PFLAGS = -pg
CPPFLAGS = -D_GFORTRAN_COMP
ARFLAGS =
ODIR = objs
MDIR = mods
LDIR = libs
INCLUDE = -J$(MODDIR)
OBJDIR = $(CURDIR)/$(ODIR)
MODDIR = $(CURDIR)/$(MDIR)
LIBDIR = $(CURDIR)/$(LDIR)
INCLUDE += -I$(MODDIR)
FFLAGS = $(OFLAGS) $(MODEL) $(INCLUDE)
LIBSRCS =
DEST = .
EXTHDRS =
HDRS =
LIBS = -llapack -lblas
LIBMODS =
LDFLAGS = $(MODEL) $(INCLUDE) -L. -L/usr/lib -L/usr/local/lib -L$(LIBDIR)
LINKER = $(FC)
MAKEFILE = Makefile
PRINT = pr
CAT = cat
PROGRAM = main.out
SRCS = LinearOperator.f90
OBJS = LinearOperator.f90
PRJS= $(SRCS:jo=.prj)
OBJECTS = $(SRCS:%.f90=$(OBJDIR)/%.o)
MODULES = $(addprefix $(MODDIR)/,$(MODS))
.SUFFIXES: .prj .f90
print-% :
#echo $* = $($*)
.f.prj:
ftnchek -project -declare -noverbose $<
.f90.o:
$(FC) $(FFLAGS) $(INCLUDE) -c $<
all::
#make dirs
#make $(PROGRAM)
$(PROGRAM): $(LIBS) $(MODULES) $(OBJECTS)
$(LINKER) -o $(PROGRAM) $(LDFLAGS) $(OBJECTS) $(LIBS)
$(LIBS):
#set -e; for i in $(LIBSRCS); do cd $$i; $(MAKE) --no-print-directory -e CURDIR=$(CURDIR); cd $(CURDIR); done
$(OBJECTS): $(OBJDIR)/%.o: %.f90
$(FC) $(CPPFLAGS) $(FFLAGS) -o $# -c $<
dirs:
#-mkdir -p $(OBJDIR) $(MODDIR) $(LIBDIR)
clean-emacs:
#-rm -f $(CURDIR)/*.*~
#-rm -f $(CURDIR)/*\#*
check: $(PRJS)
ftnchek -noverbose -declare $(PRJS) -project -noextern -library > $(PROGRAM).ftn
profile:; #make "FFLAGS=$(PFLAGS) $(MODEL) " "CFLAGS=$(PFLAGS) $(MODEL)" "LDFLAGS=$(PFLAGS) $(LDFLAGS)" $(PROGRAM)
debug:; #make "FFLAGS=$(DFLAGS) $(MODEL) $(INCLUDE)" "LDFLAGS=$(DFLAGS) $(LDFLAGS)" $(PROGRAM)
openmp:; #make "FFLAGS=$(OFLAGS) $(OPENMP) $(MODEL) $(INCLUDE)" "LDFLAGS=$(LDFLAGS) $(OPENMP)" $(PROGRAM)
clean:; #rm -f $(OBJECTS) $(MODULES) $(PROGRAM).cat $(PROGRAM).ftn
#set -e; for i in $(LIBSRCS); do cd $$i; $(MAKE) --no-print-directory clean; cd $(CURDIR); done
clobber:; #rm -f $(OBJECTS) $(MODULES) $(PROGRAM).cat $(PROGRAM).ftn $(PROGRAM)
#-rm -rf $(OBJDIR) $(MODDIR) $(LIBDIR)
#-rm -f $(CURDIR)/*.*~
#-rm -f $(CURDIR)/*\#*
.PHONY: mods
index:; ctags -wx $(HDRS) $(SRCS)
install: $(PROGRAM)
install -s $(PROGRAM) $(DEST)
print:; $(PRINT) $(HDRS) $(SRCS)
cat:; $(CAT) $(HDRS) $(SRCS) > $(PROGRAM).cat
program: $(PROGRAM)
profile: $(PROFILE)
tags: $(HDRS) $(SRCS); ctags $(HDRS) $(SRCS)
update: $(DEST)/$(PROGRAM)
main.o: linearoperator.mod
# DO NOT EDIT --- auto-generated file
linearoperator.mod : LinearOperator.f90
$(FC) $(FCFLAGS) -c $<
Your program is not valid Fortran.
The function result of mmsum has a pointer component which, during the execution of the function, is pointer associated with a dummy argument. This dummy argument (correctly for this use) has the target attribute. However, the actual argument does not have the target attribute: when the function execution completes the pointer component becomes of undefined pointer association status.
In the subroutine add_Mxv there is an attempt to dereference this pointer. This is not allowed.
It will be necessary to revisit how the operands are handled in your data type. Note in particular that an expression cannot have the target attribute: in the case of id1+id2+id3 the id1+id2 expression won't usefully remain as something to reference later on.

expressing properties of inductive datatypes in Dafny

I defined a sigma algebra datatype in Dafny, as shown below:
datatype Alg = Empty | Complement(a: Alg) | Union(b: Alg, c: Alg) | Set(s: set<int>)
class test {
var S : set<int>
function eval(X: Alg) : set<int> // evaluates an algebra
reads this;
decreases X;
{
match X
case Empty => {}
case Complement(a) => S - eval(X.a)
case Union(b,c) => eval(X.b) + eval(X.c)
case Set(s) => X.s
}
}
I want to state properties that quantify over the inductive datatype. Is it possible to express properties like this?
Here is an example of what I have tried:
lemma algebra()
ensures exists x :: x in Alg ==> eval(x) == {};
ensures forall x :: x in Alg ==> eval(x) <= S;
ensures forall x :: x in Alg ==> exists y :: y in Alg && eval(y) == S - eval(x);
ensures forall b,c :: b in Alg && c in Alg ==> exists d :: d in Alg && eval(d) == eval(b) + eval(c);
But I get the error message:
second argument to "in" must be a set, multiset, or sequence with
elements of type Alg, or a map with domain Alg
I want to state properties like: "there exists an algebra such that ...", or "for all algebras ...".
A type is not the same as a set in Dafny. You want to express the quantifiers in your lemmas as follows:
lemma algebra()
ensures exists x: Alg :: eval(x) == {}
ensures forall x: Alg :: eval(x) <= S
ensures forall x: Alg :: exists y: Alg :: eval(y) == S - eval(x)
ensures forall b: Alg, c: Alg :: exists d: Alg :: eval(d) == eval(b) + eval(c)
In the same way, you can declare a variable x to have type int, but you don't write x in int.
Because of type inference, you don't have to write : Alg explicitly. You can just write:
lemma algebra()
ensures exists x :: eval(x) == {}
ensures forall x :: eval(x) <= S
ensures forall x :: exists y :: eval(y) == S - eval(x)
ensures forall b, c :: exists d :: eval(d) == eval(b) + eval(c)
Another comment on the example: You're defining mathematics here. When you do, it's usually a good idea to stay away from the imperative features like classes, methods, and mutable fields. You don't need such features and they just complicate the mathematics. Instead, I suggest removing the class, changing the declaration of S to be a const, and removing the reads clause. That gives you:
datatype Alg = Empty | Complement(a: Alg) | Union(b: Alg, c: Alg) | Set(s: set<int>)
const S: set<int>
function eval(X: Alg): set<int> // evaluates an algebra
decreases X
{
match X
case Empty => {}
case Complement(a) => S - eval(X.a)
case Union(b,c) => eval(X.b) + eval(X.c)
case Set(s) => X.s
}
lemma algebra()
ensures exists x :: eval(x) == {}
ensures forall x :: eval(x) <= S
ensures forall x :: exists y :: eval(y) == S - eval(x)
ensures forall b, c :: exists d :: eval(d) == eval(b) + eval(c)
Rustan

How to make a matrix where its elements are functions, operate with them and the result still be a function?

I'm using Fortran I'm trying to create matrices where their elements are functions. Also I'd like to operate with them and the result still be a function. So here is what I try
module Greeninverse
use, intrinsic :: iso_fortran_env, only: dp => real64
implicit none
real(dp), public, parameter :: wl = 1d0
real(dp), public, parameter :: wr = 1d0
integer, public, parameter :: matrix_size = 5
type ptr_wrapper
procedure(f), nopass, pointer :: func
end type ptr_wrapper
abstract interface
function f(x1,x2)
import
real(dp), intent(in) :: x1
real(dp), intent(in) :: x2
complex (dp), dimension(matrix_size,matrix_size):: f
end function f
end interface
contains
function Sigma(x1) result(S)
real(dp),intent(in) :: x1
complex(dp), dimension(matrix_size,matrix_size) :: S
real(dp):: aux_wr1,aux_wl1
complex(dp) :: S11, Snn
integer :: i,j
aux_wr1 = 1-x1**2/(2d0*wr)
aux_wl1 = 1-x1**2/(2d0*wl)
S11 = dcmplx(.5*(x1**2-2d0*wl), 2.0*wL*dsqrt(1-aux_wL1**2))
Snn = dcmplx(.5*(x1**2-2d0*wr), 2.0*wr*dsqrt(1-aux_wr1**2))
do i = 1, matrix_size
do j=i,matrix_size
S(i,j) = 0d0
S(j,i) = 0d0
end do
end do
S(1,1) = S11
S(matrix_size,matrix_size) = Snn
end function Sigma
function Omega(x1) result(Om)
real(dp),intent(in) :: x1
real(dp),dimension(matrix_size, matrix_size) :: Om
integer :: i,j
do i=1,matrix_size
do j= i, matrix_size
Om(i,j) = 0d0
Om(j,i) = 0d0
end do
end do
do i = 1,matrix_size
Om(i,i) = x1**2
end do
end function Omega
! Now I'd like to add them and take the inverse of the sum and still be a function
function Inversa(x1,x2) result (G0inv)
real(dp), intent(in) :: x1
real(dp), intent(in) :: x2
complex(dp), dimension(matrix_size,matrix_size) :: G0inv
complex(dp),dimension(matrix_size,matrix_size) :: Gaux
! Down here all these variables are needed by ZGETRF and ZGETRI
DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:) :: WORK
Integer:: LWORK = matrix_size*matrix_size
Integer, Allocatable, dimension(:) :: IPIV
Integer :: INFO, LDA = matrix_size, M = matrix_size, N = matrix_size
Integer DeAllocateStatus
external liblapack
allocate(work(Lwork))
allocate(IPIV(N))
Gaux = Omega(x1)+Sigma(x2)
CALL ZGETRF (M, N, Gaux, LDA, IPIV, INFO)
! This calculates LU descomposition of a matrix and overwrites it
CALL ZGETRI(N, Gaux, N, IPIV, WORK, LWORK, INFO)
! This calculates the inverse of a matrix knowing its LU descomposition and overwrites it
G0inv = Gaux
end function Inversa
! Now I'd like to derive it
function Derivate(x1,x2,G) result(d)
! This function is supposed to derivate a matrix which its elements are functions but of two variables; x1 and x2. And it only derives respect the first variable
implicit none
real(dp), intent(in) :: x1
real(dp), intent(in) :: x2
procedure(f),pointer:: G
complex(dp),dimension(matrix_size,matrix_size) :: d
real(dp) :: h = 1.0E-6
d = (1.0*G(x1-2*h,x2) - 8.0*G(x1-h,x2) + 8.0*G(x1+h,x2) - 1.0*G(x1+2*h,x2))/(12.0*h)
end function Derivate
end module Greeninverse
program Greentest3
use, intrinsic :: iso_fortran_env, only: dp => real64
use Greeninverse
implicit none
real(dp) :: W(matrix_size,matrix_size)
complex(dp) :: S(matrix_size,matrix_size)
complex(dp) :: G(matrix_size,matrix_size)
complex(dp) :: DD(matrix_size,matrix_size)
W(:,:) = Omega(1d0)
S(:,:) = Sigma(2d0)
G(:,:) = Inversa(1d0,2d0)
DD(:,:) = Derivate(1d0,2d0,Inversa)
print*, W
print*, S
print*, G
print*, DD
end program Greentest3
The problem is in the function Derivate that I don't know how to say that the argument G is a matrix function and because of that I get an error message
DD(:,:) = Derivate(1d0,2d0,Inversa)
1
Error: Expected a procedure pointer for argument ā€˜gā€™ at (1)
That's why I use the abstract interface that it's supposed to say that is a function but it doesn't work as I expected
I tried also to make a pointer in the module section, that is
type(ptr_wrapper) :: DD(matrix_size,matrix_size)
but I get an error message
Error: Unexpected data declaration statement in CONTAINS section at (1)
I'd like to make all the matrices in the module section and in the program just evaluate them in the values of interest.
What am I doing wrong?
Looking at the function Derivate the dummy argument G is declared like
procedure(f), pointer:: G
This is a procedure pointer. The error message confirms that.
The actual argument to be passed to Derivate is, in this case, expected also to be a procedure pointer. Let's look at what the argument is:
DD(:,:) = Derivate(...,Inversa)
Inversa is a procedure (function), defined in the module. It, crucially, isn't a procedure pointer. So, indeed, the compiler complains.
Well, how do we go about fixing this? There are three obvious approaches:
have the actual argument a procedure pointer;
have the dummy argument a procedure (non-pointer);
allow argument association between a pointer and non-pointer.
For the first, the main program could have
procedure(f), pointer :: Inversa_ptr ! We've a procedure pointer...
Inversa_ptr => Inversa ! ... which we point at our procedure...
DD(:,:) = Derivate(...,Inversa_ptr) ! ... and is then the argument
For the Derivate as it is implemented, it doesn't use the pointer nature of the argument G: just the target is referenced. This means that the other two options become available.
We can make the dummy argument not a pointer, having
function Derivate(...,G)
procedure(f) :: G
end function
used like
DD(:,:) = Derivate(...,Inversa)
The third of our choices comes from defining the dummy argument as
function Derivate(...,G)
procedure(f), pointer, intent(in) :: G
end function
where, again, the reference is as in the second case.
When the dummy argument procedure pointer has the intent(in) attribute, it is allowed to be associated with a non-pointer procedure which is a valid target in pointer assignment. In this case G becomes pointer associated with that actual argument procedure (and because of the intent, that status can't be changed in the function).

Simple Haskell IORef - "Couldn't match type `IO Int' with `Int'" - can't see how it's different

I'm trying to make a simple random number generator in Haskell using IORef now to store mutable variables. The idea is that I can initialise the seed, and then generate numbers based on the seed, and store the new seed for the next random int.
The full error I'm getting is:
random2.hs:9:17:
Couldn't match type `IO Int' with `Int'
Expected type: IO (IORef Integer)
-> (IORef Integer -> IO Int) -> Int
Actual type: IO (IORef Integer)
-> (IORef Integer -> IO Int) -> IO Int
In a stmt of a 'do' block: seed <- newIORef 7
In the expression:
do { seed <- newIORef 7;
randomGen (readIORef seed) }
In an equation for `getRandom':
getRandom
= do { seed <- newIORef 7;
randomGen (readIORef seed) }
random2.hs:10:17:
Couldn't match type `(,) Int' with `IO'
Expected type: IO Int
Actual type: (Int, Int)
In the return type of a call of `randomGen'
In a stmt of a 'do' block: randomGen (readIORef seed)
In the expression:
do { seed <- newIORef 7;
randomGen (readIORef seed) }
random2.hs:10:28:
Couldn't match expected type `Int' with actual type `IO Integer'
In the return type of a call of `readIORef'
In the first argument of `randomGen', namely `(readIORef seed)'
In a stmt of a 'do' block: randomGen (readIORef seed)
Failed, modules loaded: none.
I don't understand how it can not be matching the type - I'm explicit that the randomGen takes/returns an Int. Here's my code:
module Main where
import Data.IORef
randomGen :: Int -> (Int, Int)
randomGen x = (x,x+1)
getRandom :: Int
getRandom = do
seed <- newIORef 7
randomGen (readIORef seed)
Any idea what's going on here?
Thanks,
Updated code:
module Main where
import Data.IORef
import Control.Monad
randomGen :: Int -> (Int, Int)
randomGen x = (x,x+1)
getRandom :: IO Int
getRandom = do
seed <- newIORef 7
liftM (fst (randomGen (readIORef seed)))
The types IO Int and Int are entirely different in Haskell. This applies to any other type of that form, like Maybe Int or Either String Int. This is part of Haskell's type system design that makes it so powerful. You can think of anything in this form as a sort of container, it's parametrized over that type. Therefore you can do something like
getRandom :: IO Int
getRandom = do
seed <- newIORef 7 -- IO (IORef Int)
g <- readIORef seed -- IO Int
let (x, newG) = randomGen g -- (Int, Int)
writeIORef seed newG -- IO ()
return x -- IO Int
However, this will always return the same value since the seed is discarded after every call. I'm curious as to why you want to take this approach to generating random numbers at all, since there is such a nice API in the MonadRandom package. See this answer I wrote a while back for an example of how to use the Rand monad, and this answer for a bit more of an in depth explanation of how it works.
Try:
module Main where
import Data.IORef
import Control.Monad
import Data.Tuple(fst,snd)
randomGen :: Int -> (Int, Int)
randomGen x = (x,x+1)
getRandom :: IO Int -> IO (Int,Int)
getRandom x = do
y <- x
seed <- newIORef y
liftM randomGen $ readIORef seed
At which point, use liftM fst on the output of getRandom to get the random number and liftM snd to get the seed for the next call... Oh and btw System.Random has randoms to generate an infinite list of random numbers (or anything else of Random instance). No point in reinventing the wheel.