
- •Конфигурирование MATLAB Compiler
- •Простой пример сложения двух чисел
- •Создание МЕХ-файла, использующего программу на Фортране
- •Объявление функций и локальных переменных
- •Чтение входного массива
- •Выполнение вычислений
- •Копирование полученного результата в выходную величину
- •Работа с комплексными переменными
В данной строке имя файла с интерфейсной процедурой является вторым параметром mex. После выполнения данной команды в текущем каталоге появится файл mysum.dll, который и содержит требуемую МЕХ-функ- цию. Проверим ее работу, обратившись к ней из командной строки:
>> s=mysum(l,2) s =
3
Пример создания МЕХ-функции из простейшей процедуры Fortran, приведенный выше, демонстрирует основные принципы использования интерфейса приложений Matlab API. Пользователю Matlab, не имеющему достаточного опыта в области разработки интерфейса приложений, но желающему вызывать процедуры Fortran из среды Matlab, достаточно знать небольшой набор функций Matlab API. Требуются только функции, которые позволяют обмениваться основными типами данных. Интерфейсные процедуры, как правило, принципиально не отличаются для различных процедур на Fortran и состоят из трех частей:
•получение значений входных аргументов;
•вызов процедуры на Fortran;
•возвращение значений в среду Matlab.
=========================================================
Пример из документации Matlab
Создание МЕХ-файла, использующего программу на Фортране
Напишем простую программу на Фортране timestwo, которая принимает в качестве входного параметра действительное значение переменной, а возвращает это значение, умноженное на 2:
subroutine timestwo(y_output, x_input) real*8 x_input, y_output
y_output = 2.0 * x_input return
end
Создадим интерфейсную программу для вызова этой подпрограммы на Фортране. Откроем MATLAB Editor и введем следующую информацию
C=======================================================
C |
timestwo.f |
C Функция, которая принимает скаляр, а возвращает его |
|
C |
удвоенное значение. |
C |
Это MEX-файл для MATLAB. |
C=======================================================
7
Добавимзаголовочныйфайл Фортранаfintrf.h, позволяющийпод-
ключить API MATLAB.
#include "fintrf.h"
Сохраним файл в рабочую директорию MATLAB, например, на сменный носитель f:\work, и назовем его timestwo.f.
Длядоступак подпрограмме наФортранеиспользуется интерфейсная процедура mexFunction, которая должна содержать следующий код
C Интерфейсная процедура
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
C Declarations
C Statements
return end
Для того, чтобы явным образом объявлять тип каждой переменной включим в нашу программу оператор
implicit none
Явное объявление типа переменных необходимо для 64-битных массивов.
Интерфейсная процедура mexFunction имеет четыре аргумента. Два типа mwPointer (указатели на массивы типаmxArray) и два типа inte-
ger:
nrhs – число входных аргументов, с которыми будет происходить обращение к МЕХ-функции timestwo из среды Matlab;
prhs – массив указателей на входные аргументы timestwo;
nlhs – число выходныхаргументов,с которыми будетпроисходитьобращение к МЕХ-функции timestwo из среды Matlab;
plhs — массив указателей на выходные аргументы timestwo.
Обмен данными между процедурой timestwo и средой Matlab посредством интерфейсной процедуры mexFunction осуществляется только при помощи перечисленных аргументов. Для выделения данных из prhs и занесения результата в plhs предназначены специальные функции Matlab API.
Добавим следующий код после оператора Declarations.
C mexFunction arguments: mwPointer plhs(*), prhs(*) integer nlhs, nrhs
Объявление функций и локальных переменных
8
В mexFunction использованы функции MATLAB API: mxGetPr,mxCreateDoubleMatrix, mxGetM, mxGetN возвращающие значения типа integer. Функция mxCreateDoubleMatrix вы-
деляет память под массив и возвращает указатель на массив. В рассматриваемом примере этот массив служит для возврата результата (удвоенного значения входной величины) в рабочую среду Matlab и поэтому имеет размеры один на один. Функция mxGetPr служит для получения указателя на
первый вещественный элемент в массиве. Функции mxGetM и mxGetN возвращают количество строк и столбцов в массиве соответственно. Переменная mxIsNumeric определяет является ли массив числовым.
C Function declarations: mwPointer mxGetPr
mwPointer mxCreateDoubleMatrix integer mxIsNumeric
mwPointer mxGetM, mxGetN
Локальные переменные x_ptr и y_ptr понадобятся для хранения указателей на массивы, содержащие входной и выходной аргументы. Переменные mrows, ncols определяют размерность массива для хранения данных. В нашем случае имеем массив 1х1.
Объявим локальные переменные для аргументов mexFunction
C Pointers to input/output mxArrays: mwPointer x_ptr, y_ptr
Объявим переменные, характеризующие используемый массив
C Array information: mwPointer mrows, ncols mwSize size
Переменные x_input – входная величина, y_output – выходная величина, используемые в подпрограмме, производящей вычисления. Эта подпрограмма может быть размещена как в отдельном файле, так и одном файле с интерфейсной программой.
C Arguments for computational routine: real*8 x_input, y_output
Чтение входного массива
Указатель на массив, содержащий входные данные получаем с помощью функции mxGetPr
x_ptr = mxGetPr(prhs(1))
Для создания массива Фортрана x_input, используем функцию mxCopyPtrToReal8.
9
C Get the size of the input array. mrows = mxGetM(prhs(1))
ncols = mxGetN(prhs(1)) size = mrows*ncols
C Create Fortran array from the input argument. call mxCopyPtrToReal8(x_ptr,x_input,size)
Для создания выходной величины используем функцииmxCreateDoubleMatrix и mxGetPr
C Create matrix for the return argument.
plhs(1) = mxCreateDoubleMatrix(mrows,ncols,0) y_ptr = mxGetPr(plhs(1))
Выполнение вычислений
Передадим аргументы в подпрограммуtimestwo.
C Call the computational subroutine. call timestwo(y_output, x_input)
Копирование полученного результата в выходную величину
C Load the data into y_ptr,
C which is the output to MATLAB.
call mxCopyReal8ToPtr(y_output,y_ptr,size)
В окончательном виде файлtimestwo.f будет выглядеть так
C ==================================================
C |
timestwo.f |
C |
Функция, которая принимает скаляр, а возвращает |
C |
его удвоенное значение. |
C |
Это MEX-файл для MATLAB. |
C ==================================================
#include "fintrf.h"
CGateway routine
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
C mexFunction arguments: mwPointer plhs(*), prhs(*) integer nlhs, nrhs
C Function declarations: mwPointer mxGetPr
mwPointer mxCreateDoubleMatrix
10
integer mxIsNumeric mwPointer mxGetM, mxGetN
C Pointers to input/output mxArrays: mwPointer x_ptr, y_ptr
C Array information: mwPointer mrows, ncols mwSize size
C Arguments for computational routine: real*8 x_input, y_output
x_ptr = mxGetPr(prhs(1))
C Get the size of the input array. mrows = mxGetM(prhs(1))
ncols = mxGetN(prhs(1)) size = mrows*ncols
C Create Fortran array from the input argument. call mxCopyPtrToReal8(x_ptr,x_input,size)
C Create matrix for the return argument.
plhs(1) = mxCreateDoubleMatrix(mrows,ncols,0) y_ptr = mxGetPr(plhs(1))
C Call the computational subroutine. call timestwo(y_output, x_input)
C Load the data into y_ptr,
C which is the output to MATLAB.
call mxCopyReal8ToPtr(y_output,y_ptr,size)
return end
C---------------------------------------------------
CComputational routine
subroutine timestwo(y_output, x_input) real*8 x_input, y_output
y_output = 2.0 * x_input return
11

