Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

pmi432 / LR05 / Books / Аладьев - Основы программирования в Maple, 2006

.pdf
Скачиваний:
197
Добавлен:
18.03.2015
Размер:
3.41 Mб
Скачать

По функции Array(ИФ, D, НЗ, <Опции>) создается массив с заданными характеристиками, определяемыми ее фактическими аргументами. Каждый из аргументов функции не является обязательным; если же вызов функции Array определен без фактических аргументов, то возвращается пустой 0-мерный массив. Смысл и форматы кодирования аргументов функции (ИФ - индексирующая функция, D - размерность, НЗ - начальные условия и <Опции>) достаточно прозрачны и особых пояснений не требуют. Поэтому на данном вопросе детальнее останавливаться не будем, а приведем несколько примеров на прямое определение массивов.

> A:= Array(1..6, [42, 47, 67, 62, 89, 96], datatype=integer, readonly): Ao:=Array(): A, Ao;

[42, 47, 67, 62, 89, 96], Array({}, datatype = anything, storage = rectangular, order = Fortran_order)

> A[4]:= 2006;

Error, cannot assign to a read-only Array

> ArrayOptions(A);

datatype = integer, storage = rectangular, order = Fortran_order, readonly

> B:=Array(symmetric, 1..3, 1..3, datatype=integer): B[1, 1]:=42: B[2, 2]:=47: B[3, 3]:=67: B[1, 2]:= 64: B[1, 3]:=59: B[2, 3]:=39: B, ArrayIndFns(B), ArrayOptions(B);

42

64

59

 

 

 

 

47

 

= integer , storage = triangular

 

,

64

39 , symmetric , datatype

 

 

 

 

 

upper

 

 

 

 

 

 

59

39

67

 

 

 

order = Fortran_order

> op(1, B), ArrayOptions(B, order=C_order), ArrayOptions(B);

symmetric , datatype = integer , storage = triangular upper , order = C_order

> ArrayDims(B), ArrayNumDims(B);

1 .. 3, 1 .. 3, 2

> ArrayElems(B);

{(1, 1) = 42, (1, 2) = 64, (1, 3) = 47, (2, 2) = 59, (2, 3) = 39, (3, 3) = 67}

> ArrayNumElems(B, NonZeroStored), ArrayNumElems(B, All);

6, 9

Относительно сугубо Maple-объектов NAG-объекты характеризуются двумя важными чертами, а именно: (1) ссылка на их идентификатор возвращает непосредственно сам объект, не требуя таких функций как evalm, и (2) объекты создаются всегда с определенными элементами, по меньшей мере нулевыми, если не было определено противного. Второе обстоятельство весьма упрощает ряд процедур с такими объектами, не требуя их предварительного обнуления. Обусловлено это тем, что если Maple-объекты изначально ориентированы на символьные вычисления, то NAG-объекты на числовые.

Для работы с Array-объектами Maple-язык располагает рядом полезных функций, детально рассмотренных в наших книгах [13,14,29,30,33]. Примеры предыдущего фрагмента иллюстрируют создание посредством Array-функции одномерного А-массива и двумерного В-мас- сива, а также применение к ним ряда функций работы с массивами, которые ввиду их простоты не требуют дополнительных пояснений.

Вызов процедуры Matrix(n, m, НЗ, <Опции>) возвращает матричную структуру данных (мат- рицу), являющуюся одной из базовых структур, с которыми работают функциональные средства LinearAlgebra-модуля. Первые два формальных аргумента процедуры определяют число строк и столбцов матрицы соответственно; при этом, фактические значения для аргументов могут кодироваться или целыми неотрицательными числами, или диапазонами вида 1 .. h (h целое неотрицательное). Третий аргумент определяет начальные значения, тогда как оп- ции - дополнительные характеристики создаваемого матричного объекта. Все аргументы процедуры необязательны и при их отсутствии возвращается матрица (0х0)-размерности. В общем же случае при создании матричного объекта вызов Matrix-процедуры должен содержать достаточное количество информации о его структуре и элементах. Сказанное по начальным значениям относительно rtable-функции в полной мере переносится и на третий аргумент Matrix-процедуры. Среди допустимых опций (четвертый аргумент) многие аналогичны об-

61

щему случаю rtable-функции, рассмотренной выше. Однако, среди них имеются и специфические для матричной структуры. Детальнее с описанием опций функции можно познакомиться по справке пакета. Приведем примеры на создание некоторых простых матричных объектов и их тестирование.

> M1:=Matrix(3, [[42,47,67], [64,59,39], [89,96,62]], readonly): M2:=Matrix([[a,b], [c,d]]): M1, M2;

