Компания ALT Linux
Опубликован: 24.03.2015 | Доступ: свободный | Студентов: 550 / 136 | Длительность: 19:00:00
Лекция 2:

Основы Maxima

2.7.2 Массивы

Массивы в Maxima — совокупности однотипных объектов с индексами. Число индексов не должно превышать пяти. В Maxima существуют и функции с индексами (функции массива).

Возможно создание и использование переменных с индексами до объявления соответствующего массива. Такие переменные рассматриваются как элементы массивов с неопределёнными размерностями (так называемые хэш-массивы). Размеры неопределённых массивов растут динамически по мере присваивания значений элементам. Интересно, что индексы массивов с неопределёнными границами не обязательно должны быть числами. Для повышения эффективности вычислений рекомендуется преобразовывать массивы с неопределёнными границами в обычные массивы (для этого используется функция array).

Создание массива производится функцией array. Синтаксис обращения к функции: array(name,dim_1,... ,dim_n) — создание массива с именем name и размерностями dim_1,... ,dim_n; array(name,type,dim_1,... ,dim_n) — создание массива с именем name и элементами типа type; array([name_1,... ,name_m],dim_1,... ,dim_n) — создание нескольких массивов одинаковой размерноcти.

Индексы обычного массива — целые числа, изменяющиеся от 0 до dim_i.

Пример:

(%i1)	array(a,1,1);
a\leqno{(\%o1) }
(%i2)	a[0,0]:0; a[0,1]:1; a[1,0]:2; a[1,1]:3;
0123\leqno{(\%o5) }
(%i6)	listarray(a);
[0,1,2,3]\leqno{(\%o6) }

Функция listarray, использованная в примере, преобразует массив в список. Синтаксис вызова: listarray(A).

Аргумент A может быть определённым или неопределённым массивом, функцией массива или функцией с индексами. Порядок включения элементов массива в список — по строкам.

Функция arrayinfo выводит информацию о массиве A. Синтаксис вызова: arrayinfo(A) Аргумент A, как и в случае listarray, может быть определённым или неопределённым массивом, функцией массива или функцией с индексами.

Пример использования:

(%i1)	array (aa, 2, 3);
aa\leqno{(\%o1) }
(%i2)	aa [2, 3] : %pi;
\pi \leqno{(\%o2) }
(%i3)	aa [1, 2] : %e;
e\leqno{(\%o3) }
(%i4)	arrayinfo (aa);
[declared,2,[2,3]]\leqno{(\%o4) }
(%i5)	bb [FOO] : (a + b)^2;
{\left( b+a\right) }^{2}\leqno{(\%o5) }
(%i6)	bb [BAR] : (c - d)^3;
{\left( c-d\right) }^{3}\leqno{(\%o6) }
(%i7)	arrayinfo (bb);
[hashed,1,[BAR],[FOO]]\leqno{(\%o7) }
(%i8)	listarray (bb);
[{\left( c-d\right) }^{3},{\left( b+a\right) }^{2}]\leqno{(\%o8) }

Функции listarray и arrayinfo применимы и к функциям массива:

(%i9)	cc [x, y] := y / x;
{cc}_{x,y}:=\frac{y}{x}\leqno{(\%o9) }
(%i10)	cc[1,2];
2\leqno{(\%o10) }
(%i11)	cc[2,1];
\frac{1}{2}\leqno{(\%o11) }
(%i12)	arrayinfo(cc);
[hashed,2,[1,2],[2,1]]\leqno{(\%o12) }
(%i13)	listarray(cc);
[2,\frac{1}{2}]\leqno{(\%o13) }

Ещё один пример — создание и вывод информации о функциях с индексами:

(%i1)	dd [x] (y) := y ^ x;
{dd}_{x}\left( y\right) :={y}^{x}\leqno{(\%o1) }
(%i2)	dd[1](4);
4\leqno{(\%o2) }
(%i3)	dd[a+b];
lambda\left( [y],{y}^{b+a}\right) \leqno{(\%o3) }
(%i4)	arrayinfo(dd);
[hashed,1,[1],[b+a]]\leqno{(\%o4) }
(%i5)	listarray(dd);
[lambda\left( [y],y\right) ,lambda\left( [y],{y}^{b+a}\right) ]\leqno{(\%o5) }