end
Подготовка МЕХ-файла
Проведение вычислений
=========================================================
Еще один пример
Вычисление определённого интеграла по квадратурной формуле Гаycса
Для вычисления воспользуемся подпрограммой на Фортране QS12R. Подпрограмма входит в Библиотеку численного анализа НИВЦ МГУ. Ссылка на текст, приведенный ниже http://num-anal.srcc.msu.ru/lib_na/cat/q/qs12r.htm
Подпрограмма: QS12R
Назначение
Вычисление определенного интеграла по квадратурной формуле Гаусса.
Математическое описание
QS12R вычисляет интеграл с заданной абсолютной погрешностью на отрезке интегрирования по формуле
B |
N |
|
( |
B − A |
) |
y |
A |
+ |
B |
|
|
∫f (x)dx ≈(B − A) ∑Ci f |
|
i + |
|
|
/ 2 , |
||||||
|
2 |
|
|
2 |
|
||||||
A |
i=1 |
|
|
|
|
|
|
|
|
где yi и Ci соответственно узлы и веса Гаусса для отрезка [-1, 1].
Л.Г. Васильева. Набор стандартных программ численного интегрирования с фиксированным распределением узлов. Сб. «Численный анализ на ФОРТРАНе», вып. 8, Изд-во МГУ, 1974.
Использование
SUBROUTINE QS12R (RINT, A, В, F, E, N, IERR)
Параметры
12
RINT – вещественная переменная, содержащая вычисленное значение интеграла;
A, В – заданныенижний иверхнийпределы интегрирования(тип: вещественный);
F– имя вещественной подпрограммы-функции, вычисляющей подынтегральную функцию f (x);
E– заданная абсолютная погрешность вычисления интеграла (тип: вещественный);
N – целая переменная, задающая число узлов интегрирования; IERR – целая переменная, служащая для сообщения об ошибках, обнаруженных в ходе работы подпрограммы; при этом:
IERR = 65 –
IERR = 66 –
когда заданная точность не может быть достигнута
при максимально возможном числе узлов интегрирования; значение N полагается равным - 1;
когда заданное число узлов интегрирования не
принадлежит списку возможных узлов.
Вызываемые подпрограммы
UTQS10 – подпрограмма выдачи диагностических сообщений при ра-
боте подпрограммы QS12R.
Замечания по использованию
B процессе вычисления число узлов интегрирования N может принимать
только следующие значения:
(1)2, 4, 6, 8, 10, 12, 16, 24, 32, 48, 64, 96.
Проводится несколько последовательных просчетов, причем для каждого последующего просчета берется очередное число узлов из списка
(1).
Если абсолютная величина разности двух последовательных просчетов интеграла не превосходит E, то счет заканчивается, и за значение интеграла принимается результат последнего просчета. Если список (1) исчерпан и заданная точность не достигнута, то N полагается равным - 1.
При E ≤ 0 происходит только один просчет с заданным N.
Пример использования
REAL FUNCTION F(X)
REAL X
F = 1./(X*SQRT(1. + ALOG(X)) )
RETURN
END
13
EXTERNAL F
INTEGER N
REAL RINT, A, B, F, E
A = 1.
B = EXP(3.)
E = 0.0000001
N = 2
CALL QS12R {RINT, A, B, F, E, N, IERR)
Результаты:
RINT = 1.9999999999 N = 32
Для дальнейшей работы нам надо разобраться с таким интересным средством работы в Matlab как function_handle.
Массивы указателей на функции (function_handle arrays)
Одним из типов данных, заслуживающим внимания, является класс function_handle. С терминомhandle (произносится – хэндл) многие программисты сталкивались при работе с файлами при создании подпрограмм обработки событий в различных визуальных средах. Термин handle пока не получил единообразной трактовки в отечественной литературе. Под этим термином скрывается системный способ идентификации некоторых программных компонентов. Так, например, при работе с файлами вместо их идентификаторов (имен дисковых файлов или их полных спецификаций) в операторах обмена указывается тем или иным способом созданный handle. Им может быть конкретное число, которое операционная система присваивает открываемым файлам (int fl=open...), или указатель на блок управле-
ния файлом (см. в C++ описание типа FILE *fl;). Иногда этот термин именуют дескриптором (т. е. описателем). Но, видимо, наиболее точно термину handle врусскомязыке соответствуюттермины указательили ссылка.
Указатель на функцию (function_handle) обеспечивает возмож-
ность доступа ко всей информации, необходимой для вычисления значения этой функции. Создается такой указатель (а по терминологии MATLAB — массив указателей) одним из двух следующим способов:
»f_h=@funl;
»f_h=str2func('funl')
Врезультате и той, и другой операции создается указатель f_h, который «смотрит» на функцию с именем funl. Первый вариант очень напоминает присвоение адреса переменной указателю соответствующего типа в C++ (int x; int *px=&x;). Указатель f_h может быть передан в каче-
стве аргумента другой функции:
» y = integral(a,b,f_h);
14