42

47

67

a

b

 

59

 

64

39 ,

 

 

 

 

 

 

89

96

62

c

d

> M1[3, 3]:= 47;

Error, cannot assign to a read-only Matrix

> M3:= Matrix(3, (j, k) -> 4*j^2+11*k^2-89*j-96*k+99*j*k, datatype=integer[2]): M4:= Matrix(1..3, 1..3, rand(42..99, 0.58)):; M5:= <<42,47,67>| <64, 59, 39>|<10, 17, 44>>: M3, M4, M5;

-71

-35

23

53

47

43

42

64

10

 

86

 

 

62

 

 

59

 

-49

243 , 65

92 , 47

17

-19

215

471

77

46

69

67

39

44

> map(type, [M1, M2, M2, M5], 'Matrix');

[true, true, true, true]

> M6:= Matrix(2, {(1, 1)=64, (1, 2)=59, (2, 1)=10, (2, 2)=17});

64 59

M6 := 10 17

> type(M5,'matrix'), whattype(M5), type(M6,'Array'), type(M6,'Matrix');

false, Matrix, false, true

Фрагмент представляет различные способы определения Matrix-объектов, принцип которых легко усматривается из самих примеров. Из фрагмента также следует, что в компактном виде Matrix-объект можно определять конструкцией следующего простого вида:

M:= <M11, M21, M31>|<M12, M22, M32>|<M13, M23, M33>

недостатком которой является невозможность определения для матрицы в точке определения других ее характеристик. Более того, последний пример фрагмента иллюстрирует тот факт, что type-функция не распознает Matrix-объект в качестве Maple-матрицы, тогда как тестирующая whattype-процедура определяет его как Matrix-объект. Детальнее с описанием и применением функции Matrix можно ознакомиться в книгах [13,14] и в справке по пакету. С учетом сказанного Matrix-объекты (NAG-матрицы) достаточно прозрачны и за более детальной информацией по их определению можно обращаться к справке по пакету (например,

оперативно по конструкции ?Matrix).

Наконец, по функции Vector[T](n, НЗ, <Опции>) возвращается векторная структура данных (вектор), являющаяся одной из основных структур, с которыми работают функциональные средства LinearAlgebra-модуля пакета. Индекс Т определяет тип вектора (column - столбец, row - строка, по умолчанию полагается column). Первый формальный аргумент функции определяет число элементов вектора; при этом, фактические значения для аргумента могут кодироваться или целым неотрицательным числом, либо диапазоном вида 1..h. Второй аргумент определяет начальные значения, тогда как опции - дополнительные характеристики создаваемого векторного объекта. Все аргументы функции необязательны и при их отсутствии возвращается вектор 0-размерности, т.е. элемент 0-мерного векторного пространства. В общем же случае при создании векторного объекта вызов Vector-функции должен содержать достаточное количество информации о его структуре и элементах. Сказанное выше по начальным значениям относительно rtable-функции в полной мере переносится и на второй аргумент Vector-функции. Среди допустимых опций (третий аргумент) многие аналогичны общему случаю rtable-функции, рассмотренной выше. Однако допускаемые ими значения имеют векторную специфику. Детальнее с описанием опций Vector-функции можно познакомиться в справке по пакету. Приведем простые примеры на создание векторных объектов.

62

> V1:= Vector(1..4, [42, 47, 67, 89]): V2:= Vector[row](4, {1=64, 2=59, 3=39, 4=17}): V3:= Vector(1..4): V1, V2, V 3;

 

42

 

0

 

 

 

 

 

47

 

0

 

, [64, 59, 39,

17],

 

 

67

 

0

 

 

 

 

 

89

 

0

> VectorOptions(V2);

shape = [], datatype = anything, orientation = row, storage = rectangular, order = Fortran_order

> V4:= <Sv, Ar, Art, Kr>: V5:= <Sv|Ar|Art|Kr>: V4, V5, VectorOptions(V4, readonly);

 

Sv

 

 

 

 

 

Ar

 

, [Sv, Ar, Art, Kr ], false

Art

 

 

 

 

Kr

> V6:= Vector[row](6, rand(42..99)): V7:=Vector(): V6, type(V6, vector), whattype(V6), V7;

[57, 89, 80, 52, 48, 71], false, Vector[row], []

Фрагмент представляет различные способы определения Vector-объектов, принцип которых усматривается из самих примеров. Из фрагмента также видно, что в компактной форме объект Vector-типа можно определять конструкциями следующего простого вида:

