Проблем със съответствието възниква при използване на интерфейси с функционални указатели

Започвам тази тема, за да помоля за помощ при разрешаване на проблем, който може да идва от грешната ми спецификация на функционален интерфейс, но не знам как да го поправя.

Съобщението за грешка, на което се натъкнах, е кратко и просто гласи: „Незаконен брой или тип аргументи за lnsrch – аргументите на fmin и func не съвпадат.“

Дефиницията на LNSRCH, FMIN и FUNC ще бъде ясна в съдържанието по-долу.

Оригиналният програмен код е съкратен, за да илюстрира моето намерение, както е показано по-долу. Състои се от три части: основна програмна единица, наречена MAIN, модул, наречен MODEL, и модул, наречен NEWTON). Трябва да можете да възпроизведете съобщението за грешка само като използвате следния файл във формат .f90: връзка

Модул MODEL просто дефинира проста система от уравнения в две променливи --- y(1)=x(1); y(2)=x(2) ---в подпрограмата FUNC_SYSTEM1. Модул MODEL също съдържа абстрактен интерфейс за бъдещо разширение, така че мога просто да накарам показалеца FUNCV да препраща към всяка друга система от уравнения от същия вид като настоящата примерна система от уравнения FUNC_SYSTEM1, с изключение само на броя на променливите на системата от уравнения .

MODULE model                                                             
    IMPLICIT NONE                            
    REAL, DIMENSION(:), POINTER :: fmin_fvecp
    ABSTRACT INTERFACE                              
        FUNCTION function_system_template(x) RESULT(y)     
        REAL, DIMENSION(:), INTENT(IN) :: x     
        REAL, DIMENSION(SIZE(x)) :: y           
        END FUNCTION                                
    END INTERFACE                                   
    PROCEDURE(function_system_template), POINTER :: funcv  
CONTAINS                                                          
    FUNCTION func_system1(x) Result(y)              
    IMPLICIT NONE                             
    REAL, DIMENSION(:), INTENT(IN) :: x   
    REAL, DIMENSION(size(x)) :: y                            
    y(1)=x(1)      
    y(2)=x(2)      
    END FUNCTION func_system1                           
END MODULE model

Модул NEWTON дефинира връзката между три подпрограми, които са ключови за изчисленията на програмата: BROYDEN ще извика FMIN, за да получи сумата от квадратите на x(1) и x(2); едновременно, в FMIN, векторът на x(1) и x(2) се присвоява на указател на масив, наречен FMIN_FVECP. Този указател на масив трябва да се използва за извършване на странични изчисления във функцията LNSRCH.

MODULE newton 
    USE model
    IMPLICIT NONE
    REAL, DIMENSION(:), POINTER :: fmin_fvecp
CONTAINS
    SUBROUTINE broyden(x,fmin_fvecp,funcv)           
        IMPLICIT NONE
        REAL, DIMENSION(:), INTENT(IN) :: x
        REAL, DIMENSION(size(x)), TARGET :: y
        REAL, DIMENSION(:), POINTER :: fmin_fvecp
        PROCEDURE(function_system_template), POINTER :: funcv
        fmin_fvecp=>y
        print*,fmin(x,fmin_fvecp,funcv)        ! Get the sum of squares
        print*,fmin_fvecp                      ! Show the vector x(1) and x(2)
        print*,lnsrch(x,fmin,fmin_fvecp,funcv) ! Show the figure calculated in LNSRCH
    END SUBROUTINE broyden

    FUNCTION fmin(x,fmin_fvecp,funcv) RESULT(y)
        IMPLICIT NONE
        REAL, DIMENSION(:), INTENT(IN) :: x
        REAL, DIMENSION(:), POINTER :: fmin_fvecp
        PROCEDURE(function_system_template), POINTER :: funcv
        REAL :: y
        fmin_fvecp=funcv(x)                    ! The value of FMIN_FVECP is assigend
        fmin=dot_product(fmin_fvecp,fmin_fvecp)! when FMIN is called by BROYDEN
    END FUNCTION fmin    

    FUNCTION lnsrch(x,func,a_fvecp,b_funcv) RESULT(y)
        IMPLICIT NONE
        REAL, DIMENSION(:), INTENT(IN) :: x
        REAL, DIMENSION(:), POINTER :: a_fvecp 
        PROCEDURE(function_system_template), POINTER :: b_funcv 
        INTERFACE                              
            FUNCTION func(x,fvecp,funcp) 
            IMPORT :: function_system_template  
            IMPLICIT NONE
            REAL, DIMENSION(:), INTENT(IN) :: x
            REAL :: func
            REAL, DIMENSION(:), POINTER :: fvecp 
            PROCEDURE(function_system_template), POINTER :: funcp 
            END FUNCTION                                
        END INTERFACE
        REAL, DIMENSION(SIZE(x)) :: y
        y=x+a_fvecp+b_funcv(x)+1000.
        END FUNCTION lnsrch
    END MODULE newton

Основната програмна единица е дефинирана, както следва:

PROGRAM main
    USE model                            
    USE newton                           
    IMPLICIT NONE  
    REAL, DIMENSION(:), allocatable :: x
    allocate(x(2))
    x=[1.,2.]                         ! The input arguments to be passed into 
    funcv=>func_system1               ! the equation system, FUNC_SYSTEM1.
    call broyden(x,fmin_fvecp,funcv)  ! Call BROYDEN to do the subsequent calcualtion
    deallocate(x)    
END PROGRAM main

Извинете за дългия пост. Благодаря за времето, което прочетохте въпроса ми. Очакваме с нетърпение всяка информация за заобикаляне на съобщението за грешка. Благодаря.

Лий


person Li-Pin Juan    schedule 28.04.2013    source източник
comment
Вие декларирате fmin_fvecp1 и в двата модула, което е конфликт, тъй като и двата се използват в програмата. Имате fmin=.. в function fmin, но не и y=..., което е проблем, тъй като сте декларирали result (y).   -  person M. S. B.    schedule 29.04.2013
comment
@M.S.B.: Това е грешка, идваща от копиране и поставяне от моя програмен код на различни версии. Благодаря ви, че го посочихте. След премахване на излишната декларация на „FMIN_FVECP“ от модул „NEWTON“, същото съобщение за грешка все още се показва.   -  person Li-Pin Juan    schedule 29.04.2013


Отговори (2)


Освен противоречивото използване на fmin_fvecp1, споменато в коментарите (за което бих очаквал изрична грешка на компилатора, имайте предвид, че фиктивните декларации на аргументи със същото име скриват променливата на модула в съответните процедури на модула в модул newton), имайте предвид, че телата на интерфейса не автоматично наследяват чрез асоцииране на хост обектите, дефинирани в тяхната единица за обхват на хостове, освен ако оператор IMPORT не въвежда този обект в обхвата на интерфейсния блок.

Следователно символът function_system_template в интерфейсния блок за фиктивния аргумент func в lnsrch не е същото нещо като този символ извън интерфейсния блок - следователно действителните и фиктивните аргументни процедури нямат едни и същи характеристики. Липсата на декларация за символа в интерфейсния блок е нарушение на ограничението - бих очаквал разумно специфична грешка от компилатора за това.

person IanH    schedule 28.04.2013
comment
Благодаря за отговора. Използвам оператора IMPORT в интерфейсния блок за фиктивния аргумент FUNC в LNSRCH и все още получавам същото съобщение за грешка. Мога ли да попитам дали можете да забележите друга грешка? За мен е странно, че съобщението за конфликт продължава да се показва. Благодаря. - person Li-Pin Juan; 29.04.2013
comment
Моята програма, добавена с оператора IMPORT, може да бъде изтеглена от тази връзка. Това е един файл във формат .f90. Благодаря. - person Li-Pin Juan; 29.04.2013

Кодът, показан в съдържанието по-долу, е заобиколното решение, което най-накрая получих: създавам допълнителен абстрактен интерфейс и събирам всички подпрограми в един единствен модул. Подпрограми BROYDEN, FMIN и LNSRCH се преименуват на MajorSolver, MiddleFunction и AssistantSolver. В основната програмна единица се провеждат три експеримента и се показват резултатите от тях. Общата машина зад всеки експеримент работи по следния начин: избира се система от уравнения и се предава в MajorSolver; междувременно се приема указател на масив. Указателят на масива заедно с указател на подпрограма, който препраща MiddleFunction, се предават във функция AssistantSolver за изчисляване на сумата от квадрати на елементите във входния аргумент x. В крайна сметка MajorSolver връща, за дадения входен вектор x, пропорцията на квадрат на съответния запис в сбора от квадрати.

MODULE model                                                             
IMPLICIT NONE                            
REAL, DIMENSION(:), POINTER :: fvec1p, fvec2p           ! <<Note1>>           
ABSTRACT INTERFACE                                      ! <<Note1>> !
    FUNCTION functions_system(x) RESULT(y)              !           !
    IMPLICIT NONE                                       !           !
    REAL, DIMENSION(:), INTENT(IN) :: x                 !           !
    REAL, DIMENSION(SIZE(x)) :: y                       !           !
    END FUNCTION                                        !           !
END INTERFACE                                           !           !

ABSTRACT INTERFACE                                      ! <<Note2>> 
    FUNCTION middle_function_template(x,fvec_p,proc_p) RESULT(y)  
    IMPLICIT NONE                                       !
    REAL, DIMENSION(:), INTENT(IN) :: x                 !
    REAL, DIMENSION(:), POINTER :: fvec_p               !
    PROCEDURE(functions_system), POINTER :: proc_p      !
    REAL :: y                                           !
    END FUNCTION                                        !
END INTERFACE                                           !

