Передача дополнительных аргументов в метод Ньютона на Фортране

У меня возникли проблемы с реализацией подхода к вызову метода Ньютона в программе на Фортране. Поэтому я хочу использовать метод Ньютона для решения уравнения по ссылке

Однако моя программа немного отличается от приведенного выше примера. В моем случае уравнение требует некоторой дополнительной информации, которая создается во время выполнения.

subroutine solve(f, fp, x0, x, iters, debug)

что означает, что f вычисляется не только на основе x, но и на основе нескольких других переменных (но x неизвестен).

У меня есть решение, которое работает только для простого случая: я использовал модуль для включения решателя Ньютона. Я также определил производный тип данных для хранения всех аргументов внутри модуля. Теперь это работает хорошо.

Мой вопрос: мне нужно много раз вызывать метод Ньютона, и каждый раз аргументы разные. Как мне спроектировать структуру модулей? Или я должен использовать другое решение?

Ниже я привел простой пример:

module solver
  type argu
    integer :: m
  end type argu
  type(argu):: aArgu_test  !should I put here?
  contains
    subroutine solve(f, fp, x0, x, iters, debug)
       ...
       !m is used inside here
    end subroutine solve
    subroutine set_parameter(m_in)
       aArgu%m = m_in
    end subroutine set_parameter()

end module solver

И вызывающий модуль:

!only one set of argument, but used many times
module A
   use module solver

   do i = 1, 4, 1
     set_parameter(i) 
     !call Newtow method
     ...
   enddo
end module A

!can I use an array for argu type if possible?
module B
   use module solver
   type(argu), dimension(:), allocable :: aArgu ! or should I put here or inside solver module?

end module B

Насколько я понимаю, если я помещу объект argu в модуль решателя, то все вызовы решателя будут использовать одни и те же аргументы (я все еще могу сохранить их все внутри модуля A, используя описанный выше метод). В этом случае мне нужно обновлять аргументы во время каждого цикла for?

Поскольку программа работает с использованием MPI/OpenMP, я хочу убедиться, что между потоками нет перезаписи. Спасибо.


person Chang    schedule 06.09.2018    source источник
comment
Когда вы говорите вызывать метод Ньютона много раз, вы имеете в виду: найти цель x для заданного набора параметров, а затем найти новую цель x для другого набора параметров?   -  person Ross    schedule 06.09.2018
comment
Потенциальные дубликаты " title="передача внешней функции нескольких переменных как функции одной переменной в">stackoverflow.com/questions/24127313/ stackoverflow.com/questions/26297170/ stackoverflow.com/questions/38324934/ stackoverflow.com/questions/37714406/   -  person Vladimir F    schedule 06.09.2018
comment
Пожалуйста, ограничивайте свои вопросы только одним вопросом. Но, кажется, вы сами ответили на свой вопрос 1... Но нам нужно больше деталей для вашего вопроса 2. Пожалуйста, покажите нам, как на самом деле работает код, проще говоря - покажите больше кода.   -  person Vladimir F    schedule 06.09.2018
comment
Так что пока не закрываюсь, потому что я предполагаю, что вы на самом деле просите Q2, а Q1 решен. Но нам нужно больше информации.   -  person Vladimir F    schedule 06.09.2018
comment
Ну, я хочу использовать метод Ньютона в своей программе, первый шаг/вопрос - это тест с дополнительными аргументами. Моя окончательная программа требует более одного набора аргументов. Так что @Росс прав. Я найду x для нескольких наборов аргументов.   -  person Chang    schedule 06.09.2018
comment
Вы смотрели ответы, связанные @VladimirF? Мне кажется, они отвечают на ваш вопрос.   -  person Ross    schedule 06.09.2018
comment
@VladimirF предоставил полезную информацию, очень близкую к моему вопросу 1. Я отредактировал часть вопроса 2.   -  person Chang    schedule 06.09.2018


Ответы (2)


В современном Фортране есть общий шаблон для проблемы, с которой вы сталкиваетесь (частичное функциональное приложение). В отличие от других языков, Фортран не имеет замыканий функций, поэтому создание лексической области видимости для функции немного «сложно» и отчасти ограничено.