V:= <V1, V2, V3, …, Vn> или V:= <V1|V2|V3| … |Vn>

недостатком которых является невозможность определения для вектора в точке его определения других характеристик. При этом, первый формат определяет вектор-столбец, тогда как второй – вектор-строку. Более того, последний пример фрагмента иллюстрирует тот факт, что type-функция не распознает Vector-объект в качестве Maple-вектора, тогда как тестирующая whattype-процедура определяет его как Vector-объект. С учетом сказанного Vector-типа объекты (NAG-векторы) достаточно прозрачны и за более детальной информацией по их определению можно обращаться к справке (например, оперативно по конструкции ?Vector).

Как уже отмечалось, между Maple-объектами (array, vector и matrix) и NAG-объектами (Array, Vector и Matrix) имеются принципиальные различия. Более того, классификация вторых относительно тестирующих функции type и про цедуры whattype выгодно отличается однозначностью, тогда как первые распознаются whattype-процедурой как объекты array-типа. В приведенном ниже фрагменте этот момент иллюстрируется весьма наглядно:

>a:=array(1..2, 1..2, [[42,47], [64,59]]): A:=Array(1..3, 1..3): v:=vector([1,2,3]): V:=Vector([1,2,3]): m:=matrix([[G, S, Vic], [47, 67, 42]]): M:=Matrix([[G, S, Vic], [47, 67, 42]]):

>type(a,'array'), type(a,'matrix'), type(v,'vector'), type(v,'array'), type(m,'matrix'), type(m,'array');

true, true, true, true, true, true

>type(A, 'Array'), type(A, 'Matrix'), type(V, 'Vector'), type(V, 'Array'), type(M, 'Matrix'), type(M, 'Array'); true, false, true, false, true, false

>map(whattype, map(eval, [a, v, m])), map(whattype, [A, V, M]);

[array, array, array], [Array, Vector[column], Matrix]

>convert(a, 'listlist'), convert(A, 'listlist'); [[42, 47], [64, 59]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

>a[1]:= [x, y, z];

Error, array defined with 2 indices, used with 1 indices

> A[1]:= [x, y, z]; A[1] := [x, y, z]

> convert(A, 'listlist'); [[[x, y, z], [x, y, z], [x, y, z]], [0, 0, 0], [0, 0, 0]]

>Ar:=Array(1..2, 1..2, 1..4, [[[64, 59, 39, 10], [47, 67, 42, 6]], [[c2, b2, a2, 17], [c3, b3, a3, 6]]]):

>convert(Ar, 'listlist'); [[[64, 59, 39, 10], [47, 67, 42, 6]], [[c2, b2, a2, 17], [c3, b3, a3, 6]]]

>Ar[1, 2]:= AVZ; Ar[1, 2] := AVZ

>convert(Ar, 'listlist'); [[[64, 59, 39, 10], [AVZ, AVZ, AVZ, AVZ]], [[c2, b2, a2, 17], [c3, b3, a3, 6]]]

 

a

b

c

> A1:= Array(1..3, 1..3, [[a, b, с], [x, y, z], [42, 47, 6]]);

 

y

 

A1 := x

z

 

42

47

6

63

 

 

a

b

c

 

> A1[2]:= [Grodno, Tallinn]: A1;

 

 

 

 

 

 

 

[Grodno , Tallinn ]

[Grodno ,

 

 

[Grodno , Tallinn ]

Tallinn ]

 

 

42

47

6

 

 

 

 

В целом ряде случаев точная идентификация rtable-объектов тестирующими средствами пакета играет весьма существенную роль. Еще на одном моменте данного фрагмента имеет смысл обратить внимание, а именно. Если 2-мерный Maple-массив (array) не допускает возможности замены своих строк путем присвоения, инициируя ошибочную ситуацию, то массив NAG (Array) такую операцию допускает, однако присваиваемое значение дублируется по числу элементов строки. Соответствующим образом это обобщается и на n-мерные массивы, как показано выше. В ряде случаев это может представить практический интерес.

Вместе с тем, Maple-объекты существенно проще NAG-объектов и несложно конвертируются во вторые. В наших книгах [29,33,42,43,103] и приложенной к ним библиотеке представлены дополнительные средства конвертации Maple-объектов в NAG-объекты, и наоборот. Наряду с ними, представлен ряд других средств по работе с rtable-объектами, которые существенно расширяют стандартные средства пакета. Эти средства оказываются достаточно полезными при продвинутом программировании разнообразных задач, имеющих дело с rtable-объекта- ми, обеспечивая целый ряд дополнительных возможностей.

Весьма детальный обзор функциональных средств модуля LinearAlgebra, его базовые структуры данных, средства их создания и алгебра над ними детально рассмотрены в вышеупомянутых книгах [13,14,29,30,33]. Пакетный модуль LinearAlgebra предназначен как для интерактиного режима использования, так и для эффективного программирования в Maple. Для этого пакет прикладных программ линейной алгебры фирмы NAG был имплантирован в среду пакета Maple как программный модуль. Такая организация позволяет обращаться к его средствам следующими двумя способами, а именно:

(1) как к стандартному модулю пакета по конструкции формата:

LinearAlgebra[Функция](Аргументы)

(2) как к программному модулю по конструкции формата:

LinearAlgebra:- Функция(Аргументы)

В зависимости от удобства и ситуации может быть выбран любой из двух способов. Как правило, это определяется как опытом пользователя, так и самим алгоритмом программируемой в среде пакета задачи.

Начиная с 6-го релиза, пакет Maple предоставляет два альтернативных выбора при решении задач линейной алгебры, базирующихся соответственно на модулях linalg и LinearAlgebra. Средства первого модуля и его концепция были достаточно детально рассмотрены в наших книгах [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));

