rtabobj := proc() local a b c k j t A M V x y z, , , , , , , , , , , ; assign(a = map(convert, {anames '( rtable')}, 'string'), b = { }, c = { }, x = [ ], y = [ ], z = [ ]); seq `if`( (search(k, "RTABLE_SAVE/" ' ', t ) and t = 1, assign(' 'c = {k, op( )c }), assign('b' = {k, op(b)})), k = a); for k in b do if type(`` k || , 'Array') then A := [ ]k ; for j in c do if convert(`` || k, 'listlist') = convert(`` || j, 'listlist') then A := [op(A), ]j end if end do; x := [op( )x , A] elif type(`` || k, 'Matrix') then M := [ ]k ; for j in c do if convert(`` k || , 'listlist') = convert(`` j || , 'listlist') then M := [op(M), ]j end if end do; y := [op( )y , M] else V := [ ]k ; for j in c do if convert(`` k || , 'listlist') = convert(`` j || , 'listlist') then V := [op(V), ]j end if end do; z := [op(z), V] end if end do; x y z, , end proc > rtabobj(); [["A"], ["A1", "RTABLE_SAVE/12988492", "RTABLE_SAVE/12468956"]], [["M", "RTABLE_SAVE/15041652", "RTABLE_SAVE/15049896"], ["M1", "RTABLE_SAVE/15041652", "RTABLE_SAVE/15049896"]], [["V", "RTABLE_SAVE/3384632"], ["V1", "RTABLE_SAVE/14862784", "RTABLE_SAVE/15017212", "RTABLE_SAVE/15026360"]] |
Вместе с тем, Maple-объекты существенно проще NAG-объектов и несложно конвертируются во вторые. В наших книгах [29,33,42,43,103] и приложенной к ним Библиотеке представлены дополнительные средства конвертации Maple-объектов в NAG-объекты, и наоборот. Наряду с ними, представлен ряд других средств по работе с rtable-объектами, которые существенно расширяют стандартные средства пакета. Эти средства оказываются достаточно полезными при продвинутом программировании разнообразных задач, имеющих дело с rtable-объектами, обеспечивая Maple-программиста целым рядом дополнительных возможностей. Так, например, вызов представленной выше процедуры rtabobj() возвращает трехэлементную последовательность вложенных (в общем случае) списков, где элементы данной последовательности представляют информацию о rtable-объектах в разрезах типов Array, Matrix и Vector соответственно, активных в текущем сеансе. При этом, каждый подсписок первым элементом в строчном формате определяет имя rtable-объекта соответствующего типа, тогда как остальные его элементы определяют в строчном формате соответствующие ему идентификационные номера вида «RTABLE_SAVE/nnnnnnnn». Более детальный анализ данной информации позволяет, например, прослеживать историю работы с rtable-объектами текущего сеанса [42,103].
Процедура MwsRtb(F) анализирует mws-файл F на наличие в нем rtable-объектов [103].
MwsRtb := proc(F::{string, symbol, name}) local a b c d k p h t, , , , , , , ; if not type( ,F 'file') or Ftype(F) ≠ ".mws"then ERROR("%1 is not a mws-datafile or does not exist", F) else assign(a = RS([`\n` = ``], readbytes(F, 'TEXT', ∞))), close(F); if not search( ,a "{RTABLE_HANDLES" ' ', t ) then RETURN( WARNING("rtable-objects do not exist in datafile <%1>", F)) end if; assign(' 'a = a[t + 1 .. -1], c = "{RTABLE "), search( ,a "}{" ' ', t ), assign(b = map(SD, SLD(a[15 .. t − 2], " ")), 'a' = a[t + 1 .. -1]), `if`(1 < nargs and type(args 2[ ], 'symbol'), assign(args 2[ ] = b), NULL) end if; assign(p = SLD(a c, ), d = map2(cat, "RTABLE_SAVE/", b), h = MkDir cat(( [libname ][1][1 .. 2], "\rtbobj"))); for k to nops(p) do assign(' 'a = cat(h, "\_", b k[ ], ".m")), writeline(a, cat(p k[ ][1 .. 4], " ", p k[ ][5 .. -2])), close(a); read a end do; d, WARNING("rtable-objects of datafile <%1> are active in the current session\ and have been saved in directory <%2>; their names are %3", F h, , map2(cat, "_", ,b ".m" )) end proc > MwsRtb("C:/Academy\Examples\MPL9MWS\IdR.mws", 'h'); h; Warning, rtable-objects of datafile <C:/Academy\Examples\MPL9MWS\IdR.mws> are active in a current session and have been saved in directory <c:\program files\ maple 9\rtbobj>; their names are [_5290620.m, _5603484.m, _5188712.m] ["RTABLE_SAVE/5290620", "RTABLE_SAVE/5603484", "RTABLE_SAVE/5188712"] [5290620, 5603484, 5188712] |
При наличии таких объектов возвращаются их вызовы в строчном формате, иначе возвращается NULL-значение. Через необязательный второй аргумент возвращаются идентификационные номера (rtable-индексы) rtable-объектов, находящихся в файле F.
Весьма детальный обзор функциональных средств модуля LinearAlgebra, его базовые структуры данных, средства их создания и алгебра над ними детально рассмотрены в вышеупомянутых книгах [13,14,29,30,33]. Пакетный модуль LinearAlgebra предназначен как для интерактиного режима использования, так и для эффективного программирования в Maple. Для этого пакет прикладных программ линейной алгебры фирмы NAG был имплантирован в среду пакета Maple как программный модуль. Данная организация позволяет обращаться к его средствам следующими двумя способами, а именно:
(1) как к стандартному модулю пакета по конструкции формата: LinearAlgebra[Функция](Аргументы) (2) как к программному модулю по конструкции формата:
LinearAlgebra:- Функция(Аргументы)
В зависимости от удобства и ситуации может быть выбран любой из двух способов. Как правило, это определяется как опытом пользователя, так и самим алгоритмом программируемой в среде пакета задачи.
Начиная с 6-го релиза, пакет Maple предоставляет два альтернативных выбора при решении задач линейной алгебры, базирующихся соответственно на модулях LinearAlgebra и linalg. Средства первого модуля и его концепция были довольно детально рассмотрены в наших книгах [8-14], тогда как второго в книгах [29-33]. Отметим здесь только наиболее характерные отличительные черты модуля LinearAlgebra. Прежде всего, модуль LinearAlgebra представляет собой большой набор процедур линейной алгебры, покрывающих почти все функциональные возможности пакета linalg. Вместе с тем, он имеет значительно более четкие структуры данных, располагает дополнительными средствами для создания специальных типов матриц, и улучшенными возможностями для решения матричных задач. Его преимущества особенно наглядны при вычислениях с большими числовыми матрицами, элементами которых являются значения float-типа (как данные пакетной float-арифметики, так и данные машинной float-арифметики). В качестве иллюстрации представим ряд примеров использования средств модуля LinearAlgebra для решения некоторых массовых задач линейной алгебры:
> alias(LA = LinearAlgebra): A:= <<64, 59, 39>|<42, 47, 67>|<38, 62, 95>>: B:= <10, 17, 99>: > LA[Transpose](LA[LinearSolve](A, B)), LA[Transpose](LA[LeastSquares](A, B)); -33081855 , 69211855, -67 , -33081855 , 69211855, -67 > LA:- Determinant(A); Error, `LA` does not evaluate to a module > LA[Determinant](A); ⇒ -33390 > M:= rtable([[64, 59, 39], [42, 47, 67], [43, 10, 17]], subtype = Matrix, readonly = true); 644243 594710 671739 M := > LA[Determinant](M), LA[Rank](M), LA[Trace](M); ⇒ 73670, 3, 128 > evalf(LA[Eigenvalues](M, output = 'Vector[row]')); [131.7149459, -1.85747297 + 23.57676174 I, -1.85747297 - 23.57676174 I] > evalf(LA[MatrixInverse](M, method='LU'), 6); ⇒ 0.00175105-0.02173200.0294150 -0.00799511-0.008320890.0257500 0.00719424-0.03597120.0287770 |
> evalf(LA[QRDecomposition](evalf(M), output = 'NAG'), 6); 0.2766779999999999800.283266000000000018-87.8008999999999986 -0.664429999999999965-70.3864999999999981-28.9090999999999988 -26.8831999999999988-68.803399999999996429.0239000000000011 , 1.728920000000000011.387480000000000040. > LA[FrobeniusForm](M); LA[CharacteristicPolynomial](%, h); 010 001 73670128-70 h3 − 128 h2 + 70 h − 73670 > evalf(LA[SingularValues](evalf(M), output = 'list'), 6); ⇒ [136.209, 30.5125, 17.7259] > evalf(LA[Eigenvectors](evalf(M), output = 'vectors'), 8); [0.720627899999999988 + 0. I , 0.278720599999999984 + 0.381360960000000027 I , 0.278720599999999984 − 0.381360960000000027 I] [0.613184240000000047 + 0. I , -0.671878590000000053 + 0. I , -0.671878590000000053 + 0. I] [0.323574589999999995 + 0. I , 0.315224249999999984 − 0.475490770000000006 I , 0.315224249999999984 + 0.475490770000000006 I] > LinSolve:=(P::package, A::{Matrix, matrix}, B::{Vector, vector}) -> op([assign('K'=with(P)), `if`(`if`(P = linalg, det, Det)(A)<>0, `if`(P = LinearAlgebra, LinearSolve, linsolve)(A, B), ERROR("Matrix is singular"))]): LinSolve(LinearAlgebra, A, B); # (1) LinearSolve645939 424767 389562, 101799 > a:= matrix([[64, 59, 39], [42, 47, 67], [38, 62, 95]]): b:= vector([10, 17, 99]): # (2) > alias(la = linalg): evalf(LinSolve(linalg, a, b)); ⇒ [-4.75624439, 5.94860737, -0.937646002] |
Прежде всего, следует обратить внимание на одно важное обстоятельство. С целью устранения неудобства, связанного с многократным использованием довольно длинного имени модуля LinearAlgebra, ему был присвоен алиас "LA", однако этот довольно удобный подход выявил ряд его особенностей. Прежде всего, алиас нельзя использовать в конструкциях вида LA:- Функция, как это хорошо иллюстрирует третий пример фрагмента. В этом случае следует использовать конструкцию LA[Функция]. Общей рекомендацией является определение алиаса для имени модуля вне тела процедуры/функции, в таком случае он может использоваться наравне с основным именем. Второй пример фрагмента иллюстрирует решение системы линейных уравнений посредством 2-х процедур LinearSolve и LeastSquares модуля. Посредством Transpose-процедуры результат решения системы линейных уравнений A.X = B по-лучаем в виде вектора-строки. Последующие примеры фрагмента иллюстрируют применение различных процедур пакетного модуля LinearAlgebra. Исключение составляют последние примеры 1 и 2, иллюстрирующие принципиальное отличие модуля linalg от LinearAlgebra относительно их использования внутри определений функций/процедур. В примере (2) показано, что использование вызова with(linalg) внутри тела функции делает доступными процедуры мо- дуля linalg как в области определения самой функции, так и вне ее. Тогда как согласно примера (1) аналогичный подход, но на основе модуля LinearAlgebra не работает, что в определенной мере сужает выразительные возможности программирования с использованием его функциональных средств. Имеется ряд других различий пакетных модулей linalg и LinearAlgebra, обусловленных проблемами полной интеграции второго в среду пакета, однако мы не будем здесь на них останавливаться. Заинтересованный же читатель отсылается к нашим книгам [13-14,29-33,39,41-43,45,46,103].