Вам действительно следует пересмотреть все ссылки, которыми @VladmirF поделился в комментарии, большинство из них напрямую относятся к вашему делу. Приведу пример решения.

Это решение без использования типа оболочки. Я буду использовать функцию, включенную в стандарт Fortran 2008: передачу внутренней процедуры в качестве аргумента. Он совместим с последними версиями gfortran, Intel и многими другими. Если вы не можете получить доступ к компилятору с помощью этой функции или предпочитаете решение с производным типом, вы можете обратиться к этому ответь.

module without_custom_type
  use, intrinsic :: iso_fortran_env, only: r8 => real64
  use :: solver

contains
  subroutine solve_quad(a, b, c, x0, x, iters, debug)
    integer, intent(in) :: a, b, c
    real(r8), intent(in) :: x0
    real(r8), intent(out) :: x
    integer, intent(out) :: iters
    logical, intent(in) :: debug

    call solve(f, fp, x0, x, iters, debug)

  contains
    real(r8) function f(x)
      real(r8),intent(in) :: x
      f = a * x * x + b * x + c
    end

    real(r8) function fp(x)
      real(r8),intent(in) :: x
      fp = 2 * a * x + b
    end
  end
end

Обоснование этого кода таково: поскольку f и fp лежат внутри процедуры solve_quad, они имеют доступ к аргументам a, b и c по ассоциации с хостом, не касаясь сигнатур этих функций. Полученный эффект подобен изменению арности функции.

Протестировав его с помощью gfortran 8.0 и реализации solver по ссылке, которой вы поделились, я получил следующее:

program test
  use, intrinsic :: iso_fortran_env, only: r8 => real64
  use :: without_custom_type
  implicit none

  real(r8) :: x, x0
  integer :: iters
  integer :: a = 1, b = -5, c = 4

  x0 = 0
  call solve_quad(a, b, c, x0, x, iters, .false.)
  print *, x, iters
  ! output: 1.0000000000000000, 5

  x0 = 7
  call solve_quad(a, b, c, x0, x, iters, .false.)
  print *, x, iters
  ! output: 4.0000000000000000, 6    
end
person Rodrigo Rodrigues    schedule 07.09.2018
comment
Я бы закрыл вопрос как дубликат, если бы речь шла именно об этом. Мы уже слишком много раз объясняли шаблон. Как вы думаете, это имеет значение для его второго (и после обсуждения единственного реального) вопроса? Если да, это следует указать, потому что для первой простой проблемы использование переменных модуля вместо ассоциации с хостом также вполне допустимо. - person Vladimir F; 07.09.2018
comment
Я думаю, что этот ответ предлагает мне еще одно достойное решение. Я никогда не использовал внутреннюю процедуру до сих пор. Думаю, с его помощью я смогу упростить часть исходного кода, не передавая его явно. И я думаю, что это решение отличается от метода модуля, потому что каждый экземпляр объекта производного типа данных четко разделен. Спасибо. Урок выучен. - person Chang; 08.09.2018
comment
Дело в том, что этот ответ не отличается от многих других, указанных @VladimirF как возможные дубликаты; внимательное прочтение их привело бы вас к похожему коду. Я просто написал это, потому что, несмотря на это, этот вопрос, похоже, не был закрыт как дубликат, и я не хочу, чтобы вы или будущие читатели этого вопроса думали, что это невозможно решить. Подводя итог, обратите внимание на советы таких опытных людей, как он. - person Rodrigo Rodrigues; 08.09.2018

После обсуждения с коллегой у меня есть решение моего вопроса 2.

Если у нас есть только один объект-аргумент для модуля решателя, то все вызовы будут обращаться к одним и тем же аргументам, потому что они используют одно и то же пространство памяти.

Чтобы избежать этого, мы хотим передать объект аргумента в качестве аргумента в решатель. Поэтому вместо использования подпрограммы решателя по умолчанию мы перепишем метод Ньютона, чтобы он мог принимать дополнительные аргументы.

(Ранее я использовал простейшую подпрограмму Ньютона, потому что хотел оставить ее нетронутой.)

Таким образом, мы определим массив объектов-аргументов и передадим их во время выполнения.

Спасибо за комментарии.

person Chang    schedule 06.09.2018