Для того чтобы функция integral могла воспользоваться значением функции funl (x), она использует системную процедуру feval:
»z = feval(f_h, x);
Вфирменных руководствах утверждается, что использование указателей несколько повышает производительность интерпретатора при многократных обращениях к функции.
Дополнительную информацию об использовании этого типа данных
можно найти в справке Matlab, сделав поиск по ключевому слову function_handle.
Рассмотрим пример использования этого типа данных. Зададим функцию, реализующую возведение числа в 5 степень
Теперь, чтобы получить пятую степень числа, например, 2, надо запи-
сать
Этот же результат можно получить, используя функцию Matlab feval, что мы и будем делать в дальнейшем
Теперь этот синтаксис используем для интегрирования нашей функции через процедуру, написанную на Фортране. Отметим следующую важную особенность. Основной тип данных Matlab – double, в Фортране это
соответствует типу Real*8. Так как в используемой нами процедуре на Фортране используется тип Real, то и в Matlab надо использовать соответствующий тип данных – single.
Вызовем Matlab Editor и создадим файл Test.m
15

Напишем теперь функцию-обертку, куда будем передавать объявленные аргументы. Перейдем в Фортран и создадим файл QS12R_wrapper.F.
#include "fintrf.h"
! Gateway routine
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
!Declarations implicit none
!mexFunction arguments:
mwPointer plhs(*), prhs(*) ! массивы произвольного размера integer nlhs, nrhs
!Function declarations: mwPointer mxGetPr mwPointer mxGetData
mwPointer mxCreateNumericArray integer mxIsClass
integer mxClassIDFromClassName integer mexCallMATLAB
integer mexPrintf
!Variables
real RESULT, A, B, err ! MATLAB использует тип double, но мы используем single
integer N, IERR, status, classid
mwPointer input(2), output(1) ! массивы указателей
16
character*120 line integer k
! Program !-----------------------------------------------------------------------
! Check for proper number of arguments. if(nrhs .ne. 5) then
|
call mexErrMsgIdAndTxt ('MATLAB:QS12R_wrapper:nInput', |
+ |
'Five inputs required.') |
elseif(nlhs .gt. 1) then |
|
|
call mexErrMsgIdAndTxt ('MATLAB:QS12R_wrapper:nOutput', |
+ |
'Too many output arguments.') |
endif
!Validate inputs
if(mxIsClass(prhs(1), 'function_handle') .ne. 1) then |
|
||
|
call mexErrMsgIdAndTxt ('1st input argument must be a |
|
|
+ |
function_handle') |
|
|
elseif(mxIsClass(prhs(2), 'single') .ne. 1) then |
|
|
|
|
call mexErrMsgIdAndTxt ('2nd input argument must be a single') |
||
elseif(mxIsClass(prhs(3), 'single') .ne. 1) then |
|
|
|
|
call mexErrMsgIdAndTxt ('3rd input argument must be a single') |
||
elseif(mxIsClass(prhs(4), 'single') .ne. 1) then |
|
|
|
|
call mexErrMsgIdAndTxt ('4th input argument must be a single') |
||
elseif(mxIsClass(prhs(5), 'int32') .ne. 1) then |
|
|
|
|
call mexErrMsgIdAndTxt ('5th input argument must be an int32') |
||
endif |
|
|
|
! -------------------------------------------------------------------------- |
|
|
|
input(1) = prhs(1) ! копируем указатель на ссылку на функцию |
|||
classid = mxClassIDFromClassName ('single') |
! определяем класс аргу- |
||
мента вычисляемой функции |
|
|
|
input(2) = mxCreateNumericArray (2, (/1,1/), classid, 0) |
! создаем указа- |
||
тель на аргумент, сюда потом будем записывать аргумент функции |
|||
! у указателя prhs(2) надо взять еще указатель... |
|
|
|
call mxCopyPtrToReal4 (mxGetPr (prhs(2)), A, |
1) |
! WARNING: |
|
переменная должна быть REAL4 |
|
|
|
call mxCopyPtrToReal4 (mxGetPr (prhs(3)), B, |
1) |
! WARNING: |
|
переменная должна быть REAL4 |
|
|
|
|
17 |
|
|
call mxCopyPtrToReal4 (mxGetPr (prhs(4)), err, 1) |
! WARNING: |
переменная должна быть REAL4 |
|
call mxCopyPtrToInteger4 (mxGetPr (prhs(5)), N, 1) |
! WARNING: пе- |
ременная должна быть INT |
|
call QS12R (RESULT, A, B, ourfunc, err, N, IERR) |
! выполнение функ- |
ции, ради которой все и затевалось |
|
write (line, *) 'A number of nodes = ', N ! итоговое количество узлов для заданной точности
k = mexPrintf (line//achar(13))
plhs(1) = mxCreateNumericArray (2, (/1,1/), classid, 0) ! в plhs(1) нет объ-
екта, надо его создать
call mxCopyReal4ToPtr (RESULT, mxGetPr(plhs(1)),1) !запишемрезуль-
тат на выход, не забываем о соответствии типов
! не забываем за собой убирать call mxDestroyArray (input (2))
CONTAINS |
! подфункция-обертка |
||
real FUNCTION ourfunc (x) |
|
|
|
real x, out |
|
|
|
integer mexCallMATLAB |
|
|
|
call mxCopyReal4ToPtr (x, mxGetPr (input(2)), 1) |
! мы присваиваем |
||
х аргументу функции, которая в input(1) |
|
|
|
status = mexCallMATLAB (1, output, 2, input, 'feval') |
|
|
|
call mxCopyPtrToReal4 (mxGetPr (output(1)), out, |
1) |
! достаем |
|
значение функции |
|
|
|
ourfunc = out return
END FUNCTION
END SUBROUTINE
Теперь в рабочем каталоге Matlab должны находится следующие файлы
18