-3308 6921 -6 -3308 6921 -61855, 1855, 7 , 1855, 1855, 7

> LA:- Determinant(A);

Error, `LA` does not evaluate to a module

64

>LA[Determinant](A); -33390

>M:= rtable([[64, 59, 39], [42, 47, 67], [43, 10, 17]], subtype = Matrix, readonly = true);

64

59

39

 

47

 

M := 42

67

43

10

17

> 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]

 

0.00175105

-0.00832089

0.0287770

> evalf(LA[MatrixInverse](M, method = 'LU'), 6);

 

 

 

 

 

0.0294150

-0.00799511

 

 

 

-0.0359712

 

 

-0.0217320

0.0257500

0.00719424

> evalf(LA[QRDecomposition](evalf(M), output = 'NAG'), 6);

-87.8008999999999986

-70.3864999999999981

-68.8033999999999964

1.72892000000000001

 

-28.9090999999999988

 

 

 

 

0.276677999999999980

-26.8831999999999988 ,

1.38748000000000004

 

-0.664429999999999965

 

 

0.

 

0.283266000000000018

29.0239000000000011

 

 

> LA[FrobeniusForm](M); LA[CharacteristicPolynomial](%, h);

0

0

73670

 

0

 

1

-70

0

1

128

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.381360960000000027I , 0.2787205999999999840.381360960000000027I ]

[0.613184240000000047+ 0. I , -0.671878590000000053+ 0. I , -0.671878590000000053+ 0. I ]

[0.323574589999999995+ 0. I , 0.3152242499999999840.475490770000000006I ,

0.315224249999999984+ 0.475490770000000006I ]

> 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)

64

42

38

 

10

 

 

 

 

 

 

 

 

47

 

 

 

 

LinearSolve 59

62 ,

17

 

 

67

 

 

 

 

39

95

 

99

 

> 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.756244385, 5.948607367, -0.9376460018]

Прежде всего, следует обратить внимание на одно важное обстоятельство. С целью устранения неудобства, связанного с многократным использованием довольно длинного имени модуля LinearAlgebra, ему был присвоен алиас "LA", однако такой достаточно удобный подход выявил ряд его особенностей. Прежде всего, алиас нельзя использовать в конструкциях вида LA:- Функция, как это хорошо иллюстрирует третий пример фрагмента. В этом случае следует использовать конструкцию LA[Функция]. Общей рекомендацией является определение алиаса для имени модуля вне тела процедуры/функции, в таком случае он может использоваться наравне с основным именем. Второй пример фрагмента иллюстрирует решение системы линейных уравнений посредством процедур LinearSolve и LeastSquares модуля. Посредством Transpose-процедуры результат решения системы линейных уравнений A.X=B получаем в виде вектора-строки. Последующие примеры фрагмента иллюстрируют применение различных функций LinearAlgebra-модуля. Исключение составляют последние примеры 1 и 2, иллюстрирующие принципиальное отличие модуля linalg от LinearAlgebra относительно их использования внутри определений функций/процедур. В примере (2) показано, что использование вызова with(linalg) внутри тела функции делает доступными процедуры linalg-модуля как в области определения самой функции, так и вне ее. Тогда как сог-

65

