Использование языка SAS/IML57705.selcdn.com/MSU_2013/LEC2IML.pdfЧто такое...

Preview:

Citation preview

Использование языка SAS/IML

Лекция 1. Основы IML.

Звежинский Дмитрий, SAS Russia/CISdmitry.zvezhinsky@sas.com

1Замечания об ошибках и опечатках просьба направлять лектору.

http://tiny.cc/msu_sas

Что такое IML?• Это процедура языка SAS (PROC IML;), внутри которой можно создавать свои

программы на специальном языке.

• Синтаксис этого языка упрощает работу с матрицами (линейная алгебра, матричные операторы), а также содержит встроенные алгоритмы для решения разных задач:

– Численное решение линейных уравнений, систем уравнений

– Численное решение диф. уравнений и систем диф. уравнений

– Статистический анализ в духе «Большого SAS», т.е. генерирование отчетов с определенной структурой

– Манипуляции наборами данных SAS

– Написание собственных процедур/функций, которые, правда, работают только внутри IML

– Написание программ: циклы, операторы условного перехода, …

– Оптимизация

– Вэйвлет- и Фурье-преобразования

– Вызов процедур и функций из «Большого SAS»

– …

2

Простейшие матричные операции• Основной объект – двумерная матрица.

• Тип матрицы – числовой или символьный (смешивать нельзя).

proc iml;

a={1 2,3 4};

print (a);

quit;

15 proc iml;

NOTE: IML Ready

16 a={1 'a',3 'b'};

ERROR: Mixing character with numeric in matrix literal at line=16 col=8.

17 print (a);

ERROR: Matrix a has not been set to a value.

• Доступ к элементам матрицы – по индексам:proc iml;

a={1 2 3,4 5 6};

print a ,, (a[1,2]) ,, (a[{1 2},2]);

quit;

Индексы можно задавать с помощью матрицы

3

Простейшие матричные операции• Особенность – всё кроме цифр считается символьным

значением:proc iml;

a={1 2,3 4};

b={1 1+1,3 4};

c={1 (1+1),3 4};

d1=1+1;

d2={1 d1,3 4};

print a,,b,,c;

quit;

17 b={1 1+1,3 4};

_

22

200

ERROR: Unequal number of elements per row in literal at line=17 col=16.

4

Матрицы• Можно посмотреть тип матрицы и кол-во строк/столбцов:proc iml;

a={1 2,3 4};

print (a[1,1]);

show names;

a=j(2,2," ");

a[1,1]="PRIVET!";

print (a[1,1]);

show names;

quit;

• Матрицы можно переопределять. Размер элемента символьной матрицы можно поменять, только переопределив её.

• Матрицы можно сохранить в каталоге - хранилище (WORK.IMLSTOR), и пользоваться ими на другом шаге IML:

proc iml;

a={1 2,3 4};

store a;

quit;

proc iml;

load a;

print (a[1,1]);

quit;

proc catalog catalog=work.imlstor;

contents;

run;

5

Простейшие матричные операции• Есть матричные и поэлементные операции (проверяйте размерность!)

• Операции сравнения и минимума/максимума:proc iml;

a={1 2,3 4};

b={0 0,5 6};

print a b ,'a<>b',(a<>b); *set maximum;

b={2,3};

print a b, 'a<b',(a<b);

quit;

= Т( )

6

Subscript reduction operators

• Позволяют преобразовывать матрицы по заданному правилу по указанному измерению:

proc iml;

a={1 2 3, 4 5 6,7 8 9};

print (a[+, ]),,

(a[+,<>]),,

(a[+,<:>]);

quit;

Пример 1: суммируем по строчкам, кол-во

Столбцов остаётся как в исходной матрице.

Пример 2: сначала суммируем по строчкам, потом

ищем максимум в получившейся матрице.

Аналогичный результат дает последовательное

применение reduction operators: (a[+,][,<>])

Пример 3: суммируем по строчкам, и в полученной матрице ищем индекс (номер столбика), где лежит максимум.

Если reduction operators есть сразу в двух измерениях, сначала выполняется первый (для строк), потом второй (для столбиков).

операторы сведения (матриц) по индексам (???)

7

Простейшие матричные преобразования• inv (A) – обратная матрица

• trace (A) – след матрицы (сумма диаг. эл-тов A*A)

• abs(A) – модуль каждого элемента

• sum(A,B) – сумма всех элементов из всех матриц

• nrow(A), ncol(B) – кол-во строк (столбцов)

• j (n, m, “privet!”) – матрица n строк, m столбцов, состоящая из текстовой константы “privet!”

• diag(A) – возвращает матрицу того же размера, все элементы кроме диагональных заполняются нулями

• i (n) – единичная матрица размером (n x n)

• loc (A) – возвращает индексы ненулевых элементов, в частностиможно найти эл-ты, удовлетворяющие условию.

8

МодулиВстроенные функции:

• Support.sas.com/documentation