Функция make_array(type,dim_1,... ,dim_n) создаёт и возвращает массив Lisp. Тип массива может быть any,\ flonum,\ fixnum,\ hashed,\ functional. Индекс i может изменяться в пределах от 0 до dim_i -1.

Достоинство make_array по сравнению с array — возможность динамически управлять распределением памяти для массивов. Присваивание y : make_array(...) создаёт ссылку на массив. Когда массив больше не нужен, ссылка уничтожается присваиванием y : false, память освобождается затем сборщиком мусора.

Примеры:

(%i1)	A1 : make_array (fixnum, 8);
{Lisp\  Array:\  \#(0\  0\  0\  0\  0\  0\  0\  0)}\leqno{(\%o1) }
(%i2)	A1[1]:8;
8\leqno{(\%o2) }
(%i3)	A3 : make_array (any, 8);
{Lisp\  Array:\  \#(NIL\  NIL\  NIL\  NIL\  NIL\  NIL\  NIL\  NIL)}\leqno{(\%o3) }
(%i4)	arrayinfo(A3);
[declared,1,[7]]\leqno{(\%o4) }

Переменная arrays содержит список имён массивов первого и второго видов, определённых на данный момент.

Пример:

(%i1)	array(a,1,1);
a\leqno{(\%o1) }
(%i2)	array(b,2,3);
b\leqno{(\%o2) }
(%i3)	arrays;
[a,b]\leqno{(\%o3) }

Функция fillarray позволяет заполнять массивы значениями из другого массива или списка. Заполнения производится по строкам.

Примеры:

(%i1)	array(a,1,1);
a\leqno{(\%o1) }
(%i2)	fillarray(a,[1,2,3,4]);
a\leqno{(\%o2) }
(%i3)	a[1,1];
4\leqno{(\%o3) }
(%i4)	a2 : make_array (fixnum, 8);
Lisp\  Array\  \#(0\  0\  0\  0\  0\  0\  0\  0)\leqno{(\%o4) }
(%i5)	fillarray (a2, [1, 2, 3, 4, 5]);
Lisp\  Array\  \#(1\  2\  3\  4\  5\  5\  5\  5)\leqno{(\%o5) }

Как видно из рассмотренных примеров, длина списка может и не совпадать с размерностью массива. Если указан тип массива, он должен заполняться элементами того же типа. Удаление массивов из памяти осуществляется функцией remarray.

Кроме того, для изменения размерности массива имеется функция rarray(A,dim_1,... ,dim_n). Новый массив заполняется элементами старого по строкам. Если размер старого массива меньше, чем нового, остаток нового заполняется нулями или false (в зависимости от типа массива).

2.7.3 Матрицы и простейшие операции с ними

В Maxima определены прямоугольные матрицы.

Основной способ создания матриц — использования функции matrix. Синтаксис вызова: matrix(row_1,... ,row_n). Каждая строка — список выражений, все строки одинаковой длины. На множестве матриц определены операции сложения, вычитания, умножения и деления. Эти операции выполняются поэлементно, если операнды — две матрицы, скаляр и матрица или матрица и скаляр. Возведение в степень возможно, если один из операндов — скаляр. Перемножение матриц (в общем случае некоммутативная операция) обозначается символом ". ". Операция умножения матрицы самой на себя может рассматриваться как возведение в степень. Возведение в степень -1 — как обращение (если это возможно).

Пример создания двух матриц:

(%i1)	x: matrix ([17, 3], [-8, 11]);
\leqno{(\%o1)}\left[\begin{array}{ll}
17 & 3 \\ 
-8 & 11
\end{array}\right]
(%i2)	y: matrix ([%pi, %e], [a, b]);
\leqno{(\%o2)}\left[\begin{array}{ll}
\pi &  e \\ 
a & b
\end{array}\right]

Выполнение арифметических операций с матрицами:

(%i3)	x+y;
\leqno{(\%o3)}\left[\begin{array}{ll}
\pi +17 & e+3\\ 
a-8 & b+11
\end{array}\right]
(%i4)	x-y;
\leqno{(\%o4)}\left[\begin{array}{ll}
17 -\pi & 3-e \\ 
-a-8 & 11-b
\end{array}\right]
(%i5)	x*y;
\leqno{(\%o5)}\left[\begin{array}{ll}
17 \,\pi & 3 \,e \\ 
-a\,8 & 11\,b
\end{array}\right]
(%i6)	x/y;
\leqno{(\%o6)}\left[\begin{array}{ll}
\frac{17}{\pi } & 3\,{e}^{-1} \\ 
-\frac{8}{a} & \frac{11}{b}
\end{array}\right]

Обратите внимание — операции выполняются поэлементно. При попытке выполнять арифметические операции, как представлено выше, над матрицами различных размеров, выдаётся ошибка.

Пример операций с матрицами и скалярами:

(%i9)	x^3;
\leqno{(\%o9)}\left[\begin{array}{ll}
4913 & 27 \\ 
-512 & 1331
\end{array}\right]
(%i10)	3^x;
\leqno{(\%o10)}\left[\begin{array}{ll}
129140163 & 27 \\ 
\frac{1}{6561}   & 177147
\end{array}\right]

Умножение матрицы на матрицу:

(%i11)	x.y;
\leqno{(\%o11)}\left[\begin{array}{ll}
3\,a+17\,\pi & 3\,b+17\,e \\ 
11\,a-8\,\pi  &  11\,b-8\,e
\end{array}\right]
(%i12)	y.x;
\leqno{(\%o12)}\left[\begin{array}{ll}
17\,\pi -8\,e & 3\,\pi +11\,e \\ 
17\,a-8\,b &  11\,b+3\,a
\end{array}\right]

Очевидно, что для успешного перемножения матрицы должны быть согласованы по размерам. Возведение в степень -1 даёт обратную матрицу:

(%i13)	x^^-1;
\leqno{(\%o13)}\left[\begin{array}{ll}
\frac{11}{211} & -\frac{3}{211} \\ 
\frac{8}{211} & \frac{17}{211}
\end{array}\right]
(%i14)	x.(x^^-1);
\leqno{(\%o14)}\left[\begin{array}{ll}
1 & 0 \\ 
0 & 1
\end{array}\right]

Стоит обратить внимание, что операции x^^-1 и x^-1 дают разный результат!

Пример:

(%i2)	x^-1;
\leqno{(\%o2)}\left[\begin{array}{ll}
\frac{1}{17} & \frac{1}{3}\\
-\frac{1}{8} & \frac{1}{11}
\end{array}\right]
(%i3)	x^^-1;
\leqno{(\%o3)}\left[\begin{array}{ll}
\frac{11}{211} & -\frac{3}{211}\\ 
\frac{8}{211}& \frac{17}{211}
\end{array}\right]

Функция genmatrix возвращает матрицу заданной размерности, составленную из элементов двухиндексного массива. Синтаксис вызова:

  • genmatrix (a, i_2, j_2, i_1, j_1)
  • genmatrix (a, i_2, j_2, i_1)
  • genmatrix (a, i_2, j_2)

Индексы i_1,j_1 и i_2,j_2 указывают левый и правый нижний элементы матрицы в исходном массиве.

Пример:

(%i1)	h [i, j] := 1 / (i + j - 1);
{h}_{i,j}:=\frac{1}{i+j-1}\leqno{(\%o1) }
(%i2)	genmatrix(h,3,3);
\leqno{(\%o2)}\left[\begin{array}{lll}
1 & \frac{1}{2} & \frac{1}{3}\\ 
\frac{1}{2} & \frac{1}{3} & \frac{1}{4}\\
\frac{1}{3} & \frac{1}{4} & \frac{1}{5}
\end{array}\right]
(%i3)	array (a, fixnum, 2, 2);
a\leqno{(\%o3) }
(%i4)	a [1, 1] : %e;
e\leqno{(\%o4) }
(%i5)	a [2, 2] : %pi;
\pi \leqno{(\%o5) }
(%i6)	genmatrix (a, 2, 2);
\leqno{(\%o6)}\left[\begin{array}{ll}
e & 0\\ 
0 & \pi
\end{array}\right]

Функция zeromatrix возвращает матрицу заданной размерности, составленную из нулей (синтаксис вызова zeromatrix(m,n)).

(%i7)	zeromatrix(2,2);
\leqno{(\%o7)}\left[\begin{array}{ll}
0 & 0\\ 
0 & 0
\end{array}\right]

Функция ident возвращает единичную матрицу заданной размерности (синтаксис ident(n))

(%i9)	ident(2);
\leqno{(\%o9)}\left[\begin{array}{ll}
1 & 0 \\ 
0 & 1
\end{array}\right]

Функция copymatrix(M) создаёт копию матрицы M. Обратите внимание, что присваивание не создаёт копии матрицы (как и присваивание не создаёт копии списка).

Пример:

(%i1)	a:matrix([1,2],[3,4]);
\leqno{(\%o1)}\left[\begin{array}{ll}
1 & 2 \\ 
3 & 4
\end{array}\right]
(%i2)	b:a;
\leqno{(\%o2)}\left[\begin{array}{ll}
1 & 2 \\ 
3 & 4
\end{array}\right]
(%i3)	b[2,2]:10;
10\leqno{(\%o3) }
(%i4)	a;
\leqno{(\%o4)}\left[\begin{array}{ll}
1 & 2 \\ 
3 & 10
\end{array}\right]

Присваивание нового значения элементу матрицы b изменяет и значение соответствующего элемента матрицы a. Использование copymatrix позволяет избежать этого эффекта.

Функции row и col позволят извлечь соответственно строку и столбец заданной матрицы, получая список. Синтаксис вызова:

  • row(M,i) — возвращает i-ю строку;
  • col(M,i) — возвращает i-й столбец.

Функции addrow и addcol добавляют к матрице строку или столбец соответственно. Синтаксис вызова:

  • addcol(M,list_1,... ,list_n)
  • addrow(M,list_1,... ,list_n)

Здесь list_1,... ,list_n — добавляемые строки или столбцы.

Пример:

(%i1)	a:matrix([1,2],[3,4]);
\leqno{(\%o1)}\left[\begin{array}{ll}
1 & 2 \\ 
3 & 4
\end{array}\right]
(%i2)	b:addrow(a,[10,20]);
\leqno{(\%o2)}\left[\begin{array}{ll}
1 & 2\\
3 & 4\\ 
10 & 20
\end{array}\right]
(%i3)	addcol(b,[x,y,z]);
\leqno{(\%o3)}\left[\begin{array}{lll}
1 & 2 & x\\
3 & 4 & y\\
10 & 20 & z
\end{array}\right]

Функция submatrix возвращает новую матрицу, состоящую из подматрицы заданной. Синтаксис вызова:

  • submatrix(i_1,... ,i_m,M,j_1,... ,j_n)
  • submatrix(i_1,... ,i_m,M)
  • submatrix(M,j_1,... ,j_n)

Подматрица строится следующим образом: из матрицы M удаляются строки i_1,... ,i_m и j_1,... ,j_n.

Пример (используем последний результат из предыдущего примера, удаляем третью строку и третий столбец):

(%i6)	submatrix(3,%,3);
\leqno{(\%o6)}\left[\begin{array}{ll}
1 & 2 \\ 
3 & 4
\end{array}\right]

Для заполнения матрицы значениями некоторой функции используется функция matrixmap (аналог map, apply, fullmap). Синтаксис вызова: matrixmap(f,M). Функция matrixmap возвращает матрицу с элементами i,j, равными f(M[i,j]).

Пример:

(%i1)	a:matrix([1,2],[3,4]);
\leqno{(\%o1)}\left[\begin{array}{ll}
1 & 2 \\ 
3 & 4
\end{array}\right]
(%i2)	f(x):=x^2;
f\left( x\right) :={x}^{2}\leqno{(\%o2) }
(%i3)	matrixmap(f,a);
\leqno{(\%o3)}\left[\begin{array}{ll}
1 & 4 \\ 
9 & 16
\end{array}\right]

Для работы с матрицами существует ещё много функций, но они относятся к решению различных задач линейной алгебры, поэтому обсуждаются ниже, в главе 3.2.