ласно примера (1) аналогичный подход, но на основе модуля LinearAlgebra не работает, что в определенной мере сужает выразительные возможности программирования с использованием его функциональных средств. Имеется ряд других различий пакетных модулей linalg и LinearAlgebra, обусловленных проблемами полной интеграции второго в среду пакета, однако мы не будем здесь на них останавливаться. Заинтересованный читатель отсылается к нашим книгам [13-14,29-33,39,41-43,45,46].

С учетом сказанного рассмотренные средства линейной алгебры и их базовые структуры данных не представляют каких-либо затруднений при использовании их знакомым с основами линейной алгебры читателем. В свете сказанного следует иметь в виду, что нами были представлены наиболее употребительные форматы матрично-векторных средств Maple-языка с определенными акцентами скорее на особенностях их реализации и выполнения, чем на их математической сущности, хорошо известной имеющим опыт в данном разделе математики. Поэтому за деталями их описания необходимо обращаться к Help-системе пакета либо к цитированной выше литературе. Однако, многие вопросы снимаются при практической апробации рассмотренных средств. В настоящее время имеется целый ряд внешних модулей пакета (часть из них поставляется по выбору), весьма существенно расширяющих рассмотренные базовые средства матрично-векторных операций Maple-языка. Данные средства постоянно расширяются. На базе рассмотренных средств Maple-языка пользователь имеет возможность программировать собственные, недостающие для решения его матрично-векторных задач, средства. Пакет постоянно, расширяя свои приложения, между тем, не в состоянии в должной мере учесть все потребности, поэтому его программная среда и предоставляет пользователям возможность расширять его новыми средствами под ваши нужды. Типичным примером такого подхода и является наша библиотека программных средств [41, 103]. Ниже вопросы решения задач линейной алгебры в среде Maple (учитывая специфику настоящей книги) не рассматриваются. Заинтересованный читатель отсылается к книгам [8-14,78,84,86,88,55,59- 62], а также к [91] с адресом сайта, с которого можно бесплатно загрузить некоторые книги.

Псевдослучайные числа. Еще с одним видом значений - псевдослучайных пользователь имеет возможность работать на основе встроенного генератора псевдослучайных чисел (ГПСЧ), активизируемого по rand-процедуре, имеющей три формата кодирования. По вызову rand() возвращается псевдослучайное неотрицательное integer-число (ПСЧ) длиной в 12 цифр, тогда как по вызову rand({n|n..p}) (n, p - целочисленные значения и n p) возвращается равномерно распределенное на интервале соответственно [0 .. n] и [n .. p] целое ПСЧ. Для установки начального значения для ГПСЧ используется предопределенная _seed-переменная пакета, имеющая значение 427419669081, которое в любой момент может быть переопределено пользователем, например: _seed:= 2006.

Для этих же целей, но с более широкими возможностями, используется и randomize-проце- дура, кодируемая в одном из допустимых форматов следующего вида: randomize({|n}), где n > 0 - целочисленное выражение, значение которого и присваивается _seed-переменной. Если используется формат randomize()вызова процедуры, то для _seed-переменной устанавливается значение, базирующееся на текущем значении системного таймера. Так как randomize()- вызов возвращает базовое значение для ГПСЧ на основе текущего значения таймера, то таким способом можно достаточно эффективно генерировать различные последовательности ПСЧ. Сохраняя необходимые значения _seed-переменной, можно повторять процесс вычислений с псевдослучайными числами, что особенно важно в случае необходимости проведения повторных вычислений.

Вызов rand может инициировать вывод самого тела соответствующей ей процедуры, рекомендуемый подавлять по завершающему обращение к процедуре двоеточию. В случае же намерений пользователя написать собственную процедуру для подобных целей текст пакетной rand-процедуры может оказаться определенным прообразом. В общем же случае для обеспечения доступа к ГПСЧ рекомендуется использовать конструкции вида Id:= rand({|n|n .. p}), выполнение которых открывает доступ к последовательностям ПСЧ по вызовам Id(), каждое

66

использование которого инициирует получение очередного равномерно распределенного на заданном интервале ПСЧ. Следующий пример иллюстрирует применение рассмотренных средств Maple-языка по работе с псевдослучайными числами:

> rand(); AVZ:= rand(1942 .. 2006): _seed:= 2006: 403856185913

>seq(AVZ(), k=1 .. 10); 2003, 1960, 1944, 1990, 1986, 1972, 1986, 1992, 2006, 1964

>randomize(2006): _seed; 2006

>ПСЧ:= array[1 .. 10]: for k while k <= 10 do ПСЧ[k]:= AVZ() end do:

>seq(ПСЧ[k], k=1 .. 10); 2005, 1946, 1958, 1951, 1983, 1992, 1946, 1955, 1995, 1951