PROCEDURE(functions_system), POINTER :: proc1p, proc2p  ! <<Note1>>   
CONTAINS                                                          
FUNCTION func_system1(x) RESULT(y)                      ! Equation system             
    IMPLICIT NONE                                       ! in two variables     
    REAL, DIMENSION(:), INTENT(IN) :: x   
    REAL, DIMENSION(size(x)) :: y                            
    y(1)=x(1)                                        
    y(2)=x(2)                                  
END FUNCTION func_system1

FUNCTION func_system2(x) RESULT(y)                      ! Equation system
    IMPLICIT NONE                                       ! in three variables  
    REAL, DIMENSION(:), INTENT(IN) :: x
    REAL, DIMENSION(size(x)) :: y
    y(1)=x(1)*10.
    y(2)=x(2)*10.
    y(3)=x(3)*10.
END FUNCTION func_system2

FUNCTION func_system3(x) RESULT(y)
    IMPLICIT NONE
    REAL, DIMENSION(:), INTENT(IN) :: x 
    REAL, DIMENSION(SIZE(x)) :: y
    REAL, DIMENSION(:), POINTER :: ans2
    proc2p=>func_system1                                ! 
    allocate(ans2(2))                                   ! <<Note2>>
    call MajorSolver(ans2,x(1:2),fvec2p,proc2p)         !
    y(1)=ans2(1)
    y(2)=ans2(2)
    y(3)=0.
    deallocate(ans2)
END FUNCTION func_system3

SUBROUTINE MajorSolver(ans,x,fvec_p,proc_p)
    IMPLICIT NONE
    REAL, DIMENSION(:), POINTER :: ans
    REAL, DIMENSION(:), INTENT(IN) :: x
    REAL, DIMENSION(:), POINTER :: fvec_p
    PROCEDURE(functions_system), POINTER :: proc_p
    PROCEDURE(middle_function_template), POINTER :: proc3p
    REAL, DIMENSION(SIZE(x)), TARGET :: y
    REAL :: z
    fvec_p=>y                                           ! pointer initialization <<Note1>>
    proc3p=>MiddleFunction                              ! <<Note2>>
    z=AssistantSolver(x,proc3p,fvec_p,proc_p) 
    ans=fvec_p**2/z          
END SUBROUTINE MajorSolver

FUNCTION MiddleFunction(x,fvec_p,proc_p)                ! <<Note2>> This function returns something
    IMPLICIT NONE                                       ! back to MajorSolver. In this    
    REAL, DIMENSION(:), INTENT(IN) :: x                 ! case, it computes the inner product.
    REAL, DIMENSION(:), POINTER :: fvec_p               ! 
    PROCEDURE(functions_system), POINTER :: proc_p
    REAL :: MiddleFunction
    fvec_p=proc_p(x)
    MiddleFunction=dot_product(fvec_p,fvec_p)
END FUNCTION

FUNCTION AssistantSolver(x,func,fvec_p,proc_p)          ! <<Note2>> 
    IMPLICIT NONE                                       ! 
    REAL, DIMENSION(:), INTENT(IN) :: x                 ! 
    procedure(middle_function_template), pointer :: func! 
    REAL, DIMENSION(:), POINTER :: fvec_p               !  
    PROCEDURE(functions_system), POINTER :: proc_p      ! 
    REAL :: AssistantSolver                             ! 
    AssistantSolver=func(x,fvec_p,proc_p)               ! 
END FUNCTION AssistantSolver                            ! 
END MODULE model

PROGRAM main
USE model
IMPLICIT NONE
REAL, DIMENSION(:), POINTER :: ans
REAL :: data2(2), data3(3)
data2=[1.,2.]
proc1p=>func_system1
allocate(ans(size(data2)))
call MajorSolver(ans,data2,fvec1p,proc1p)
write(*,'(a,2(f7.3))'),'Equations system 1: Ans= ',ans
nullify(ans)

data3=[1.,2.,3.]
proc1p=>func_system2
allocate(ans(size(data3)))
call MajorSolver(ans,data3,fvec1p,proc1p)
write(*,'(a,3(f7.3))'),'Equations system 2: Ans= ',ans
nullify(ans,proc1p)

data3=[1.,2.,3.]
proc1p=>func_system3
allocate(ans(size(data3)))                              ! 
call MajorSolver(ans,data3,fvec1p,proc1p)               ! <<Note1>>
write(*,'(a,3(f7.3))'),'Equations system 3: Ans= ',ans  ! 
! The answer is 0.059 0.941 0.000
! Because in system 3 we calculate system 1 first, the 3rd entry of 
! data3 will be ignored before passed into system 1. The result is
! [0.200 0.800] as we already know in system 1.
! Then this vector will be passed into MajorSolver again. So, 
! the answer is [0.059 0.941] = [0.2**2/(0.2**2+0.8**2) 0.8**2/(0.2**2+0.8**2)]

END PROGRAM main

Резултатът е

Equations system 1: Ans=   0.200  0.800
Equations system 2: Ans=   0.071  0.286  0.643
Equations system 3: Ans=   0.059  0.941  0.000
Press any key to continue . . .
person Li-Pin Juan    schedule 30.04.2013