> X:= a: Y:= X: Y:= b: [X, Y]; ⇒ [a, b]
> A:= array(1..5, [42, 47, 67, 88, 96]); ⇒ A := [42, 47, 67, 88, 96]
> C:= copy(A); ⇒ C := [42, 47, 67, 88, 96]
> C[3]:= 39: C[5]:= 10: [A[3], A[5]]; ⇒ [67, 96]
> B:= A: B[3]:= 95: B[5]:= 99: [A[3], A[5]]; ⇒ [95, 99]
Создание по copy-процедуре копий объектов указанных двух типов позволяет модифицировать только их копии без изменения самих объектов-оригиналов.
В качестве встроенных индексных атрибутов Maple для table-функции используются: sparse, symmetric, antisymmetric, diagonal и identity (а также определяемые пакетными модулями), детальнее обсуждаемые при рассмотрении матричных объектов. Обсуждение tableтипа структуры данных будет постоянно детализироваться и многоаспектно рассматриваться на протяжении последующих глав книги. Целый ряд полезных средств для работы с табличными объектами представляет и наша Библиотека, прилагаемая к книге [103] и находящаяся в свободном доступе по адресам [109].
В завершение рассмотрения структур данных, поддерживаемых пакетом, будет вполне уместно представить и связанные с объектами array-типа, уже упоминаемые матрицы и векторы. Матрицы являются весьма широко применимым понятием в целом ряде естественно-научных дисциплин, составляя самостоятельный объект исследования современной математики – теорию матриц, выходящую за рамки традиционного университетского курса высшей алгебры. Основу теории матриц составляет алгебра квадратных матриц, для обеспечения которой Maple-язык располагает целым рядом важных и полезных средств, поддерживаемых функциональными средствами – модулей LinearAlgebra и linalg. Данные модули содержат определения 118 и 114 процедур соответственно (в зависимости от релиза пакета; пример приведен для Maple 10), обеспечивающих расширенные средства линейной алгебры по работе с матричными и векторными выражениями. Данные средства не входят в задачу настоящей книги, акцентирующей внимание на вопросах собственно программирования в Maple, поэтому здесь мы лишь представим основные структуры, с которыми имеют дело средства линейной алгебры пакета, а именно: матрицы (matrix) и векторы (vector).
• Матрицы (matrix); в среде Maple-языка матрица представляется в виде 2D-массива, нумерация строк и столбцов которого производится, начиная с единицы. Матрица определяется либо явно через рассмотренную выше array-функцию, например M:= array(1..n, 1..p), или посредством процедуры matrix, имеющей следующие два простых формата кодирования, а именно:
matrix(L) и matrix(n, p, {L|Fn|Lv})
где L – вложенный список (listlist) векторов элементов матрицы, n и p – число ее строк и столбцов, Fn – функция генерации элементов матрицы и Lv – список или вектор элементов матрицы. Функция Fn генерации элементов матрицы определяется в форме пользовательских функции или процедуры, например Fn:=(k,j) -> Ф(k,j), такой, что M[k,j]:= Fn(k,j). Процедура randmatrix модуля linalg позволяет стохастически генерировать матрицы (mxn)-размерности, что удобно, например, для различного рода отладок и тестов.
По тестирующей функции type(M, {matrix|'matrix'(K{, square})}) возвращается true-значение, если М-выражение является матрицей; при этом допускается проверка на принадлежность значений ее элементов заданной К-области и/или квадратности (square) матрицы. В противном случае возвращается false-значение. Так как матрица является одним из типов более общего понятия массив, то функция type(M, 'array') также возвращает true-значение, если М - матрица. Обратное же в общем случае неверно, например, в случае одномерных массивов-векторов. По функции convert(L, 'matrix') возвращается матрица, если L - соответствующая ей вложенная списочная структура. С другой стороны, по функции convert(M, 'multiset') производится конвертация матричной структуры в структуру вложенных списков, каждый элемент-список которой содержит три элемента, где первые два определяют координаты элемента матрицы, а третий – его значение. Следующий фрагмент иллюстрирует вышесказанное.
> M:= matrix(3, 3, [x, y, z, a, b, c, V, G, S]); M := Vax Gby Scz > type(M, 'array'), type(M, 'matrix'), type(M, 'matrix'(symbol, square)); ⇒ true, true, true > convert([[x, y, z], [a, b, c], [V, G, S]], 'matrix'); Vax Gby Scz > convert(M, 'multiset'); [[3, 2, G], [2, 2, b], [1, 1, x], [1, 3, z], [1, 2, y], [2, 1, a], [3, 1, V], [2, 3, c], [3, 3, S]] > convert((a+b)*x/(c+d)*y, 'multiset'); ⇒ [[a+b, 1], [x, 1], [c+d, -1], [y, 1]] |
Следует отметить, что функция convert(M, 'multiset') имеет более широкое применение, допуская в качестве своего первого фактического М-аргумента любое Maple-выражение (при этом, трактовка составляющих возвращаемого ею вложенного списка весьма существенно зависит от типа М-выражения), однако наибольший смысл она имеет для М-выражений типа массив или содержащих термы-множители. Не отвлекаясь на частности, рекомендуем читателю определить влияние типа М-выражения на семантику возвращаемого функцией вложенного списка, тем более, что в ряде случаев это может оказаться весьма полезным приемом в практическом программировании.
Обращение к элементам М-матрицы производится по индексированной M[k, j]-конструкции, идентифицирующей ее (k, j)-й элемент. Посредством этой конструкции элементам М-матрицы можно как присваивать значения, так и использовать их в вычислениях в качестве обычных переменных. Следовательно, данная индексированная конструкция обеспечивает адресное обращение к элементам М-матрицы. Совместное использование функций map и F-функции/процедуры позволяет применять последнюю одновременно ко всем элементам М-матрицы, не идентифицируя их отдельно, т.е. имеет место следующее определяющее соотношение: map(F, M {, <опции>}) ≡ ∀(k)∀(j) (M[k, j] := F(M[k, j] {, <опции>}))
Например:
> M:= matrix(3, 3, [x, y, z, a, b, c, V, G, S]): map(F, M, Art, Kr, Arn);
FFF(((V Art Kr Arna Art Kr Arnx,,, Art,,,Kr,,,Arn))) FFF(((G Art Kr Arnb Art Kr Arny,,,Art,,,Kr,,,Arn))) FFF(((S Art Kr Arnc Art Kr Arnz,,,Art,,, Kr,,, Arn)))
В целом же М-матрица рассматривается как единый объект и для его вывода или возвращения в матричной нотации можно использовать соответствено функции print и {op|evalm}. Однако на основе адресного подхода обработку матриц можно производить и рассмотренными функциональными средствами, ориентированными на сугубо скалярные аргументы. В частности, по конструкции numboccur(eval(M), <Элемент>) можно тестировать наличие в указанной M-матрице заданного элемента. Позволяет это делать и наша процедура belong [103,109].
С другой стороны, целый ряд процедур позволяют обрабатывать М-матрицу как единый объект; такие функции будем называть матричными, т.е. в качестве одного из ведущих аргументов их выступает идентификатор матрицы. Язык Maple располагает достаточно обширным набором матричных процедур, характеристика которых весьма детально рассмотрена в книгах [8-14,55-60,86-88] с той или иной степенью охвата и в полном объеме в справке по пакету. Лишь некоторые из них будут рассмотрены ниже. По функции evalm(VM) возвращается результат вычисленим VM-выражения, содержащего матрицы, применяя функциональные map-преобразования над матрицами. Однако, применение evalm-функции требует особой осмотрительности, ибо Maple-язык перед передачей фактических аргументов evalm-функции может производить их упрощения (предварительные вычисления), в ряде случаев приводящие к некорректным с точки зрения матричной алгебры результатам. Например, по evalm(diff(M, x)) возвращается нулевое значение, тогда как предполагается результат дифференцирования М-матрицы. Это связано с тем обстоятельством, что отличные от матричных функции воспринимают идентификатор матрицы неопределенным. В VM-выражении все неопределенные идентификаторы полагаются evalm-функцией в зависимости от их использования символьными матрицами либо скалярами. В суммах, содержащих матрицы, все скалярные константы рассматриваются умноженными на единичную матрицу, что позволяет естественным образом определять матричные полиномы. Так как операция произведения матриц некоммутативна, то для нее следует использовать матричный (&*)-оператор произведения, приоритет которого идентичен приоритету (*)-оператора скалярного произведения. В качестве операндов бинарного матричного (&*)-оператора могут выступать матрицы либо их идентификаторы. Следующий фрагмент иллюстрирует способы определения, тестирования и вычисления матричных выражений:
> M1:= convert([[42, 47], [67, 89]], 'matrix'): M2:=matrix(2, 3, [x, x^2, x^3, x^3, x^2, x]): > M3:= matrix([[T, G], [G, M]]): M4:=matrix(2, 2, [ln(x), x*sin(x), Catalan*x^2, sqrt(x)]): > map(type, [M1, M2, M3, M4], 'matrix'); ⇒ [true, true, true, true] > map(op, [M1, M2, M3, M4]); 4267 4789, xx3 xx22 xx3, GT MG, Catalan xln(x) 2 x sin (x)> [map(diff, M2, x), map(int, M4, x)]; 31x2 22 xx 31x2, Catalan xx ln(3x) − x3 sin(x2) − x3(x3/2cos) (x) > evalm(10*M1^2 + 17*M1); 4984488909 11221362369 > evalm(M4&*(M1 + M3)); Catalan xln(x) (42 + 2 (T42) + + xTsin) + (xx) ((6767 + + GG)) Catalan xln(x) (47 + 2 (G47) + + Gx sin) + (xx) ((8989 + + MM)) |
С учетом сказанного, примеры фрагмента представляются достаточно прозрачными и каких-либо особых дополнительных пояснений не требуют.