>restart; [_seed, rand(), _seed]; [_seed, 427419669081, 427419669081]

Наряду с приведенными Maple располагает и другими подобными средствами, в частности, для решения статистических задач (модуль stats), работы со стохастическими объектами (мо- дуль RandomTools), стохастической генерации матриц (linalg[randmatrix]), полиномов (про- цедура randpoly) и др. Средства поддержки работы с псевдослучайными числами могут быть использованы во многих вычислительных задачах стохастического и квазистохастического характера, а также в задачах, требующих наборов данных для отладки программ и тестирования вычислительных алгоритмов. Рассмотренные средства широко используются нами в различного рода иллюстративных примерах для генерации числовых данных.

Выше мы уже не раз употребляли такое понятие как математическое выражение (либо просто выражение), являющееся одним из важнейших понятий Maple, да и математики в целом. Работа с математическими выражениями в символьном виде — основа основ символьной математики. Не меньшую роль они играют и в численных вычислениях. Выражение - центральное понятие всех математических систем. Оно определяет то, что должно быть вычислено в численном или символьном виде. Не прибегая к излишнему формализму, несколько поясним данное понятие. Математические выражения строятся на основе чисел, констант, переменных, операторов, вызовов функций/процедур и различных специальных знаков, например, скобок, изменяющих порядок вычислений. Выражение может быть представлено в общепринятом виде (как математическая формула или ее часть) с помощью операторов, например, с*(х + у^2+sqrt(z)) или (a+b)/(c+d), оно может определять просто вызов некоторой функции или процедуры F(x,y,z) либо их комбинацию. Используемые в дальнейшем многочисленные иллюстративные фрагменты представят достаточное число примеров на определение допустимых Maple-выражений, что уже практически позволит уяснить данное ключевое понятие.

Наряду с рассмотренными Maple-язык поддерживает работу с рядом других структур данных (стэк, очередь, функциональные ряды, связные графы, графические объекты и т.д.). В этом направлении нами был создан ряд ролезных средств, расширяющих и дополняющих стандартные. В частности, для работы со структурами типа стэк (stack) и очередь (queue), а также введен новый тип структур прямого доступа (dirax) [41,42,103]. Пока же нам будет вполне достаточно приведенных сведений по типам данных и структур данных для понимания сути излагаемого материала, который ссылается на данные понятия. Переходим теперь к средствам Maple-языка, тестирующим рассмотренные типы данных, структур данных и выражений.

67

1.6. Средства тестирования типов данных, структур

данных и выражений

Согласно аксиоматике пакета под типом понимается Т-выражение, распознаваемое type-фу- нкцией и инициирующее возврат логического {true|false}-значения на некотором множестве допустимых Maple-выражений. В общем случае Т-выражения языка относятся к одной из четырех групп: (1) системные, определяемые идентификаторами языка {float, integer, list, set и др.}; (2) процедурные, когда тип входит в качестве аргумента в саму тестирующую функцию {type(<Выражение>,<Тип>)}; (3) приписанные и (4) структурные, представляющие собой Maple- выражения, отличные от строковых и интерпретируемые как тип {set(<Id>=float)}. К пятой группе можно отнести типы, определяемые модульными средствами пакета. Несколько детальнее о данной классификации типов языка будет идти речь ниже по мере рассмотрения все более сложных Maple-объектов.

Уже неоднократно упоминавшееся понятие выражения, хорошо знакомое обладающему определенной компьютерной грамотностью читателю, является одним из фундаментальных понятий Maple-языка. Понятие выражения Maple-языка аккумулирует такие рассмотренные конструкции языка как: константы, идентификаторы, переменные, данные и их структуры, а также рассматриваемые детально ниже функции, процедуры, модули и т.д. К выражениям в полной мере можно относить, в частности, и такие конструкции языка, как процедуры, ибо их определения допустимо непосредственно использовать при создании сложных выражений. Детальнее на данном вопросе не будем акцентироваться, а отсылаем заинтересованного читателя, например, к таким книгам как [9-14,29-33,59-62,78-89,103].

Для определения рассмотренных типов данных и структур данных язык пакета располагает развитыми средствами, базирующимися на специальных тестирующих процедуре whattype и функциях typematch, type, имеющих следующие форматы кодирования:

{type|typematch}(<Maple-выражение>, {<Тип>|<Множество типов>}) whattype(<Выражение>)