• SAS/IML 9.3 User's Guide

Пользовательские (называются модули):

• Можно их определять прямо в proc iml :

START <name> <( arguments )> <GLOBAL( arguments )> ;

FINISH <name> ;

• Пользоваться можно тоже только внутри IML.

• Есть в виде подпрограмм (subroutine, запускаются оператором CALL), либо в виде функций (function), которые могут вернуть какое-то значение. Отличаются только наличием оператора Return внутри модуля (если он есть – это функция).

9

Модули• Область видимости для переменных: зависит от того, есть ли в определённом

модуле аргументы

• Из модуля-процедуры без аргументов можно ссылаться на глобальные переменные, которые определятся позднее (из модуля-функции нельзя):

proc iml;

start test ;

print a;

finish;

a=5;

call test;

quit;10

Есть (it depends): Нет (все перем. глобальные):

Модули• Вложенные модули преобразуются так, чтобы у них был один (и тот же)

уровень вложенности.

• Выражения в качестве аргументов – вычисляются, но хранятся как локальная копия аргумента:

proc iml;

start test(in,out);

out=in+1;

print in out;

finish;

inx={1 2 3};

outx={1 2 3};

out=0;

call test(inx[1],outx[1]);

print (outx[1]);

call test(inx[1],out);

print (out);

quit; 11

Значение выражения (которое нужно как-то вычислить) видно внутри модуля, но оно хранится как локальная копия! И вернуть эту локальную копию в глобальную область видимости нужно явно.

Во втором вызове out – это не выражение (его не нужно вычислять), а имя матрицы. Через него можно возвратить значение в глобальную область видимости.

Глобальная или локальная переменная?

12

1. Переменная инициализируется вне модуля – глобальная2. Переменная инициализируется внутри модуля, но у модуля отсутствуют

аргументы – глобальнаяstart test;

output=input+1;

finish;

input=5;

output=0;

call test;

print output;

3. Переменная передаётся как аргумент в модуль – внутри модуля с ней можно работать как с глобальнойstart test(input,output);

output=input+1;

finish;

in=5;

out=0;

call test(in,out);

4. С помощью опции Global указываем переменную – внутри модуля она будет считаться глобальной.5. Если в качестве аргумента передаётся выражение, а не матрица, то переменная, которая в него входит, не считается глобальной переменной.

out

6

output

6

Резюме

Глобальная или локальная переменная?proc iml;

x={1 2 3 4 5};

start sum1(x);

return (x[1]+x[2]);

finish;

do i=1 to 4;

print(sum1(x[i]||x[i+1]));

end;

quit;

proc iml;

x={1 2 3 4 5};

start sum1;

c=x[i]+x[i+1];

finish;

c=0;

do i=1 to 4;

call sum1;

print (c);

end;

quit;13

х – глобальнаяа внутри модуля?(локальная)

В качестве аргумента передаём глоб. переменную

х – глобальнаяа внутри модуля?(как и «i», глобальная)

Глобальная или локальная переменная?proc iml;

start sum1(m) global (x);

c=x[m]+x[m+1];

finish;

x={1 2 3 4 5};

c=0;

do i=1 to 4;

call sum1(i);

print (c);

end;

quit;

14

х – глобальная, m-локальная

Создаём вектор-строку х

Вызываем модуль.

Хранение модулей• В IML есть механизм для хранения модулей (для их

последующего использования) и матрицproc iml;

start test;

print "this is a test";

finish;

STORE MODULE= test;

quit;

proc iml;

LOAD MODULE= test;

call test;

quit;

• You can view the names of the modules in storage with the SHOW statement, as follows:

show storage;

15

3568 STORE MODULE= test;NOTE: Opening storage library WORK.IMLSTOR3569 quit;NOTE: Exiting IML.NOTE: Storage library WORK.IMLSTOR closed.NOTE: PROCEDURE IML used (Total process time):

real time 0.00 secondscpu time 0.00 seconds

3570 proc iml;NOTE: IML Ready3571 LOAD MODULE= test;NOTE: Opening storage library WORK.IMLSTOR

Элементы языка IML• Циклы:

16

скобочки в условии обязательны!

скобочки в условии обязательны!

Элементы языка IML• Оператор условного перехода:

proc iml;

if . then do;

print ". is true";

end;

if 0 then do;

print "0 is true";

end;

quit;

• Условие должно возвращать число. Истина – это любое значение кроме нуля и пропущенного значения.

• Если в условии один оператор, то группу do; .. end; можно не добавлять.

• есть дополняющий оператор “else … ;”17

Программа ничего не печатает.

Попробуйте добавить оператор отрицания «^» перед условием.

Элементы языка IML• Оператор PRINT – вывод в отчет результатов и отладочной

информации. Общий вид вот такой:PRINT <matrices> (expression) "message" pointers <[options]> ;

• Если нужно вычислить выражение (вывести элементы матрицы, арифметика, функции) – указывайте его в скобочках!

