> map2(F, a1, [x,y,z], a, b, c, d, e); ⇒ [F(a1, x, a, b, c, d, e),F(a1, y, a, b, c, d, e),F(a1, z, a, b, c, d, e)]
> map2(S, x, G(a, b, c), y, z, h, t); ⇒ G(S(x, a, y, z, h, t), S(x, b, y, z, h, t), S(x, c, y, z, h, t))
> map(F, W, x, y, z, t, h), map2(F, W, x, y, z, t, h); ⇒ F(W, x, y, z, t, h), F(W, x, y, z, t, h)
Из данного фрагмента несложно усматривается не только общий принцип выполнения функции map2, но и ее эквивалентность map-функции на определенных наборах аргументов. И выше, и в дальнейшем обе эти функции достаточно часто используются в иллюстративных примерах, лучше раскрывая припцип своего выполнения. Нами был определен ряд новых процедур map3, map4, map5, map6, mapN, mapLS, mapTab (расширяющих возможности функций map и map2), описанных в нашей книге [103] и включенных в состав прилагаемой к ней Библиотеке [109]. Maple-язык располагает обширным набором средств для работы с множествами и списками, которые будут рассматриваться нами детальнее ниже в различных контекстах. Более того, данный набор дополнен нашими средствами работы со списочными структурами [103,109].
•Массив (array) – структура данных, весьма широко используемая Maple, в первую очередь, при работе с матричными и векторными объектами. Массив представляет собой определенное обобщение понятия списочной структуры, когда ее элементам приписываются индексы, идентифицирующие местоположение элементов в структуре. При этом, размерность массива может быть более единицы, а сами индексы элементов могут принимать как положительные, так и отрицательные значения, например:
> M:= array(-10 .. 16, [k$k = 1 .. 27]): M[-7], M[-1], M[0], M[16]; ⇒ 4, 10, 11, 27
Характерной чертой массива является возможность переопределения его элементов, не затрагивая всей структуры в целом. В общем случае М-массив определяется конструкцией следующего достаточно простого вида:
M := array(<Индексная функция>, <Размерность>, <Начальные значения>) где Индексная функция определяет специальный индексный атрибут (например, symmetric атрибут определяет соотношение M[n, m]=M[m, n]). Размерность задается в виде интервалов “а .. в” по каждому из индексов массива и Начальные значения задают исходные значения для элементов массива. При этом, следует иметь в виду, что Maple-язык автоматически не определяет элементы массива, поэтому сразу же после создания массива его элементы являются неопределенными, например: a:= array(1..3): print(a); ⇒ [a1, a2, a3]. Обращение к массиву производится по его идентификатору, а к его элементам в виде индексированного идентификатора, например: print(M); M[5, 6, 2]. Вывод массива на печать производится по print-функции, тогда как по функциям eval и evalm не только предоставляется возможность вывода содержимого массива, но и возврата его в качестве результата для возможности последующего использования в вычислениях. Применение данных функций проиллюстрировано ниже. Ни один из трех аргументов функции array не является обязательным, однако должен присутствовать по меньшей мере один из двух последних для возможности построения массива. Наиболее простой формат array-конструкции имеет следующий вид:
M := array(J11 .. J1n, J21 .. J2n, ..., Jm1 . .Jmn {, []| })
определяя пустой (неопределенный) М-массив mxn-размерности. Переопределение элементов M-массива производится по конструкции вида M[p, k, h, ...]:=<Выражение>, которая остается действительной и для списочных структур. В целом ряде случаев при определении массива целесообразно сразу же задавать начальные значения для его элементов полностью или частично, что иллюстрирует следующий простой фрагмент:
> G:= array(1..3, 1..3, []): G[1,1]:= 42: G[1,2]:= 47: G[1,3]:= 67: G[2,1]:= 89: G[2,2]:= 96: G[2,3]:= 99: G[3,1]:= 95: G[3,2]:= 59: G[3,3]:= 62: print(G); 428995 479659 679962 > assign(MMM = [eval(G), evalm(G)]), MMM, sum(MMM[k], k = 1..2); 429589 475996 679962, 428995 479659 679962, 2 _addmultmp > eval(_addmultmp), map(sqrt, _addmultmp); 428995 479659 679962, > S:= array(1..3, 1..3, [[a, b, c], [d, e, f], [g, h, k]]): map([eval, evala, evalm], S); [[[ad d dg g g,, ,, ,a, a]]] [[[bh h he e e,,, ,b,, b]]] [[[ck k kf f f,, ,, ,c, c]]] > Art:=array(symmetric, 1..4, 1..4): Art[1, 1]:= 42: Art[1, 2]:= 47: Art[1, 3]:= 67: Art[1, 4]:= 62: Art[2, 2]:= 57: Art[2, 3]:= 89: Art[2, 4]:= 96: Art[3, 3]:= 52: Art[3, 4]:= 99: Art[4, 4]:= 9: > whattype(eval(Art)), type(Art, 'array'); ⇒ array, true > [op(0, eval(Art))], [op(1, eval(Art))], [op(2, eval(Art))], [op(3, eval(Art))]; [array], [symmetric], [1 .. 4, 1 .. 4], [[(1, 1) = 42, (2, 2) = 57, (4, 4) = 9, (1, 2) = 47, (3, 3) = 52, (2, 4) = 96, (2, 3) = 89, (1, 4) = 62, (1, 3) = 67, (3, 4) = 99]] |
Как следует из приведенного фрагмента в первом примере определяется пустой G-массив с последующим прямым определением его элементов путем присваивания; в качестве разделителей предложений выбрано двоеточие, чтобы не загромождать документ выводом промежуточных результатов. Затем над полученным G-массивом производятся простые операции, о которых говорилось выше. Во втором примере определяется S-массив той же (3х3)-размерности с одновременным заданием начальных значений для всех его элементов. Результаты определения массива используются для выполнения нестандартной процедуры, использующей рассмотренные выше функции и которая может оказаться полезной в практической работе с объектами типа array. Там же иллюстрируется применение map-функции для поэлементной обработки массива. При определения начальных значений элементов непосредственно в array-конструкции они представляются в виде вложенного списка listlist-типа, структура которого должна строго соответствовать структуре определяемого массива, как это иллюстрируется фрагментом. В качестве встроенных индексных атрибутов пакет использует: symmetric, antisymmetric, sparse, diagonal, identity и ряд определяемых пакетными модулями, которые детально обсуждаются при рассмотрении матричных объектов, например, в нашей книге [12].
При этом, массив одновременно выводится и возвращается по функциям evalm и eval, тогда как по print-функции производится только вывод массива на экран. Предыдущий фрагмент иллюстрирует сказанное. Наряду с этим, примеры фрагмента иллюстрируют использование функции op для получения типа Art-объекта, индексной функции (первый аргумент array-функции), размерности массива (второй аргумент) и содержимого всех начальных значений для входов массива (третий аргумент). Иллюстрируется и применение map-функции для поэлементной обработки массива.
Ниже обсуждение структур данных array-типа будет детализироваться и рассматриваться на протяжении последующих глав книги. При этом, следует иметь в виду то обстоятельство, что частным случаем понятия массива являются векторы (одномерный массив) и матрицы (двухмерный прямоугольный массив), для обеспечения работы с которыми Maple-язык располагает достаточно развитым набором средств, прежде всего, определяемых пакетным модулем linalg, ориентированным на решение задач линейной алгебры [11-14,80-89]. Ниже этот вопрос будет рассмотрен несколько детальнее.
• Массив hfarray-типа. Для обеспечения численных вычислений на основе машинной арифметики с плавающей точкой (МАПТ) Maple-язык поддерживает новый тип структуры данных – массивы hfarray-типа, определяемые hfarray-функцией формата вида:
Mhf := hfarray({<Размерность>}{, <Начальные значения>})
где назначение формальных аргументов функции полностью аналогично случаю функции array; при этом, оба аргумента необязательны. Размерность определяется одним либо несколькими ранжированными выражениями, при ее отсутствии используется установка по умолчанию. Пределы изменения индексов по каждому измерению массива определяются используемой платформой и для 32-битной платформы находятся в диапазоне от -2147483648 до 2147483647 и для 64-битной платформы от -9223372036854775808 до 9223372036854775807.
Данные массивы составляют специальный hfarray-тип, распознаваемый тестирующими функцией type и процедурой whattype. Массивы данного типа в качестве значений своих элементов содержат числа с плавающей точкой двойной точности стандарта IEEE-754. При этом, поддерживаются три специальные значения данного стандарта: +Infinity, Infinity и Quiet NaN, последнее из которых определяется как `undefined`. Для hfarrayфункции в качестве начальных значений могут выступать любые допустимые Mapleвыражения, результатом вычисления которых являются числа float-типа, или значения undefined, infinity, -infinity. Полностью массивы hfarray-типа возвращаются и выводятся на экран соответственно по функциям eval и print. Следующий фрагмент иллюстрирует вышесказанное:
> МАПТ:= hfarray([evalf([sqrt(10), sqrt(17)]), evalf([sqrt(64), sqrt(59)])]); 3.16227766000000000 4.12310562600000008 МАПТ := 8. 7.68114574799999960 > МАПТ:= hfarray([[sqrt(10), sqrt(17)], [sqrt(64), sqrt(59)]]); Error, unable to store '10^(1/2)' when datatype=float[8] > type(МАПТ,'hfarray'), type(МАПТ,'array'), whattype(eval(МАПТ)); ⇒ true, false, hfarray > eval(МАПТ), print(МАПТ); 3.162277660000000008. 4.123105626000000087.68114574799999960 |
3.162277660000000008. 4.123105626000000087.68114574799999960 > evalf(array([[sqrt(10), sqrt(17)], [sqrt(64), sqrt(59)]])); 3.1622776608. 4.1231056267.681145748 |
Структуры данных hfarray-типа широко используются с evalhf-функцией, поддерживающей МАПТ, и достаточно детально рассматриваются, например, в [11,12]. При этом, следует иметь в виду, что работа с такого типа массивами вне рамок МАПТ не эффективна, ибо требуется выполнение соглашений между МАПТ и Maple-арифметикой с плавающей точкой. Последний пример фрагмента иллюстрирует различия между массивами типов array и hfarray при одной и той же установке предопределенной Digits-переменной пакета. Тогда как второй пример фрагмента иллюстрирует недопустимость определения элементов hfarray-массива типами данных, отличными от extended_numericтипа (обобщение типов numeric, undefined либо infinity, -infinity). Для устранения данного недостатка используется evalf-функция.