где в качестве первого аргумента выступает произвольное допустимое Maple-выражение, а в качестве второго указывается идентификатор требуемого Типа или их множество. Булева функция {type|typematch} возвращает логическое true-значение, если значение Maple-выраже- ния имеет тип, определяемый ее вторым аргументом, и false-значение в противном случае. В случае определения в качестве второго аргумента множества типов {type|typematch}-функ- ция возвращает логическое true-значение в том случае, если тип значения Maple-выражения принадлежит данному множеству, и false-значение в противном случае. При этом, следует помнить, что в качестве второго аргумента может использоваться только множество ({}-конст-

рукция, а не []-конструкция; данное обстоятельство может на первых порах вызывать ошибки пользователей, ранее работавших с пакетом Mathematica, синтаксис которого для списочной структуры использует именно первую конструкцию). Для второго аргумента {type|typematch}-функции допускается более 202 определяемых пакетом типов (Maple 10), из которых здесь рассмотрим только те, которые наиболее употребляемы на первых этапах программирования в Maple и которые непосредственно связаны с рассматриваемыми нами конструкциями языка пакета: идентификаторы, текст, числовые и символьные данные, структуры данных и др. При этом, typematch-функция имеет более расширенные средства тестирования типов, поэтому детальнее она рассматривается несколько ниже.

Наконец, по тестирующей процедуре whattype(<Выражение>) возвращается собственно тип Maple-выражения, определяемого ее фактическим аргументом. При этом, следует отметить, что данная процедура в ряде случаев решает задачу тестирования более эффективно, например для последовательностных структур и в случае неизвестного типа, что позволяет избегать перебора подвергающихся проверке типов. Тут же уместно отметить, что средства тестирования типов, обеспечиваемые, в частности, {type|typematch}-функцией существенно более

68

развиты, чем подобные им средства пакета Mathematica [28-30, 32, 42, 43]. На основе данных средств предоставляется возможность создания достаточно эффективных средств программного анализа типов данных и их структур. В табл. 5 представлены некоторые допустимые Maple-языком типы, тестируемые {type|typematch}-функцией и используемые в качестве значений ее второго фактического аргумента, а также их назначение.

 

Таблица 5

Id типа

тестируемое Maple-выражение; пояснения и примечания:

algnum

алгебраическое число

array

массив; дополнительно позволяет проверять вид массива, тип его

 

элементов и другие характеристики

Array

массив rtable-типа; дополнительно позволяет проверять вид массива, тип

 

его элементов и другие характеристики

hfarray

массив МАПТ-типа; используется средствами МАПТ

anything

любое допустимое Maple-выражение, кроме последовательности

boolean

логическая константа {true, false, FAIL}

complex

комплексная константа; не содержит нечисловых констант {true, false,

 

FAIL, infinity}, тестирует тип действительной и комплексной частей

complexcons

комплексная константа; a+b*I, где evalf(a) и evalf(b) - float-числа

constant

числовая константа

{odd|even}

{нечетное|четное} целое выражение

float

действительное выражение

fraction

число вида a/b; где a, b - целые числа

indexed

индексированное выражение

infinity

значение бесконечности; +infinity, -infinity, complex infinity

integer

целочисленное выражение

exprseq

последовательность; распознается только whattype-процедурой

{list|set}

{список|множество}; позволяет проверять тип элементов

 

 

listlist

вложенный список (ВС); элементы ВС имеют то же число членов

literal

литерал; значение одного из типов integer, fraction, float, string

matrix

матричный объект, массив; дополнительно позволяет проверять вид

 

массива, тип его элементов и др. характеристики

Matrix

матричный объект rtable-типа, массив; дополнительно позволяет прове-

 

рять вид массива, тип его элементов и другие характеристики

{positive|nega

выражение {> 0|< 0|0}

tive|nonneg}

 

{posint|negint

целое выражение {>0|<0|0}

|nonnegint}

 

numeric

числовое выражение; числовое значение {integer|float| fraction}-типа

protected

protected-свойство; select(type, {unames(), anames(anything)}, 'protected ')

rational

рациональное выражение (дробь, целое)

range

ранжированное выражение; выражение вида a .. b

realcons

действительная константа; включает float-тип и ±infinity

string

строчное выражение

symbol

символ; значение, являющееся не индексированным именем

table

табличный объект; корректно тестирует таблицы, массивы, матрицы

type

тестирует значение на допустимость в качестве типа

vector

вектор, 1-мерный массив; позволяет проверять и тип элементов

Vector

rtable-вектор; позволяет проверять и тип элементов

69

procedure

процедурный объект

`module`

модульный объект

 

 