• pointers – управляет разбивкой по строкам ( , ) и по страницам ( / )

• Можно подписывать строки и столбцы при выводе на экран:proc iml;

x = {45.125 50.500,

75.375 90.825};

r = {"Div A" "Div B"};

c = {"Amount" "Net Pay"};

print x[rowname=r colname=c format=12.2];

quit;

18

Интеграция IML и SASЧтение наборов данных:

1) Открыть набор данных для чтения:proc iml;

use test;

2) Прочитать нужные столбцы в матрицы:read all var {a} into char_test;

read all var {b} into num_test;

print char_test num_test;

quit;

19

Интеграция IML и SAS• Мы помним, что в матрице можно хранить данные только

одного типа. Размер для хранения данных берётся из дескриптора набора данных:

data test;

length a $ 3 text $ 200;

input a $ b text $ ;

datalines;

aaa 10 blahblahblah

bbb 20 blahblahblah

ccc 30 blahblahblah

ddd 40 blahblahblah

;

run;

proc iml;

use test;

show datasets;

read all var {a} into char_test;

read all var {b} into num_test;

read all var {text} into text_test;

print (char_test || text_test);

show names;

quit;

20

SYMBOL ROWS COLS TYPE SIZE

------ ------ ------ ---- ------

char_test 4 1 char 3

num_test 4 1 num 8

text_test 4 1 char 200

Интеграция IML и SASЗапись наборов данных

• 1) Создать набор данных с помощью оператора Create,

• 2) заполнить набор данных из матрицы – оператор Append:proc iml;

x=repeat(do(1,3,1),3,1);

y=repeat(T(do(1,3,1)),1,3);

print x y;

create test1 from x;

append from x;

create test2 from y;

append from y;

quit;

3849 quit;

NOTE: Exiting IML.

NOTE: The data set WORK.TEST1 has 3 observations and 3

variables.

NOTE: The data set WORK.TEST2 has 3 observations and 3

variables.

21

Интеграция IML и SASОператор Use – открыть набор данных и сделать его текущим для ввода/вывода (то есть тем набором, который будет использован операторами Read, Edit, Append, …)

Setin/Setout – выбрать текущий набор для ввода/выводаcreate test1 from x;

create test2 from y;

setout test1;

append from x;

setout test2;

append from y;

Close .. ; – закрыть набор данных, открытый операторами Use, Create, Edit

Show datasets; - статус наборов данных, использованных в текущем сеансе IML.

22

Преобразования типов

• Символы в число: NUMc = {"1" "2" "3"};

reset print; /*display values and type of matrices*/

m = num(c);

• Числа в символы: CHAR( matrix <, w> <, d> ) ;

a = {-1.1 0 3.1415 4};

reset print; /*display values and type of matrices*/

m = char(a, 4, 1);

23

Вызов процедур SAS из IMLSUBMIT <parameters> </ options> ;

language statements

ENDSUBMIT;

• Пример :proc iml;

x=do(-10,10,0.5);

eps=j(1,ncol(x),1);

call randgen(eps, "normal", 0,2);

y=3#x+5+eps;

