Красавин Компютерныы практикум в среде МатЛаб 2015
.pdfразреженных матриц, т.е., например, операция A+B, где A и B – разреженные матрицы, даст в результате также разреженную матрицу. Если одна из матриц – полная, то в результате может получиться как разреженная, так и полная матрица в зависимости от типа выполняемой операции. В табл. 20.1 показаны типы результирующей матрицы при различных операциях с разреженными матрицами; R означает разреженную матрицу, F – полную.
Таблица 20.1
Тип результата при выполнении операций с разреженными матрицами
R+R |
R |
R+F |
F |
R–R |
R |
R–F |
F |
R*R |
R |
R*F |
F |
R.*R |
R |
R.*F |
R |
R./R |
R |
R./F |
R |
Функция spdiags является аналогом функции diag для разреженных матриц и позволяет формировать разреженные матрицы с заданными диагоналями или выделять диагонали из разреженных матриц. Например, для матрицы A
A = [0 1 0 2 0 0; 0 0 3 0 4 0; 5 0 0 6 0 7;...
8 9 0 0 10 0; 0 11 12 0 0 13];
A =
0 |
1 |
0 |
2 |
0 |
0 |
0 |
0 |
3 |
0 |
4 |
0 |
5 |
0 |
0 |
6 |
0 |
7 |
8 |
9 |
0 |
0 |
10 |
0 |
0 |
11 |
12 |
0 |
0 |
13 |
команда
[B, d] = spdiags(A)
231
сформирует матрицу B, состояющую из столбцов, содержащих диагонали матрицы А, и вектор d, содержащий позиции этих диагоналей в матрице:
B =
0 |
0 |
1 |
2 |
0 |
0 |
3 |
4 |
0 |
5 |
6 |
7 |
8 |
9 |
10 |
0 |
11 |
12 |
13 |
0 |
d =
-3 -2 1 3
Позиции диагоналей в матрице показаны на рис. 20.3. Для диагоналей, лежащих под главной диагональю, значения элементов добавляются в конец соответствующего столбца матрицы B, а для диагоналей, лежащих над главной диагональю, – в начало соответствующего столбца.
Рис. 20.3. Позиции диагоналей в матрице
232
Функция speye(m,n) создает единичную матрицу размера в разреженном виде.
Функция full выполняет преобразование разреженной матрицы в полную.
Функция find выполняет поиск ненулевых элементов в матрице:
[i,j,x] = find(A); % такое обращение к функции find с тремя выходными параметрами приводит к созданию двух векторов индексов и вектора, содержащего значения ненулевых элементов
i = |
4 |
1 |
4 |
5 |
2 |
5 |
1 |
3 |
|
2 |
4 |
3 |
5 |
|
3 |
|
|
||||||||||||
j = |
1 |
2 |
2 |
2 |
3 |
3 |
4 |
4 |
|
5 |
5 |
6 |
6 |
|
1 |
|
|
||||||||||||
x = |
8 |
1 |
9 |
11 |
|
3 |
12 |
2 |
6 |
4 |
|
10 |
7 |
13 |
5 |
|
|
Функция spconvert выполняет преобразование полной матрицы в разреженную на основе матрицы, содержащей три столбца: два столбца индексов и столбец значений. Следующие две команды эквивалентны:
A = spconvert(x);
A = sparse(x(:,1),x(:,2),x(:,3)); % эта команда аналогична предыдущей
Если матрица x содержит четыре столбца, то два последних столбца используются как массивы значений, а матрица A получается комплексной; значения реальной части элементов берутся из третьего столбца x, мнимой части – из четвертого столбца.
Функция nnz возвращает число ненулевых элементов матрицы:
233
nnz(A)
ans = 13
Функция spfun используется для вычисления функций от ненулевых элементов матрицы. Функция имеет следующий формат: С = spfun(@f,A), где f – функция. Значения функции будут вычислены только от ненулевых элементов матрицы А:
C(i,j)=f(A(i,j)). Например,
CN = spfun(@cos,A)
CN = |
0.2837 |
(3,1) |
|
(4,1) |
-0.1455 |
(1,2) |
0.5403 |
(4,2) |
-0.9111 |
(5,2) |
0.0044 |
(2,3) |
-0.9900 |
(5,3) |
0.8439 |
(1,4) |
-0.4161 |
(3,4) |
0.9602 |
(2,5) |
-0.6536 |
(4,5) |
-0.8391 |
(3,6) |
0.7539 |
(5,6) |
0.9074 |
Функция eigs вычисляет собственные значения матрицы и оптимизирована для работы с разреженными матрицами. Она уже использовалась при вычислении энергии частицы в потенциальной яме (см. гл. 14).
Задание
20.1. Переписать алгоритмы из главы о частице в потенциальной яме, использовав трехдиагональные разреженные матрицы.
234
21
Фракталы. Рекурсия
21.1. Рекурсивные функции
Термин «рекурсия» означает «что-то, определяемое в терминах самого себя». В программировании рекурсивной называется функция, вызывающая саму себя.
Классическим примером рекурсии является рекурсивное определение факториала целого числа:
! |
· |
1 ! –общийслучай; |
Такое определение |
1! |
1 –частный случай. |
|
факториала является рекурсивным, потому что |
факториал определяется в терминах другого факториала. В рекурсивном определении любого объекта всегда присутствуют общий и частный случаи. В общем случае факториал числа равен
числу , умноженному на факториал числа |
|
. В частном |
|||
случае факториал числа |
|
равен |
. Достижение |
частного случая |
|
|
1 |
|
|||
останавливает рекурсию. |
Например, |
|
|
||
1 |
|
1 |
|
|
3! 3·2!
2! 2·1!
1! 1
Вычисление 3! невозможно без вычисления 2!; вычисление 2! невозможно без вычисления 1!; вычисление 1! – частный случай, результат равен 1. После достижения частного случая вычисления разворачиваются в обратном порядке: зная 1!, можно найти 2!, а зная 2!, можно найти 3!.
235
При организации рекурсии необходимо обеспечить, чтобы частный случай рано или поздно был реализован, иначе рекурсия будет бесконечной. В примере 21.1 приведен код программы, вычисляющей факториал методом рекурсии.
Пример 21.1.
function facn = fact(n)
if n == 1 facn = 1;
else
facn = n * facn(n-1);
end end
Программа в примере 21.1 работает следующим образом. Пусть снова требуется вычислить 3!. При первом обращении к функции происходит попытка присвоить переменной facn результат вычисления 3 * facn(2). Однако значение facn(2) в этот момент не определено, и вычисление прерывается рекурсивным обращением к функции facn для вычисления facn(2). При этом обращении делается попытка вычисления значения 2 * facn(1). Но значение facn(1) в этот момент также не определено, и вычисление прерывается рекурсивным обращением к функции facn для вычисления facn(1). При этом обращении реализуется ветвь if конструкции if-else, и рекурсия достигает частного случая. Вычисляется значение facn(1), далее оно передается в процесс, ожидающий вычисления facn(2), которое, в свою очередь, передается в процесс, ожидающий вычисления facn(3).
В примере 21.2 рассматривается применение рекурсивной функции для перестановки слов в предложении в обратном порядке.
Пример 21.2.
function reverse_words(sent)
% sent – исходное предложение
236
[word, rest] = strtok(sent); % функция strtok разбивает входной аргумент на две части: первое слово записывается в переменную word, а оставшийся текст – в переменную rest
if ~isempty(rest) % если переменная rest не является пустым
массивом, |
происходит |
рекурсивное |
||
обращение |
к |
функции; |
когда |
в |
переменной rest не остается слов, |
||||
наступает частный случай, и рекурсия |
||||
останавливается |
|
|
|
|
reverse_words(rest); |
|
|
|
|
end |
|
|
|
|
disp(word) % вывод на экран слова, |
содержащегося в |
переменной |
word; первым будет выведено последнее слово в предложении, так как именно на нем останавливается рекурсия
end
% Пример работы функции
reverse_words('Маша любит кашу')
кашу
любит
Маша
Рекурсивные функции часто используются при построении фрактальных объектов.
21.2. Ковер Серпинского
Ковер Серпинского является фрактальным объектом с размерностью 1.585 [5]. Метод построения ковра достаточно простой. В качестве начального множества выберем равносторонний треугольник . Удалим внутренность центральной треугольной части и обозначим оставшееся множество . Затем повторим описанный процесс для каждого из трех оставшихся треугольников и получим следующее приближение . Продолжая таким же образом, получим
237
последовательность множеств |
, которая и образует ковер |
Серпинского (рис. 21.1). |
|
Рис. 21.1. Построение ковра Серпинского
Для построения ковра Серпинского можно использовать следующий алгоритм.
1. |
Задать порядок ковра . |
|
|
|
|
|
|
2. |
Задать координаты вершин исходного треугольника |
||||||
3. |
Построить: , |
равносторонний, , , , |
треугольник. |
и залить его |
|||
|
черным цветом. |
|
|
|
|
|
|
4. |
Вычислить координаты середин сторон треугольника |
: |
|||||
|
|
2 |
; |
2 |
; |
|
|
|
|
|
238 |
; |
; |
|
|
|
|
|
|
2 |
; |
; |
|
|
|
|
; |
|
. |
|
Построить треугольник2 |
|
||||
5. |
|
|
и залить его белым цветом. |
|||
6. |
Повторить |
раз действия |
в пунктах 4 и 5 для |
|||
|
треугольников |
, |
|
|
, |
соответственно. |
Алгоритм можно реализовать с использованием рекурсивной процедуры, выполняющей последовательность действий, описанную в пп. 4 и 5. Полный код программы [4] приведен в примере 21.2.
Пример 21.2.
function z = Serpinsky(Lmax)
%Lmax - порядок ковра
%задание координат вершин равнобедренного треугольника x1=0;
y1=0;
x2=1;
y2=0;
x3=0.5;
y3=sin(pi/3);
h=figure(1); % инициализация графического окна hold on
fill([x1 x2 x3],[y1 y2 y3],'k'); % прорисовка равностороннего треугольника и заливка его черным цветом; функция fill закрашивает многоугольник, определяемый векторами координат x и y
set(gca,'xtick',[],'ytick',[]); % отключение режима оцифровки осей set(gca,'XColor','w','YColor','w'); % установка цвета рисования
осей
% обращение к функции, прорисовывающей равносторонние треугольники белого цвета
239
Simplex(x1,y1,x2,y2,x3,y3,0,Lmax); hold off %
function z=Simplex(x1,y1,x2,y2,x3,y3,n,Lmax)
if n < Lmax % условие достижения рекурсией частного случая
%задание координат вершин текущего равностороннего треугольника dx=(x2-x1)/2;
dy=(y3-y1)/2; x1n=x1+dx; y1n=y1; x2n=x1+dx+dx/2; y2n=y1+dy; x3n=x1+dx/2; y3n=y1+dy;
%прорисовка текущего равностороннего треугольника
n=n+1;
fill([x1n x2n x3n],[y1n y2n y3n],'w');
%применение функции Simplex к треугольнику c вершинами
%(Xa',Ya); (Xa',Ya); (Xc',Yc') Simplex(x1,y1,x1n,y1n,x3n,y3n,n,Lmax);
%применение функции Simplex к треугольнику c вершинами
%(Xa',Ya); (Xb',Yb'); (Xb',Yb') Simplex(x1n,y1n,x2,y2,x2n,y2n,n,Lmax);
%применение функции Simplex к треугольнику c вершинами
%(Xc',Yc'); (Xb',Yb'); (Xc,Yc) Simplex(x3n,y3n,x2n,y2n,x3,y3,n,Lmax);
end
21.3. Губка Менгера
Губка Менгера является объемным аналогом ковра Серпинского. Принципиально схема построения губки не отличается от схемы построения ковра, разница состоит лишь в числе итераций на каждом уровне. Пример 21.3 содержит код, реализующий построение губки и ее заливку различными цветами
(рис. 21.2).
240