Смысл большинства типов достаточно прозрачен и особого пояснения не требует. Таблица 5 отражает далеко не полный перечень типов, распознаваемых пакетом. Этот перечень значительно шире и с каждым новым релизом пакета пополняется новыми типами. Например, для Maple 8 этот перечень содержит 176 типов, Maple 9 182 и Maple 10 202. При этом, пользователь также имеет возможность расширять пакет новыми типами и нами был определен целый ряд новых и важных типов, отсутствующих в Maple. Все они описаны в нашей последней книге [103] и включены в прилагаемую к ней библиотеку. Ниже мы представим механизм определения пользовательских типов. Следующий простой фрагмент иллюстрирует применения {type, typematch}-функций и whattype-процедуры:

> [whattype(64), whattype(x*y), whattype(x+y), whattype(a..b), whattype(a::name), whattype([]), whattype(a <= b), whattype(a^b), whattype(Z<>T), whattype(h(x)), whattype(a[3]), whattype({}), whattype(x,y), whattype(table()), whattype(3<>10), whattype(a..b), whattype(47.59), whattype(A and B), whattype(10/17), whattype(array(1 .. 3, [])), whattype(proc() end proc), whattype(a.b), whattype(module() end module), whattype(hfarray(1 .. 3)), whattype("a+b"), whattype(AVZ)];

[integer, *, +, .., ::, list, <=, ^, <>, function, indexed, set, exprseq, table, <>, .., float, and, fraction, array, procedure, function, module, hfarray, string, symbol]

>A:= -64.42: Art:= array(1 .. 3, 1 .. 6): S:= 67 + 32*I: V:= -57/40: L:= {5.6, 9.8, 0.2}: T:= table(): LL:=[[V, 64, 42], [G, 47, 59]]: K:= "Академия": W:= array(1 .. 100): W[57]:= 99:

>[type(A,'algnum'),type(Art,'array'), type(`true`,{'boolean','logical'}), type(S,'complex'(integer)), type(56*Pi, 'constant'), type(56/28, 'even'), type(1.7, 'float'), type(A, 'fraction'), type(A*infinity, infinity), type(V, 'integer'), type(L, 'set'(float)), type(LL, 'listlist'), type(Art, 'matrix'), type(AVZ, 'symbol'), type(A,'negative'), type(V,'negint'), type(S,'numeric'), type(A,'rational'), type(infinity, 'realcons'), type(K, 'string'), type(Art, 'table'), type(T, 'table'), type(real, 'type'), type(W, 'vector'), type(hfarray(1 .. 3), 'hfarray')];

[false, true, true, true, true, true, true, false, true, false, true, true, true, true, true, false, false, false, true,

true, true, true, false, true, true]

> map(whattype,[H, A, eval(Art),`true`, eval(T)]); [symbol, float, array, symbol, table]

> map(type, [64, 47/59, 10.17, `H`, G[3], "TRG"], 'literal'); [true, true, true, false, false, true] > map(type, [range, float, set, list, matrix, string, symbol, array, Array, matrix, `..`, `*`], 'type');

[true, true, true, true, true, true, true, true, true, true, true, true]

Приведенный сводный фрагмент охватывает, практически, все типы, представленные выше и тестируемые рассмотренными {type, typematch}-функциями и whattype-процедурой, достаточно прозрачен и особых пояснений не требует. Ранее отмечалось, что whattype-проце- дура позволяет тестировать последовательностные структуры, тогда как {type|typematch}- функция этого сделать не в состоянии. Более того, в отличие от вторых, whattype-процедура ориентирована, в первую очередь, на тестирование выражений, структурно более сложных, чем данные и структуры данных. При этом, следует иметь в виду, что и данные, и их структуры также можно рассматривать как частный случай более общего понятия выражения.

Так как выражение представляет собой более широкое понятие, чем данные (значения), то для тестирования их типов Maple-язык располагает достаточно развитым набором средств. Прежде всего, для прямого определения типа выражения используется уже упомянутая процедура whattype, которая имеет весьма простой формат кодирования: whattype(<Выражение>) и возвращает тип заданного выражения, если он является одним из нижеследующих:

`*` `+`

`.` `..`

`::`

`<`

`<=`

`<>`

`=` `^`

`||`

`and` array complex

complex(extended_numeric)

exprseq

extended_numeric float fraction

function

hfarray

implies indexed

integer

list

module

moduledefinition

`not` `or`

procedure

series

set

string symbol

table uneval unknown `xor` zppoly

 

Array

Matrix

SDMPolynom

Vector[column]

Vector[row]

 

70

Соседние файлы в папке Books