data_iml=(T(x//y));

create test1 from data_iml;

append from data_iml;

close test1;

SUBMIT;

proc reg data=test1;

model col2=col1;

quit;

ENDSUBMIT;

quit;

24

!!! Наличие пробела между “T” и “;” приводит к зависанию IML

Любопытно, что внутрь SUBMIT можно передавать переменные из IML:

proc iml;

VarName = "Sex";

submit VarName;

proc freq data=Sashelp.Class;

table &VarName / out=OutFreq;

run;

endsubmit;

quit;

Работа с памятью• Для размещения матриц используется выделяемая в

памяти область (Workspace)

• Что будет, если мы всю её займём?

ERROR: (execution) Unable to allocate sufficient memory. At least 2147483647 more bytes required.

• Память выделяется частями (extent). Сначала SAS пытается выделить всё больше и больше extent’ов. Память сжимается (избавляемся от промежуточных временных переменных). Когда мы достигаем ограничения, выдается ошибка.

• Освобождение памяти:FREE A B C; *удаляет из памяти матрицы A,B,C;

FREE /; *удаляются все матрицы;

FREE / A B; *удаляются все матрицы, кроме A и B;

25

Работа с памятью• Изменение настроек собственно PROC IML для работы с

памятью делается опциями worksize= и symsize= (после которых указывается лимит памяти в килобайтах):

PROC IML <SYMSIZE=n1> <WORKSIZE=n2> ;

• Worksize= память для хранения содержимого матриц

• Symsize= память для хранения таблицы с именами матриц

• Команда для вывода отладочной информации о кол-ве extents, памяти, кол-ве сжатий:

show space;

• Команда для вывода информации о созданных и хранящихся в памяти переменных:

show names;

26

Матричные преобразования• Разложение SVD:proc iml;

A={1 2 3,

4 5 6,

8 9 10,

11 12 13};

CALL SVD( u, q, v, A ) ;

/*check decomposition*/

print A ,,(u*diag(q)*T(v)) ;

quit;

• Разложение Холецкого:Матрица А – симметричная и положительно определённая.proc iml;

A={10 0 0,

0 1 2,

0 2 9};

u=ROOT(A) ;

/*check decomposition*/

print A ,,(T(u)*u) ;

quit;

27

Матричные преобразования• QR- разложение:

CALL QR( q, r, piv, lindep, a <, ord> <, b> ) ;

proc iml;

A={1 2 3,

4 5 6,

7 8 9};

call qr(q,r,piv,lindep,A) ;

/*check decomposition*/

print q ,,(q*T(q)),r,,(q*r) ;

quit;

28

Матричные преобразования• Собственные векторы, собственные значения.

• Матрица А имеет только действительные элементы. Полученные с.в., с.з. имеют или одну (действит.) или две (действит. + мнимую) составляющих.

CALL EIGEN( evals, evecs, A ) ;

Ax = λx

CALL GENEIG( eval-M, evecs-E, A, B ) ;

EIGVEC( A ) ;

EIGVAL( A ) ;

proc iml;

M={0 -1,1 0};

call eigen(evals, evecs, M);

print evals ,, evecs;

quit;

29

1/√2

-i/√2

Матричные преобразования• Если матрица А не симметричная, и собственные значения получаются

комплексные, evals содержит 2 колонки. Первая – действительная часть, вторая – мнимая.

• Если строчки i, i+1 в матрице собственных значений (evals) содержат комплексно-сопряженные соб.значения, то в матрице соб.векторов(evecs) содержится действительная и мнимая части для координат одного из соб. векторов.

Иллюстрация результата, полученного на прошлом слайде:

30

1/√2

-i/√2= +i

1/√2

i/√2

1/√2

i/√2= -i

1 с.з.2 с.з.

1 с.в.2 с.в.

Re,Im

Re,Im

Задание• Напишите свой модуль, который вычисляет определитель матрицы

(матрица передаётся как параметр). Нельзя пользоваться функцией det. Результат задания – программа *.sas

• Вычислять можно любым методом, какой вам нравится.

• http://stackoverflow.com/questions/2435133/what-is-the-best-matrix-determinant-algorithm

• Оценка от 0 до 3:

• 0 – не сделал(а) или программа считает det неправильно

• 1 – определитель вычисляется для матрицы фиксированного размера

• 2 – п. «1» + сообщения об ошибках (неквадратная матрица, ???)

• 3 – п. «2» + определитель вычисляется для матрицы произвольного размера

• Сохраните его в хранилище для последующего вызова

• Загрузите модуль из хранилища и вызовите его в другой процедуре IML, написав пример(ы) его использования

Больше по этой лекции заданий нет.

31

32

Использование языка SAS/IML

• Supplementary: Решение разных задач

Статистическое описание данных• Создание отчета с рассчитанными статистиками, в том числе в разбивке по

классифицирующим переменным. На вход подается набор данных, открытый оператором USE.

SUMMARY <CLASS operand> <VAR operand> <WEIGHT operand> <STAT operand> <OPT operand> <WHERE(expression)> ;proc iml;

use sashelp.class;

SUMMARY CLASS {sex} VAR {age} STAT {mean min max};

quit;

Analysis variable : Age

Sex Nobs MEAN MIN MAX

---------------------------------------------

F 9 13.22222 11.00000 15.00000

M 10 13.40000 11.00000 16.00000

All 19 13.31579 11.00000 16.00000

---------------------------------------------

• Расчет матрицы с частотами:

CALL TABULATE( levels, freq, x <, method> ) ;

• Распечатка открытого набора данных:

LIST <range> <VAR operand> <WHERE(expression)> ; 33

Графика*

*let's plot sine and cosine;

proc iml;

do x1=-10 to 10 by 0.1;

x=x||x1;

y=y||sin(x1);

y2=y2||cos(x1);

end;

A=T(x//y//y2);

create work.temp1

from A

[colname={"x","sine","cosine"}];

append from A;

quit;

proc gplot data=temp1;

*goptions vsize=3 hsize=3;

SYMBOL1 COLOR=red INTERPOL=JOIN value=x;

SYMBOL2 COLOR=green INTERPOL=JOIN value=none;

*legend;

legend1 label=("Fancy plot") value=("sine plot" "cosine plot");

axis1 label=('y=f(x)');

plot sine*x cosine*x / overlay legend=legend1 vaxis=axis1;

run;

quit;

Чтобы построить график массива , созданного в IML, предлагается сбросить его в набор данных, а затем подать его на вход процедуры gplot:

* В IML есть собственные графические процедуры, но мы их изучать не будем 34

Графика

proc iml;

/** define functions **/

start Func1(x);

return( sin(x));

finish;

start Func2(x);

return( cos(x));

finish;

x = do(-5,5,0.1); *make matrix row;

y1=Func1(x);

y2=Func2(x);

A=T(x//y1//y2);

create work.temp1 from A[colname={"x","sine","cosine"}];append from A;

quit;

Построение графиков можно сделать меньшим кол-вом кода IML:

определили функции

вектор-строка Х

без циклов посчитали вектор-строку У

35

Решение ОДУ• В IML присутствует только одна процедура для этого: ODE

• The ODE subroutine is an adaptive, variable-order, variable-step-size, stiff integrator based on implicit backward-difference methods. …

• Как и любой численный метод, ODE должен гарантировать нам решение с точностью до указанного эпсилон (по умолчанию, 10^(-4))… Проверим!

• Давайте начнем его проверять с простого ОДУ:

• Начальные условия:

• Аналитическое решение:

y'(t)=-t*y(t)

y(t=0)=1

36

Решение ОДУ/*plot ode solve*/

proc iml;

start fun(t,y);

v = -t*y; *the equation is y'(t)=-t*y(t);

return(v);

finish;

/* Call ODE */

c = 1; *vector of initial values;

t = do(0,10,0.1); *start time, end time;

h = {1E-12 1 1E-5}; * the minimum allowable step size, hmin;

* the maximum allowable step size, hmax;

* and the initial step size to start the integration process,

hinit;

call ode(r1, "FUN", c, t, h);

TAB=T(t//(c||r1));

create work.temp1 from TAB[colname={"t","solution"}];

append from TAB;

quit;

/*plot*/

proc gplot data=temp1;

goptions reset;

SYMBOL1 COLOR=green INTERPOL=JOIN value=none;

plot solution*t;

run;

quit;

Модуль, где (система) ОДУ задается в виде вектор-столбца dy/dt:

Начальное условие для y(t(1))вектор t, для которых мы получим решение

…магия…решение не содержит начальное условие, мы его добавим

сбросим решение в набор данных и построим его с помощью gplot.

37

Решение ОДУ• Проверим и построим ошибку (EPS=1E-4)

/*-=-check error-=-*/

data errors;

set temp1;

analyt=exp(-t*t/2);

err=analyt-solution;

log10err=log(abs(err))/log(10);

run;

/*plot*/

proc gplot data=errors;

goptions reset;

SYMBOL1 COLOR=green

INTERPOL=JOIN value=none;

plot log10err*t / vref=-4;

run;

quit;

По оси У отложен десятичн.логарифм ошибки – мы видим, что она «под контролем» численного метода!

38

Решение системы ОДУ

• Пример:y(t)''= exp(-y(t)' /10) * sin(2*t)Нач. условия: y(0)=1, y'(0)=-1• Перепишем ур-е со второй производной как систему двух уравнений с первой

производной:y(t)’ =z(t)z(t)’ =exp(-z/10)*sin(2*t) = y(t)’’• Как будет выглядеть модуль для функции ODE?start ode2ord(t,y);

y1=y[2];

y2=exp(-y1/10)*sin(2*t);

y=y1//y2;

return(y);

finish;

• Вызовем функцию ODE:c = {1, -1}; *vector of initial values;

t = do(0,2,0.1); *start time, end time;

h = {1E-12 1 1E-5};

call ode(r1, "ODE2ORD", c, t, h);

TAB=T(t//(c||r1));

create work.temp1 from TAB[colname={"t","sol1","sol2"}];

append from TAB;

или ОДУ высших порядков, что то же самое

39

t-независ. переменная,y – вектор-столбец: [ y (t) ][ y’(t) ]на выходе – тоже вектор-столбец:[ y’(t) = f1() ][ y’’(t) = f2() ]

порядок решений

Решение системы ОДУgoptions reset;

goptions hsize=500pt vsize=250pt;

SYMBOL1 COLOR=red INTERPOL=JOIN value=none;

SYMBOL2 COLOR=blue INTERPOL=JOIN value=none;

Legend1 value=('function y(t)');

Legend2 value=('derivative y''(t)');

proc gplot data=temp1;

plot sol1*t / legend=legend1;

plot sol2*t=2 / legend=legend2 ;

run;

quit;

40

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

Решение жесткого (stiff) ОДУ• Уравнение, которое дает резкое возрастание погрешности при

недостаточно малом шаге – хорошая проверка численных методов!

• Пример с аналитическим решением *:

dy/dt = y2- y3

y(0) = δ0 < t < 2/δ

• Модуль, задающий ОДУ + программа:proc iml;

start fun(t,y);

v = y##2-y##3;

return(v);

finish;

/* Call ODE */

c = 1E-4; *vector of initial values;

t = 0 || 2/c; *start time, end time;

h = {1E-15 1 1E-5};

call ode(r1, "FUN", c, t ,h) data="work.steps";

*The data set is used to save the successful independent and dependent

variables of the integration at each step. The keyword for this option is

DATA;

quit;

41* http://www.mathworks.com/company/newsletters/articles/stiff-differential-equations.html

Проверяем, как работает адаптивный контроль шага. Выводим последовательные шаги в набор данных steps:

Жесткое ОДУ• Построим график решения у(t):goptions reset vsize=250pt hsize=500pt;

SYMBOL1 COLOR=green INTERPOL=none value=x;

proc gplot data=steps;

plot y1*time;

run;

42http://www.mathworks.com/cmsimages/64812_wl_may03_ode23_large.gif

OOOPS!

Решение жесткого ОДУ• Ошибка явно вышла из-под контроля числ. метода!

• Можно добавить параметр eps=1E-8, и решение будет ближе к ожидаемому:

call ode(r1, "FUN", c, t ,h) data="work.steps" eps=1e-8;

• Но будет ли метод честно контролировать ошибку? Для этого давайте построим аналитическое решение, которое выражается через спец. функцию:

y(x) = ( LambertW0 [c1*exp(c1-t)]+1)^(-1), где c1=1/δ -1

В нашем случае δ =1E-4;

• “The Lambert W function is named after J. H. Lambert (1728 - 1777), who was a colleague of Euler and Lagrange at the Berlin Academy of Sciences. Lambert is best known for his laws of illumination and his proof that π is irrational.“ *

• … через спец. функцию, которой нет в SAS…

43* http://www.mathworks.com/company/newsletters/articles/stiff-differential-equations.html

Решение жесткого ОДУ. Спецфункции.

• Ради методических целей разберёмся, как можно использовать сторонние библиотеки численных методов (хотя можно было бы «упереться», и переписать вычисление LambertW0 на SAS).

• Кстати, известные лектору библиотеки ч.м., которыми он сам иногда пользуется:

• http://www.netlib.org/ (много фортрана!! иногда мало документации)

• http://www.nr.com/ (“c”)

• http://www.gnu.org/software/gsl/ (доступна в любой системе, даже windows)

• План: подключим стороннюю библиотеку (GSL) и воспользуемся готовой функцией

44

7.23 Lambert W Functions

Lambert's W functions, W(x), are defined to be solutions of the equation W(x) \exp(W(x)) = x. This function has multiple branches for x < 0; however, it has only two real-valued branches. We define W_0(x) to be the principal branch, where W > -1 for x < 0, and W_{-1}(x) to be the other real branch, where W < -1 for x < 0. The Lambert functions are declared in the header file gsl_sf_lambert.h.

— Function: double gsl_sf_lambert_W0 (double x)

Подключение сторонних библиотек dll*• Сначала поставим уже собранную библиотеку GSL, например, отсюда:

http://wiki.rglab.org/images/Data/GSL/setup_32.zip

• Пропишем путь к файлу dll в переменной PATH:

• Перезагрузим SAS, если он запущен.

45*не доступно в on-demand

Подключение сторонних библиотек• Каким образом SAS узнает о конкретной функции из конкретной

библиотеки?

1) Сделаем специальный файл*, в котором записана сигнатура нужной функции:

* table for sample function in gsl;

* double gsl_sf_lambert_W0 (double x);

ROUTINE gsl_sf_lambert_W0 MINARG=1 MAXARG=1 RETURNS=DOUBLE;

ARG 1 NUM INPUT BYVALUE FORMAT=RB8.;

* double gsl_sf_exp (double x);

ROUTINE gsl_sf_exp MINARG=1 MAXARG=1 RETURNS=DOUBLE;

ARG 1 NUM INPUT BYVALUE FORMAT=RB8.;

2) Вызывающая программа:filename sascbtbl "c:\workshop\gsl_tab.sas";

data work.lambert; *let's get analytical solution!;

length x y arg 8;

c=1E-4;

set work.steps;

invcm1=(1/c-1);

arg=(invcm1*exp(invcm1-time));

y = modulen( '*',

"libgsl-0,gsl_sf_lambert_W0", arg );

analyt=1/(y+1);

run;

46* см. help->modulen function

Подключение сторонних библиотек• При первом вызове функция modulen загружает в память указанную

библиотеку.

• На выходе получаем численное возвращаемое значение.

• После выхода из шага data библиотека выгружается из памяти.

• Можно вызывать в IML.

• CAUTION:

Use the correct arguments and attributes.

If you use incorrect arguments or attributes, you can cause the SAS System, and possibly your operating system, to fail.

• CAUTION:

Using the CALL MODULE routine without a defined attribute table can cause the SAS System to fail or force you to reset your computer.

You need to use an attribute table for all external functions that you want to invoke.

• Для более сложных функций (например, требующих на вход структуры/объекты, или предварительный malloc) предлагается писать свою обвязку (свои dll).

47

Сравнение с точным решениемdata err1;

set lambert;

err=log(abs(analyt-y1))/log(10);

label err='log(abs(error))';

run;

/*plot*/

goptions reset;

goptions reset vsize=250pt hsize=500pt;

SYMBOL1 COLOR=green INTERPOL=NONE value=x;

proc gplot data=err1;

plot err*time / vref=-8;

run;

quit;

48

опять построим десятичный логарифм ошибки

Здесь у экспоненты получился слишком большой аргумент, ~exp(999), и мы

точное решение не посчитали.

y(x) = ( LambertW0 [c1*exp(c1-t)]+1)^(-1), где c1=1/δ -1δ =1E-4;

Здесь ошибка вышла из-под контроля численного метода.

***• На момент чтения лекции, лектору не удалось добиться от тех. поддержки SAS

внятного объяснения этого поведения функции ODE

• Проблема осложняется отсутствием отладочной информации от функции ODE, или какого-либо кода возврата от неё же, который бы обращал внимание пользователя на неконтролируемый рост ошибки.

• Вроде бы можно вручную уменьшить максимальный шаг, но… он не уменьшается (вектор “h”)

• Варианты решения ситуации (не полный список?):

1. «Дожимать» тех. поддержку;

2. Самому писать метод для интегрирования жестких ОДУ (хорошая идея!);

3. Write in C:

49

Уравнение теплопроводности (метод конечных разностей, неявная схема)

• «Экономисты любят решать уравнение теплопроводности» … (????)

• Лектор не обнаружил в SAS каких-либо готовых методов для решения уравнений в частных производных и краевых задач.

• Поэтому будем писать свой! *

• Формулировка задачи:

50* Сохин А.С., Скорик В.А. Метод сеток решения уравнений параболического типа, Харьков, 2003

Уравнение теплопроводности• Идея: введём дискретизацию по t и x, аппроксимируем производные

конечными разностями, и запишем полученную систему уравнений.

• Выберем неявную схему для аппроксимации производных:

• Сформулируем задачу в матричной форме Ax=b, где x – вектор-столбец с искомыми решениями U(I,j), A – матрица, b – некоторый вектор-столбец.

51

x (i)

t(j)

U(i-1,j+1) U(i+1,j+1)U(i,j+1)

U(i,j)

Начальные условия

Граничные условия

hτ Пусть у нас отсутствует источник (F=0)

Уравнение теплопроводности

(1+2α) -α .. U(1,1) U(1,0)+αU(0,1)

-α (1+2α) -α .. U(2,1) U(2,0)

-α (1+2α) .. U(3,1) U(3,0)+αU(4,1)

-1 (1+2α) -α … U(1,2) αU(0,2)

-1 -α (1+2α) -α … U(2,2) 0

-1 -α (1+2α) … U(3,2) αU(4,2)

… … … …

52

дискретизованное, в матричном виде

A X b

• Матрица А содержит только параметры разностной схемы. Столбец b содержит начальные U( *,0) и граничные U(0,*) U(4,*) условия.

• В матрице много нулей. Может не нужно их все хранить? (каждая ячейка, даже пустая – 8 байт)

• Для решения такой задачи с разреженной матрицей А имеются специальные методы.

Разреженные матрицы• Процедура ITSOLVER получает решение разреженной линейной системы с

помощью разных итеративных методов.

call itsolver(x,error,it,"BICG",A,b,"MILU");

• x решение системы Ax=b.

• error относительная ошибка полученного решения.

• iter количество итераций.

Входные аргументы:

method - тип итеративного метода:

• "CG" - conjugate gradient algorithm. The matrix A must be symmetric and positive definite.

• "CGS" specifies a conjugate gradient squared algorithm, for general A.

• A – матрица в специальном формате.

• b – вектор-столбец в уравнении Ax=b.

• Метод для предобусловления матрицы А для более быстрой сходимости (совместимость с итеративным методом обсуждается в справке)

53

Разреженные матрицы/*Heat conduction equation using IML solution with finite differences */

%let len=20;

proc iml;

h=0.1;

tau=0.1;

alpha=tau/h##2;

L=&len;

T=2;

NL=int(L/h);

NT=int(T/tau);

/* value row col */

do j=0 to NT-1; /*index for submatrices*/

do i=1 to NL; /*fill main diagonal*/

A = A //

((1+2*alpha) || i+j*NL || i+j*NL);

end;

do i=1 to NL-1; /*fill upper&lower diagonal*/

A = A //

((-alpha)|| i+j*NL+1 || i+j*NL) //

((-alpha)|| i+j*NL || i+j*NL+1);

end;

end;

do j=1 to NT-1;

do i=1 to NL; /*fill 2-nd lower diagonal*/

A = A //

((-1)|| i+j*NL || i+(j-1)*NL);

end;

end;

54

шаги дискретизации

Размер области, где получается решение = (NL+2)*hи максимальное время = (NT+1)*tau

Формируем разреженную матрицу A в формате {«значение» «строка» «столбец»}

NL

NL

Разреженные матрицы• Выберем начальное условие – гауссиан

f(x,t=0) = 1/sqrt(2*pi) *exp(-(x-L/2)^2/2)

• и граничное (U(x=0)=0; U(x=L)=0).

• Создадим и заполним вектор-столбец b

(это обычная матрица):/* right-hand sides */

b = J( NL*NT, 1, 0) ;

/* add boundary conditions to b*/

do i=0 to NT-1;

b[i*NL+1 ,1]=b[i*NL+1,1]+alpha*0;

b[i*NL+NL,1]=b[i*NL+NL,1]+alpha*0;

end;

/* add initial conditions to b*/

do i=1 to NL-1;

b[i ,1]=b[i ,1]+1/sqrt(2*3.1415926)*exp(-(L/2-i*h)##2/(2));

end;

• Теперь магия:call itsolver(x,error,it,"BICG",A,b,"MILU");

55эти настройки дают лучшую сходимость метода для несимметричной матрицы А

Уравнение теплопроводности/*break x into matrix to plot later*/

SOL=J(NT*NL,3,0);

do j=1 to NT; /*row*/

do i=1 to NL;

SOL[i+NL*(j-1),3]=x[i+NL*(j-1),1];

SOL[i+NL*(j-1),1]=j*tau;

SOL[i+NL*(j-1),2]=i*h;

end;

end;

create work.temp1 from SOL;

append from SOL;

• Аналитическое решение для выбранного начального условия (в виде гауссиана) – тоже гауссиан (известно как одномерная «предписанная диффузия»):

• Если станд. отклонение у гауссиана в начальном условии было σ, то:

56

Ф(x,t)=1/ 𝜋 4𝑡 + 2𝜎2 ∗ 𝑒− 𝑥−𝑥0 2/(4𝑡+2𝜎2)

Уравнение теплопроводностиdata analyt_temp;

set temp2;

retain time 1;

if (col1=time) then do;

analyt=1/sqrt(3.1415926*(4*time+2*1**2))*exp(-(col2-&len/2)**2/(4*time+2*1**2));

output;

end;

run;

symbol1 COLOR=green INTERPOL=join value=none;

symbol2 COLOR=red INTERPOL=join value=none ;

proc gplot data=analyt_temp;

plot col3*col2 analyt*col2 / overlay;

run;

quit;

57

(Дискретное) Фурье-преобразование

• Оно есть!• Для примера посмотрим на фильтрацию суммы синусов:%let fd=10; *discretization frequency;

proc iml;

t=do(-25.5,25.6,1/&fd);

pi=3.1415926;

y=sin(2*pi*0.2#t)+0.5*sin(2*pi*0.5#t);

y1=y;

do i=1 to ncol(t);

y1[i]=y1[i]+RAND('NORMAL',0,0.5);

end;

PLT1=T(t)||T(y)||T(y1);

create plot1 from plt1;

append from plt1;

quit;

goptions reset;

goptions hsize=500pt vsize=400pt;

SYMBOL1 COLOR=red INTERPOL=JOIN value=none;

SYMBOL2 COLOR=blue INTERPOL=JOIN value=none;

proc gplot data=plot1;

plot col2*col1 col3*col1/ overlay;

run;

quit;

58

Фурье-преобразованиеproc iml;

use plot1;

read all into plt1;

NFFT=nrow(plt1); *points in signal;

fft_y=fft(plt1[,2])/(NFFT /2 );

*set norm for fourier transform;

harm=sqrt(fft_y[,1]##2+fft_y[,2]##2);

*amplitude of harmonic;

fd=&fd ; *discretization frequency;

f=do(0,1,2./NFFT);

*frequencies for fourier-transformed

signal;

Теперь можно построить:

• Гармоники исходного сигнала

• и зашумленного

59

Фурье-фильтр• Пара строчек:

fil_fft_y=fft_y;

fil_fft_y[loc(harm<0.1),]=0;

• И обратное Фурье-преобразование:

/*and inverse fourier transform*/

fil_y=ifft(fil_fft_y)/2;

• Теперь сбрасываем всё что нужно в наборы данных, и строим графики:

fourier=T(fd/2#f)||harm||harm_1;

create plot2 from fourier;

append from fourier;

fil_y_tab= plt1[,1]||fil_y;

create plot3 from fil_y_tab;

append from fil_y_tab;

quit;

60

Фурье-фильтр• Объединим наборы данных для построения исходного, зашумленного и

отфильтрованного сигнала:data merged;

set plot3(rename=(col1=t1 col2=yfilt));

set plot1(rename=(col1=t col2=y col3=noisy));

run;

• И построим график:SYMBOL1 COLOR=green INTERPOL=none value=dot;

SYMBOL2 COLOR=red INTERPOL=JOIN value=none;

SYMBOL3 COLOR=blue INTERPOL=JOIN value=none;

proc gplot data=merged;

plot noisy*t y*t yfilt*t / overlay;

run;

quit;

61

ххх

62

Разберитесь с процедурой для численного вычисления интегралов:1. Найдите в справке, как она называется2. Напишите программу, которая вычисляет интегральный синус от +1000.

Si (x)=∫0

x sin(t )

tdt

Recommended