• 10.1. Задание функций
  • 10.1.1. Задание функции пользователя
  • 10.1.2. Конструктор функций unapply
  • 10.1.3. Визуализация функции пользователя
  • 10.1.4. Импликативные функции
  • 10.2. Управляющие структуры
  • 10.2.1. Условные выражения
  • 10.2.2. Циклы for и while
  • 10.2.3. Вложенные циклы и задание с их помощью матриц
  • 10.2.4. Упрощенная конструкция циклов
  • 10.2.5. Операторы пропуска и прерывания циклов
  • 10.3. Процедуры и процедуры-функции
  • 10.3.1. Простейшие процедуры
  • 10.3.2. Графические процедуры
  • 10.3.3. Просмотр кодов процедур
  • 10.3.4. Оператор возврата значения RETURN
  • 10.3.5. Статус переменных в процедурах и циклах
  • 10.3.6. Объявления переменных локальными с помощью оператора local
  • 10.3.7. Объявления переменных глобальными с помощью слова global
  • 10.3.8. Функция вывода сообщений об ошибках ERROR
  • 10.3.9. Ключи в процедурах
  • 10.3.10. Ключ remember
  • 10.3.11. Ключ builtin
  • 10.3.12. Ключ system
  • 10.3.13. Ключи operator и arrow
  • 10.3.14. Ключ trace
  • 10.3.15. Ключ copyright
  • 10.3.16. Общая форма задания процедуры
  • 10.4. Средства отладки программ
  • 10.4.1. Средства контроля и отладки процедур
  • 10.4.2. Преобразование программных кодов
  • 10.4.3. Работа с отладчиком программ
  • 10.5. Файловые операции с программными модулями
  • 10.5.1. Считывание и запись программных модулей
  • 10.5.2. Создание своей библиотеки процедур
  • 10.6. Программирование символьных операций
  • 10.6.1. Реализация итераций Ньютона в символьном виде
  • 10.6.2. Вычисление интеграла по известной формуле
  • 10.6.3. Вложенные процедуры и интегрирование по частям
  • 10.7. Дополнительные возможности Maple-языка
  • 10.7.1. Переназначение определений
  • 10.7.2. Модули
  • 10.7.3. Макросы
  • 10.7.4. Внешние вызовы
  • 10.7.5. Вызов внешних процедур, написанных на языке С
  • 10.8. Визуально-ориентированное программирование интерфейса
  • 10.8.1. Вызов пакета Maplets
  • 10.8.2. Примеры создания визуально-ориентированного интерфейса
  • 10.8.3. Управление цветом
  • 10.9. Моделирование RLC-цепи с применением маплет-интерфейса
  • 10.9.1. Подготовка процедуры моделирования и тестового примера
  • 10.9. 2. Подготовка окна маплет-интерфейса
  • 10.9.3. Организация связи между процедурой моделирования и маплет-интерфейсом
  • 10.9.4. Моделирование RLC-цепи в окне маплет-интерфейса
  • 10.10. Визуально-ориентированное проектирование маплетов в Maple 10
  • 10.10.1. Ассистент по проектированию маплетов Maplet Builder
  • 10.10.2. Пример проектирования маплета — окна с текстовой надписью
  • 10.10.3. Пример проектирования маплета — окна с графиком функции
  • 10.10.4. Справка по проектированию маплетов
  • Глава 10

    Типовые средства программирования

    По существу все описанные выше средства (операторы, команды и функции) систем Maple 9.5/10 являются компонентами языка программирования системы Maple. Но есть ряд типовых средств программирования (функции пользователя, условные выражения, циклы, средства вывода, маплеты и др.), которые и рассматриваются в данной главе [23, 51, 52]. Применение таких средств существенно расширяет возможности систем Maple в решении ряда математических и научно-технических задач.

    10.1. Задание функций

    10.1.1. Задание функции пользователя

    Хотя ядро Maple 9 5/10, библиотека и встроенные пакеты расширения содержат свыше 3500 команд и функций, всегда может оказаться, что именно нужной пользователю (и порою довольно простой) функции все же нет. Тогда возникает необходимость в создании собственной функции, именуемой функцией пользователя. Для этого используется следующая конструкция:

    name(x,y,...)->expr

    После этого вызов функции осуществляется в виде name(х,у,…), где (x,y,…) — список формальных параметров функции пользователя с именем name. Переменные, указанные в списке формальных параметров, являются локальными. При подстановке на их место фактических параметров они сохраняют их значения только в теле функции (expr). За пределами этой функции переменные с этими именами оказываются либо неопределенными, либо имеют ранее присвоенные им значения.

    Следующие примеры иллюстрирует сказанное (файл p1):

    > restart;

    > х:=0;y:=0;

    х := 0 у := 0

    > m:=(x,y)->sqrt(х^2+y^2);

    > m(3,4);

    5

    > m(3., 4);

    5.000000000

    > [x,y];

    [0, 0]

    Нетрудно заметить, что при вычислении функции m(х,у) переменные х и у имели значения 3 и 4, однако за пределами функции они сохраняют нулевые значения, заданные им перед введением определения функции пользователя. Использование хотя бы одного параметра функции в виде числа с плавающей точкой ведет к тому, что функция возвращает результат также в виде числа с плавающей точкой.

    10.1.2. Конструктор функций unapply

    Еще один способ задания функции пользователя базируется на применении функции-конструктора unapply:

    name:=unapply(expr, var1, var2, ...)

    Ниже даны примеры такого задания функции пользователя (файл p1):

    > restart;

    > fm:=unapply(sqrt(х^2+y^2),х,y);

    > fm(4.,3.);

    5.000000000

    > fe:=unapply(х^2+y^2,х,y);

    fе:=(х,у)→х²+у²

    > fe(sin(х),cos(х));

    sin(x)² + cos(x)²

    > simplify(fe(sin(x),cos(x)));

    1

    Последний пример показывает возможность проведения символьных операций с функцией пользователя.

    10.1.3. Визуализация функции пользователя

    В ряде случаев весьма желательна визуализация результатов выполнения функций пользователя. Порой она может давать неожиданный результат. На рис. 10.1 представлены примеры задания двух функций пользователя от двух переменных и построение их графиков с помощью функции plot3d.

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

    Рис. 10.1. Примеры задания функций пользователя двух переменных с построением их графиков

    10.1.4. Импликативные функции

    Другой важный класс функций, которые нередко приходится задавать — импликативные функции, в которых связь между переменными задана неявно в виде какого-либо выражения. Самый характерный пример такой функции — это выражение для задания окружности радиусаr: х²+у²=r².

    Итак, импликативные функции записываются как уравнения. Соответственно их можно решать с помощью функции solve. Следующие примеры иллюстрируют задание уравнения окружности в общем и в частном (численном) виде (файл p1):

    > impf:=х^2+y^2=r^2;

    impf := x² + у² = r²

    > subs(х=а,impf);

    а² + у² = r²

    > solve(%);

    > impf1:=х^2+у^2=25;

    impf1 := х² + у² =25

    > subs(х=4,impf1);

    16 + y² =25

    > solve(%);

    3, -3

    Для графической визуализации импликативных функций служит функция implicitplot пакета plots. На рис. 10.2 представлено задание двух импликативных функций и построение их графиков.

    Рис. 10.2. Задание двух импликативных функций и построение их графиков

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

    10.2. Управляющие структуры

    10.2.1. Условные выражения

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

    Простейшую конструкцию разветвляющихся программ в Maple-языке программирования задает оператор if или оператор условного выражения:

    if <Условие сравнения> then <Элементы>

    |elif <Условие сравнения> then <Элементы>|

    |else <Элементы>|

    fi;

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

    if <Условие> then <Элементы 1> fi — если Условие выполняется, то исполняются Элементы 1, иначе ничего не выполняется;

    if <Условие> then <Элементы 1> else <Элементы 2> fi — если Условие выполняется, то исполняются Элементы 1, иначе исполняются Элементы 2.

    В задании условий используются любые логические конструкции со знаками сравнения (<, <=, >, >=, =, <>) и логические операторы and, or и not, конструкции с которыми возвращают логические значения true и false.Рассмотрим следующий простой пример (файл р2):

    > х:=-5:

    > if х<0 then print(`Negative`) fi;

    Negative

    > x:=1:

    > if x<0 then print(`Negative`) fi;

    В этом примере анализируется значение х. Если оно отрицательно, то с помощью функции вывода print на экран выводится сообщение «Negative». А вот если х неотрицательно, то не выводится никакого сообщения. В другом примере если х неотрицательно, то выводится сообщение «Positive»:

    > х:=-5:

    > if х<0 then print(`Negative`) else print(`Positive`) fi;

    Negative

    > x:=1:

    > if x<0 then print(`Negative`) else print(`Positive`) fi;

    Positive

    Приведем еще один пример, показывающий особую форму задания конструкции if-then-else-fi:

    > х:=-5:

    > `if` (х<0, print(`Negative`),print(`Positive`));

    Negative

    > x: =1:

    > `if` (x<0, print(`Negative`),print(`Positive`));

    Positive

    В этой конструкции вида

    `if `(Условие, Выражение1, Выражение2)

    если Условие выполнятся, то будет исполнено Выражение1, в противном случае будет исполнено Выражение2. Ввиду компактности записи такая форма условного выражения нередко бывает предпочтительна, хотя она и менее наглядна. На рис. 10.3 представлено применение данной конструкции для моделирования трех типов сигналов.

    Рис. 10.3. Применение конструкции с функцией if для моделирования сигналов


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

    10.2.2. Циклы for и while

    Зачастую необходимо циклическое повторение выполнения выражения заданное число раз или до тех пор, пока выполняется определенное условие. Maple имеет обобщенную конструкцию цикла, которая задается следующим образом:

    |for <name>| | from <expr1>| |to <expr3>| | <expr2>| |while <expr4>|

    do <statement sequence> od;

    Здесь name — имя управляющей переменной цикла, expr1, expr2 и expr3 — выражения, задающие начальное значение, конечное значение и шаг изменения переменной name, expr4 — выражение, задающее условие, пока цикл (набор объектов между словами do и od) будет выполняться.

    В ходе выполнения цикла управляющая переменная меняется от значения expr1 до значения expr2 с шагом, заданным expr3. Если блок by <expr2> отсутствует, то управляющая переменная будет меняться с шагом +1 при expr1<expr2. Это наглядно поясняет следующий пример:

    > for i from 1 to 5 do print(i) od;

    1 2 3 4 5

    В нем выводятся значения переменной i в ходе выполнения цикла. Нетрудно заметить, что она и впрямь меняется от значения 1 до значения 5 с шагом +1 Следующий пример показывает, что границы изменения управляющей переменной можно задать арифметическими выражениями:

    > for i from 7/(2+5) to 2+3 do print(i) od;

    1 2 3 4 5

    А еще один пример показывает задание цикла, у которого переменная цикла меняется от значения 1 до 10 с шагом 2:

    > for i from 1 to 10 by 2 do print(i) od;

    1 3 5 7 9

    В этом случае выводятся нечетные числа от 1 до 9. Шаг может быть и отрицательным:

    > for i from 9 to 1 by -2 do print(i) od;

    9 7 5 3 1

    Следует отметить, что expr1>expr2 задать заведомо невыполнимое условие, например, expr1>expr2 и положительное значение шага, то цикл выполнятся не будет. В цикл можно прервать с помощью дополнительного блока while <expr4>. Цикл с таким блоком выполняется до конца или до тех пор, пока условие expr4 истинно:

    > for i from 1 to 10 by 2 while i<6 do print(i) od;

    1 3 5

    Таким образом, конструкция цикла в Maple-языке программирования вобрала в себя основные конструкции циклов for и while. Есть еще одна, более специфическая конструкция цикла:

    |for <name>| |in <expr1>| | while <expr2>| do <statement sequence> od;

    Здесь expr1 задает список значений, которые будет принимать управляющая переменная name. Цикл будет выполняться, пока не будет исчерпан список и пока выполняется условие, заданное выражением expr2. Следующий пример иллюстрирует сказанное:

    > for i in [1,2,5,-1,7,12] do print(i) od;

    1 2 5 -1 7 12

    > for i in [1,2,5,-1,7,12] while i>0 do print(i) od;

    1 2 5

    В цикле этого вида управляющая переменная может меняться произвольно.

    10.2.3. Вложенные циклы и задание с их помощью матриц

    Циклы могут быть вложенными. Это иллюстрирует следующий пример, создающий единичную матрицу на базе заданного массива М:

    > M:=array(1..3,1..3);

    М:=array(1..3, 1..3, [])

    > for i to 3 do for j to 3 do M[i,j]:=0; if i=j then M[i,j]:=1 fi; od od;

    > evalm(M);

    Однако по образцу этого примера читатель может задавать другие, нужные ему, матрицы.

    Этот пример имеет не более чем познавательное значение, поскольку дня создания такой матрицы Maple имеет функции identity, с помощью которой функция array позволяет сразу создать единичную матрицу:

    > array(1..3,1..3,identity);

    10.2.4. Упрощенная конструкция циклов

    В заключение отметим, что возможна упрощенная частная конструкция цикла типа while:

    while expr do statseq od;

    Здесь выражения statseq выполняются, пока выполняется логическое условие expr. Пример такого цикла:

    > n:=1;

    n:=1

    > while n<16 do n:=2*n od;

    n:=2 n:=4 n:=8 n:=16

    В этом примере идет удвоение числа n с начальным значением n=1 до тех пор, пока значение n меньше 16.

    10.2.5. Операторы пропуска и прерывания циклов

    Иногда бывает нужным пропустить определенное значение переменной цикла. Для этого используется оператор next (следующий). Приведенный ниже пример иллюстрирует применение оператора next в составе выражения if-fi для исключения вывода значения i=-2:

    > for i in [1,2,3,-2,4] do if i=-2 then next else print(i) fi od;

    1 2 3 4

    Другой оператор — break — прерывает выполнение фрагмента программы (или цикла) Его действие поясняет слегка модифицированный предшествующий пример:

    > for i in [1,2,3,-2,4] do if i=-2 then break else print(i) fi od;

    1 2 3

    В данном случае при значении i=-2 произошло полное прекращение выполнения цикла. Поэтому следующее значение 4 переменной i присвоено не было и это значение на печать не попало.

    Любой из операторов quit, done или stop обеспечивает также прерывание выполнения текущей программы (в частности цикла), но при этом окно текущего документа закрывается.

    10.3. Процедуры и процедуры-функции

    10.3.1. Простейшие процедуры

    Процедурой называют объект программы, имеющий самостоятельное значение и выполняющий одну или несколько операций. Процедуры являются важнейшим элементом структурного программирования и служат средством расширения возможностей системы Maple пользователем.

    Каждая процедура имеет свое уникальное имя и список параметров (он может быть пустым). Процедуры вызываются так же как встроенные функции — указанием их имени со списком фактических параметров. При этом просто процедуры обычно не возвращают каких-либо значений после своего исполнения, хотя могут присваивать значения входящим в них переменным. Процедуры-функции в ответ на обращение к ним возвращают некоторое значение. Они как бы являются новыми функциями, задаваемыми пользователем. Описанные ранее функции пользователя фактически являются процедурами-функциями с несколько упрощенной структурой.

    Простейшая форма задания процедуры следующая:

    name := proc(Параметры)

    Тело процедуры

    end;

    Параметры процедуры задаются перечислением имен переменных, например proc(х) или proc(x,y,z). С помощью знака :: после имени переменной можно определить ее тип, например в объявлении prog(n::integer) объявляется, что переменная n является целочисленной.

    При вызове процедуры выражением вида

    name(Фактические_параметры)

    фактические параметры подставляются на место формальных. Несоответствие фактических параметров типу заданных переменных ведет к сообщению об ошибке и к отказу от выполнения процедуры.

    В качестве примера ниже приведена процедура вычисления модуля комплексного числа z — в данном случае это единственный параметр процедуры (файл р4):

    > mode:=рroc(z)

    > evalf(sqrt(Re(z)^2+Im(z)^2))

    > end;

    modc := proc(z) evalf (sqrt(ℜ(z)^2 + ℑ(z)^2)) end proc

    После ввода заголовка процедуры под строкой ввода появляется сообщение: «Warning, premature end of input». Оно указывает на то, что ввод листинга процедуры не закончен и должен быть продолжен до тех пор, пока не будет введено завершающее слово end листинга процедуры. Если после этого слова поставить символ точки с запятой, то листинг процедуры будет выведен на экран дисплея.

    Теперь для вычисления модуля достаточно задать обращение к процедуре modc(z), указав вместо z конкретное комплексное число:

    > mode(3.+I*4.);

    5.0000000000

    Нетрудно заметить, что при знаке ; после завершающего слова end текст процедуры повторяется в строке вывода (в общем случае в несколько ином виде).

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

    10.3.2. Графические процедуры

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

    > mob := proc(width)

    > plot3d([(5+cos(1/2*t)*u)*cos(t),

    (5+cos(1/2*t)*u)*sin(t),sin(1/2*t)*u], t=0..2*Pi,

    > u=-width/5..width/5, gnd= [60,10] ,

    > scaling=UNCONSTRAINED, orientation= [0,140]);

    > end:

    Запуск этой процедуры командой

    > mob(5);

    строит фигуру, показанную на рис. 10.4.

    Рис. 10.4. Кольцо Мебиуса, построенное графической процедурой

    10.3.3. Просмотр кодов процедур

    Коды процедур на языке Maple можно просмотреть с помощью функции eval(name) или pint(name), где name — имя процедуры. При этом уровень просмотра можно менять с помощью функции interface(verboseproc=N), где N — уровень вывода. Следующий пример иллюстрирует это для только что созданной процедуры mode (файл р4):

    > eval(modc);

    proc(z) evalf (sqrt(ℜ(z)^2 + ℑ(z)^2)) end proc

    > interface(verboseproc=0);

    1

    > eval(modc);

    proc(z) evalf (sqrt(ℜ(z)^2 + ℑ(z)^2)) end proc

    > interface(verboseproc=1);

    0

    > eval(modc);

    proc(z) evalf (sqrt(ℜ(z)^2 + ℑ(z)^2)) end proc

    Аналогичным образом можно просмотреть коды процедуры, уже созданной в Maple. Например, не очень большой процедуры смены системы координат changecoords из пакета расширении plots:

    > interface(verboseproc=0);

    1

    > eval(plots[changecoords]);

    proc(p,coord) … end proc

    > interface(verboseproc=2);

    0

    > eval(plots[changecoords]);

    proc(p, coord)

    local c_name, a, b, c;

    option

     `Copyright (c) 1994 by the University of Waterloo. All rights reserved;`

     a :=1;

     b := 1/2;

     с := 1/3;

     if type(coord, function) then

      c_name :=op(0, coord);

      if nops(coord) = 1 then a :=op(1, coord)

      elif nops(coord) = 2 then a :=op(1, coord); b :=op(2, coord)

      elif nops(coord) = 3 then

       a :=op(1, coord); b :=op(2, coord); с :=op(3, coord)

      else error "Inappropriate number of parameters."

      end if

     else c_name := coord

     end if;

     if member(c_name, `plot3d/coordset2` ( )) then

      (p, c_name, a)

     elif member(c_name , `plot3d/coordset` ( )) then

      `plots/changecoords/threetrans` (p, c_name, a,b,c)

     else error "Cannot convert to coordinate system %1", coord

     end if

    end proc

    10.3.4. Оператор возврата значения RETURN

    Как отмечалось, процедуры, которые возвращают значение результата в ответ на обращение к ним, во многом тождественны функциям. Будем называть их процедурами-функциями. Обычно процедура возвращает значение последнего выражения в ее теле или выражения, намеченного к возврату специальным оператором возврата RETURN (файл р4):

    > modc:=proc(z)

    > evalf(sqrt(Re(z)^2+Im(z^2)):

    > RETURN(%)

    > end;

    modc := proc(z) evalf (sqrt(ℜ(z)^2 + ℑ(z)^2)); RETURN(%) end proc

    > modc(3.+I*4.);

    5.000000000

    Параметром оператора RETURN может быть любое выражение. В Maple не принято выделять процедуры-функции в какой-то отдельный класс. Действует правило — если не использован оператор RETURN, процедура возвращает значение последнего выражения в ее теле. Для устранения выдачи значений выражений внутри процедуры-функции после них просто надо установить знак двоеточия.

    10.3.5. Статус переменных в процедурах и циклах

    Переменные, которые указываются в списке параметров (например, z в нашем примере) внутри процедуры являются локальными. Это означает, что изменение их значений происходит лишь в теле процедуры, то есть локально. За пределами тела процедуры эти переменные имеют то значение, которое у них было до использования процедуры. Это хорошо поясняет следующий пример (файл р5):

    > restart:z:=1;

    z := 1

    > modc:=proc(z)

    > evalf(sqrt(Re(z)^2+Im(z)^2));

    > end;

    modc := proc(z) evalf (sqrt(ℜ(z)^2 + ℑ(z)^2)) end proc

    > modc(3.+I*4.);

    5.000000000

    > z;

    1

    Нетрудно заметить, что внутри процедуры z=3+I*4, тогда как вне нее значение z=1. Таким образом, имена переменных в списке параметров процедуры могут совпадать с именами глобальных переменных, используемых за пределами процедуры.

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

    10.3.6. Объявления переменных локальными с помощью оператора local

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

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

    > restart:m:=0;

    m := 0

    > modc:=proc(z)

    > m:=evalf(sqrt(Re(z)^2+Im(z)^2)):RETURN(m)

    > end;

    Warning, `m` is implicitly declared local to procedure 'modc'

    modc:= proc(z) evalf (sqrt(ℜ(z)^2 + ℑ(z)^2)); RETURN(m) end proc

    > modc(3.+I*4.);

    5.000000000

    > m;

    0

    Обратите внимание на то, что в тело процедуры было автоматически вставлено определение local m, задающее локальный статус переменной m. Оператором print (modc) можно вывести текст процедуры.

    10.3.7. Объявления переменных глобальными с помощью слова global

    Говорят, что запретный плод сладок! Что бы ни говорили о нежелательности работы с глобальными переменными, бывает, что их применение желательно или даже необходимо. Чтобы сделать переменные внутри процедуры глобальными, достаточно объявить их с помощью ключевого слова global, после которого перечисляются идентификаторы переменных.

    Следующий пример поясняет применение оператора global в процедуре (файл р5):

    > а:=1;b:=1;

    а := 1 b := 1

    > fg:=proc(х, у)

    > global a,b;

    > а:=х^2:b:=у^2:

    > RETURN(sqrt(a+b));

    > end;

    fg := proc(x, y) global a, b; a:= х^2; b:= у^2; RETURN (sqrt (a+b)) end proc

    > fg(3, 4);

    5

    > [a,b];

    [9, 16]

    В примере переменным а и b вначале присвоены значения 1. Поскольку они в процедуре объявлены глобальными, то внутри процедуры они принимают новые значения х2 и у2. В результате при выходе из процедуры они имеют уже новые значения. Это и есть побочный эффект при исполнении данной процедуры. Если пользователь не знает (или не помнит), что та или иная процедура имеет побочный эффект, то он рискует получить самые неожиданные (и неверные) результаты своих вычислений.

    Следует отметить, что нельзя делать глобальными переменные, указанные в списке параметров процедуры, поскольку они уже фактически объявлены локальными. Такая попытка приведет к появлению сообщения об ошибке следующего вида «Error, argument and global `х` have the same name». При этом соответствующие переменные останутся локальными

    10.3.8. Функция вывода сообщений об ошибках ERROR

    При профессиональной подготовке процедур пользователь должен предусмотреть их поведение при возможных ошибках. Например, если он готовит процедуру или функцию, вычисляющую квадратный корень из действительных чисел, то надо учесть, что такой корень нельзя извлекать из отрицательных чисел (будем, исключительно в учебных целях, считать, что комплексные числа в данном примере недопустимы).

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

    ERROR(expr_1, expr_2, ...)

    где exp_1, … — ряд выражений (возможно, пустой). Наиболее часто ERROR выводит просто строковое сообщение об ошибке, например ERROR(`string`). Полное сообщение об ошибке имеет вид.

    Error, (in name) string, ...

    Приведем пример процедуры, в которой предусмотрен вывод сообщения об ошибке при задании переменной х < 0 (файл р5):

    > f := proc(х) if х<0 then error "invalid variable x: %1", x else

    х^(1/2) end if end proc;

    f:= proc(x)

     if x < 0 then error "invalid variable x:%1", x else х^(1/2) end if

    end proc

    > f(3.) ;

    1.732050808

    > f(-3.);

    Error, (in f) invalid variable x: -3.

    > lasterror;

    "invalid variable x: %1", -3

    > lastexception;

    f, "invalid variable x: %1",-3

    Эта процедура вычисляет квадратный корень из числа х. При х<0 выводится заданное сообщение об ошибке. Еще раз обращаем внимание читателя на учебный характер данного примера, поскольку вычисление квадратного корня (в том числе из комплексных и отрицательных действительных чисел) реализовано встроенной функцией sqrt.

    10.3.9. Ключи в процедурах

    В объявление процедуры можно включить ключевые слова, вводимые словом

    options opseq

    Иногда их называют расширяющими ключами. Предусмотрены следующие ключи:

    arrow — определят процедуру-оператор в нотации ->;

    builtin — определяет функцию как встроенную;

    call external — задает обращение к внешним программным модулям;

    copyright — защищает процедуру от копирования.

    inline — определяет процедуру как подчиненную (возможно не для всех процедур — см. справку).

    load=memberName — загружает нужный для определений процедуры модуль (см. также опцию unload и детали в справке);

    operator — объявляет процедуру — функциональный оператор;

    system — определяет процедуру как системную,

    remember — определяет таблицу памяти для процедуры;

    trace — задает трассировку процедуры;

    unload=memberName — выгружает нужный для определений процедуры модуль (см. опцию load).

    10.3.10. Ключ remember

    Ключ remember обеспечивает занесение результатов обращений к процедуре в таблицу памяти, которая используется при исполнении процедуры. Функция ор позволяет вывести таблицу (файл p6):

    > f:=proc(x) options remember; x^3 end:

    > f(2);

    8

    > f(3);

    27

    > op(4,eval(f));

    table([2 = 8, 3 = 27])

    Ключ remember особенно полезен при реализации итерационных процедур. К примеру, в приведенной ниже процедуре (без использования ключа remember) время вычисления n-го числа Фибоначчи растет пропорционально квадрату n:

    > f:=proc(n) if n<2 then n else f(n-1)+f(n-2) fi end;

    f := proc(n) if n < 2 then n else f(n - 1)+f(n-2) end if end proc

    > time(f(30));

    4.891

    > f(30);

    832040

    Вычисление f(30) по этой процедуре на ПК с процессором Pentium 4 НТ 2,6 ГГц в системе Maple 9.5 время вычисления составляет менее 5 с — см. контроль этого времени с помощью функции time (результат в секундах).

    Стоит добавить в процедуру ключ remember, и время вычислений резко уменьшится:

    > restart;

    > fe:=proc(n) options remember; if n<2 then n else fe(n-1)+fe(n-2) fi

    end:

    > fe(30);

    832040

    > time(fe(30));

    0.

    При этом вычисление fe(30) происходит практически мгновенно, так как все промежуточные результаты в первом случае вычисляются заново, а во втором они берутся из таблицы. Однако это справедливо лишь тогда, когда к процедуре было хотя бы однократное обращение. Обратите внимание на то, что данные процедуры являются рекурсивными — в их теле имеется обращение к самой себе.

    10.3.11. Ключ builtin

    Ключ builtin придает процедуре статус встроенной. Он должен использоваться всегда первым. С помощью функции eval(name) можно проверить, является ли функция с именем name встроенной:

    > eval(type);

    proc() option builtin, 274 end proc

    > eval(print) ;

    proc() option builtin, 235 end proc

    Числа в теле процедур указывают системные номера функций. Следует отметить, что в новой версии Maple 9 они существенно отличаются от принятых в предшествующих версиях (даже Maple 8).

    10.3.12. Ключ system

    Этот ключ придает процедуре статус системной. У таких процедур таблица памяти может быть удалена. У обычных процедур таблица памяти не удаляется и входит в так называемый «мусорный ящик» (garbage collector).

    10.3.13. Ключи operator и arrow

    Эта пара ключей задает процедуре статус оператора в «стрелочной» нотации (->). Это достаточно пояснить следующими примерами:

    > o:=proc(x,y) option operator , arrow; x-sqrt(у) end;

    о:=(x,y)→x-√y

    > о(4, 2);

    4 - 2

    > о(4, 2.);

    2.585786438

    10.3.14. Ключ trace

    Ключ trace задает вывод отладочной информации:

    > o:=proc(x,y) option trace, arrow; x-sqrt(y) end;

    о: = proc(x, y) option trace, arrow, x - sqrt(y) end proc

    > о(4, 2.);

    {—> enter o, args =4, 2.

    2.585786438

    <- exit о (now at top level) = 2.585786438}

    2.585786438

    10.3.15. Ключ copyright

    Этот ключ защищает тело процедуры от просмотра. Это поясняют следующие два примера:

    > o:=proc(x,y) x-sqrt(у) end;

    о: = proc(x, х - sqrt(у) end proc

    > oo:=proc(х,у) option Copyright; x-sqrt(у) end;

    oo:= proc(x,у) … end proc

    > oo(4,2.);

    2.585786438

    Нетрудно заметить, что во втором примере тело процедуры уже не просматривается. Для отмены защиты от просмотра можно использовать оператор interface(verboseproc=2).

    10.3.16. Общая форма задания процедуры

    Выше мы рассмотрели основные частные формы задания процедур. Все они могут быть объединены в общую форму задания процедуры:

    name:=proc(<argseq>) # объявление процедуры

    local<nseq>; # объявление локальных переменных

    global<nseq>; # объявление глобальных переменных

    uses<useg> # объявление структур use ... in ... end use

    options<nseq>; # объявление расширяющих ключей

    description<stringseq>; # объявление комментарий

    <stateq> # выражения — тело процедуры

    end; (или end:) # объявление конца процедуры

    Эта форма охватывает все описанные выше частные формы и позволяет готовить самые сложные и надежно работающие процедуры. Читателям-программистам стоит детально изучить по справке возможности этой формы задания процедур, а также возможности конструкции use … in … end use.

    10.4. Средства отладки программ

    10.4.1. Средства контроля и отладки процедур

    Для контроля и отладки процедур прежде всего надо уметь вывести их текст. Для этого, что уже отмечалось, служит команда

    print(name);

    где name — имя процедуры.

    Перед тем как использовать ее, надо также исполнить команду

    > interface(verboseproc=2,prettyprint=1,version);

    1, 3, Classic Worksheet Interface, Maple 9.50, Windows, Aug 9 2004 Build ID 163356

    Ее смысл детально будет пояснен ниже. Пока же отметим, что эта команда обеспечивает полный вывод текста процедур библиотеки. Встроенные в ядро процедуры, написанные не на Maple-языке, в полном тексте не представляются. Поясним это следующими примерами:

    > print(evalf);

    proc() option builtin, remember; 171 end proc

    > print(erf);

    proc(x::algebraic)

    local Re_x, Im_x, sr, si, xr, xi;

    option `Copyright (c) 1994 by the University of Waterloo. All rights reserved.`;

     if nargs <> 1 then error "expecting 1 argument, got %1", nargs

     elif type(x, 'complex(float)') then evalf('erf'(x))

     elif x = 0 then 0

     elif type(x, 'infinity') then

      if type(x, ' cx_infinity') then undefined + undefined*I

      elif type(x, 'undefined') then NumericTools:-ThrowUndefined(x)

      elif type(Re(x), 'infinity') then CopySign(1, Re(x))

      elif type(x, 'imaginary') then x

      else infinity + infinity*I

      end if

     elif type(x, 'undefined') then NumericTools:-ThrowUndefined(x, 'preserve' = 'axes')

     elif `Symbolic/Sign`(x) = -1 then -erf(-x)

     else 'erf'(x)

     end if

    end proc

    Здесь вначале выполнен вывод сокращенного листинга встроенной в ядро процедуры evalf, а затем выведен полный листинг процедуры вычисления функции ошибок erf. Эта функция имеет довольно короткую процедуру — многие важные функции и операторы задаются гораздо более сложными и большими процедурами. Их просмотр очень полезен читателям, которые занимаются программированием — листинги процедур на языке Maple являются наглядными примерами профессионально выполненных программ.

    Но вернемся к функции interface. Она служит для управления выводом и задается в виде

    interface(arg1, arg2, …)

    где аргументы задаются в виде равенств вида name=value и слов-указателей:

    ansi          autoassign   echo        errorbreak  errorcursor

    imaginaryunit indentamount labelling   labelwidth  latexwidth

    longdelim     patchlevel   plotdevice  plotoptions plotoutput

    postplot      preplot      prettyprint prompt      quiet

    rtablesize    screenheight screenwidth showassumed verboseproc

    version       warnlevel

    Рассмотрим только некоторые, наиболее важные возможности этой функции.

    Указание verboseproc=n задает степень детальности вывода листинга процедур. При n=0 текст не выводится, при n=1 выводится текст только заданных пользователем процедур, а при n=2 — всех процедур на Maple-языке. Пример этого был дан выше. Указание prettyprint=0 или 1 управляет выводом стандартных сообщений. Указание plotdevice=string управляет выводом графики, например plotdevice=gif указывает на то, что запись графиков в виде файлов будет происходить в формате .gif.

    Одним из основных средств отладки процедур является функция трассировки trace(name). Детальность ее работы задается системной переменной printlevel (уровень вывода). При printlevel:=n (значение n=1 по умолчанию) выводится результат только непосредственно исполняемой функции или оператора. Для вывода информации о выполнении k-го уровня вложенности надо использовать значение этой переменной от 5*k до 5*(k+1). Так, при n от 1 до 5 выводятся результаты трассировки первого уровня, при n от 6 до 10 второго и т.д. Максимальное значение n — 100 обеспечивает трассировку по всем уровням вложенности процедуры name.

    Следующий пример показывает осуществление трассировки для функции int(x^n,x):

    > printlevel:=5;

    printlevel := 5

    > trace(int);

    {--> enter trace, args = int

    <-- exit trace (now at top level) = int}

                                        int

    > int(x^n,x);

    Действие функции трассировки отменяется командой untrace:

    > untrace(int);

    {--> enter untrace, args = int

    <-- exit untrace (now at top level) = int}

                                          int

    > int(х^n,x);

    > enter int, args = x^n, x <-- exit int (row at top level) = x^(n+1)/(n+1)}

    > printlevel:=1;

    printlevel := 1

    > int(x^n,x);

    При отладке алгоритмов выполнения вычислений надо тщательно следить за сообщениями об ошибках. Для этого в Maple предусмотрены функция traceerr и системная переменная lasterr, в которой сохраняется последнее сообщение об ошибке. При каждом обращении к tracerr переменная lasterr очищается:

    > 2/0;

    Error, numeric exception: division by zero

    > 2/4;

    1/2

    > 2/.3;

    6.666666667

    > lasterror;

    "division by zero"

    > traperror(3/4);

    3/4

    > lasterror;

    lasterror

    > traperror(5/0);

    Error, numeric exeption: division by zero

    > lasterror;

    "numeric exception: division by zero"

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

    10.4.2. Преобразование программных кодов

    В пакете расширения CodeGenetarion определены функции преобразования Maple-кодов в коды других языков программирования:

    > with(CodeGeneration);

    Warning, the protected name Matlab has been redefined and unprotected

    [C, Fortran, IntermediateCode, Java, LanguageDefinition, Matlab, Names, Save, Translate, VisualBasic]

    Например, преобразовать Maple-коды процедуры mode в коды языка MATLAB можно следующим образом:

    > Matlab(mode);

    Warning, the function names {Im, Re} are not recognized in the target

    language

    function modcreturn = modc(z)

     modcreturn = (sqrt(Re(z) ^ 2 + Im(z) ^ 2));

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

    10.4.3. Работа с отладчиком программ

    В большинстве случаев составители программ (процедур) редко прибегают к пошаговой их отладке. Средства общей диагностики уже в Maple развиты настолько хорошо, что позволяют выявлять грубые ошибки в процедурах при их выполнении. Иногда, правда, для этого приходится неоднократно «прогонять» процедуру, пока она не начнет работать как задумано. Тем не менее, для отладки процедур служит специальный интерактивный отладчик (debugger). Опишем, как его запустить и как с ним работать.

    Допустим, мы составили некоторую процедуру demo, вычисляющую сумму квадратов чисел (1^2+2^2+...+n^2):

    > demo:=proc(n::integer) local y,i:

    > у:=3:

    > for i to n do y:=y+i^2 od

    > end;

    demo := proc(n::integer) local y,i; y: = 0; for i to n do у:=i^2 end do end proc

    > demo(3);

    14

    Чтобы включить отладчик в работу, надо исполнить команду stopat:

    > stopat(demo);

    [demo]

    > demo(3); demo:

     1* y := 0;

    DBG>

    Признаком, указывающим на работу отладчика, является изменение приглашения к вводу со знака > на DBG> (как нетрудно догадаться, DBG означает debugger). Теперь, подавая команды next (следующий), step (шаг) и stop (остановка), можно проследить выполнение процедуры:

    DBG> next

    0

    demo:

     2 for i to n do

        ...

       end do

    DBG> step

    0

    demo:

     3 y := y+i^2

    DBG> step

    1

    demo:

     3 y := y+i^2

    DB3> step

    5

    demo:

     3 y := y+i^2

    DBG> step

    14

    В последнем случае процедура по шагам дошла до конца вычислений; на этом работа отладчика завершается сама собой.

    Можно также вывести листинг процедуры с помощью команды showstat:

    > showstat(demo);

    demo := proc(n::integer)

    local y, i;

    1* y := 0;

    2  for i to n do

    3   y := y+i^2

       end do

    end proc

    Обратите внимание, что в этом листинге строки вычисляемых элементов пронумерованы. Это сделано для облегчения разбора работы процедуры.

    В общем случае отладчик выключается при выполнении команд stopat, stopwhen или stoperr. Если используется команда stopat, то вывод на экран соответствует исполнению последней выполненной команды. Для отмены этой команды используется команда unstopat.

    Команда stopwhen позволяет установить точку наблюдения за указанной в команде переменной. Отменить ее можно командой unstopwhen. Команда stoperror позволяет задать остановку при появлении определенной ошибки. Для отмены этой команды используется команда unstoperror.

    Команда cont используется для продолжения работы до следующей точки прерывания, установленной указанными выше командами, или до конца процедуры. Для прерывания отладки можно использовать команду quit После команды stop можно вычислить любое Maple-выражение.

    В действительности команд отладчика намного больше и их функции более развиты, чем это описано выше. Пользователи, заинтересованные в серьезной работе с отладчиком (скорее всего, их немного) могут просмотреть его подробное описание. Для этого в разделе справочной системы Context найдите раздел Programming, а в нем — раздел Debugging.

    10.5. Файловые операции с программными модулями

    10.5.1. Считывание и запись программных модулей

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

    Для записи на диск используется оператор save:

    save filename — запись всех определений текущего файла под именем filename;

    save name_1, name_2,…, name_k, filename — запись избранных модулей с именами name_1, name_2, name_k под именем filename.

    Считывание имеющегося на диске файла filename осуществляется оператором read:

    read <filename>

    При считывании все имеющиеся в файле определения становятся доступными для рабочих документов Maple. При записи файлов отдельных определений используется специальный внутренний Maple-формат файлов. Для загрузки файлов типа *.m из стандартной библиотеки используется функция readlib. А для записи файлов в качестве библиотечных достаточно в имени filename оператора save указать расширение .m. Разумеется, можно считывать такие файлы и оператором read, указав в имени файла расширение .m (файл р7):

    > save my_proc, `my_lib.m`: # запись файла my_proc и

    > # библиотечного файла my_lib.m;

    > load `my_lib.m`: # считывание библиотечного файла

    > # my_lib.m.

    10.5.2. Создание своей библиотеки процедур

    Если приведенные выше примеры составления процедур кажутся вам простыми, значит, вы неплохо знаете программирование и, скорее всего, уже имеете несколько полезных процедур, которые вы хотели бы сохранить — если не для потомков, то хотя бы для своей повседневной работы. Сделать это в Maple довольно просто.

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

    > restart;

    > mylib :=table();

    mylib := table([])

    Теперь надо ввести свои библиотечные процедуры. Они задаются с двойным именем — вначале указывается имя библиотеки, а затем в квадратных скобках имя процедуры. Для примера зададим три простые процедуры с именами f1, f2 и f3:

    > mylib[f1] :=proc(x::anything) sin(x) +cos(x) end:

    > mylib[f2]:=proc(x::anything) sin(x)^2+cos(x)^2 end:

    > mylib[f3]:=proc(x::anything) if x=0 then 1 else sin(x)/x fi end:

    Рекомендуется тщательно проверить работу процедур, прежде чем записывать их на диск. Ограничимся, скажем, такими контрольными примерами:

    > mylib[f1](х);

    sin(x) +cos(x)

    > mylib[f1](1.);

    1.381773291

    > mylib[f2](x);

    sin(x)² +cos(x)²

    > simplify(mylib[f2](x));

    1

    > evalf(mylib[f3](x));

    > sin(0)/0;

    Error, division by zero

    > mylib[f3](0);

    1

    > evalf(mylib[f3](.5));

    .9588510772

    Можно построить графики введенных процедур-функций. Они представлены на рис. 10.5.

    Рис. 10.5. Построение графиков процедур-функций f1, f2 и f3

    С помощью функции with можно убедиться, что библиотека mylib действительно содержит только что введенные в нее процедуры. Их список должен появиться при обращении with(mylib):

    > with(mylib);

    [f1,f2,f3]

    Теперь надо записать эту библиотеку под своим именем на диск с помощью команды save:

    > save(mylib, `с:/mylib.m`);

    Обратите особое внимание на правильное задание полного имени файла. Обычно применяемый для указания пути знак \ в строках Maple-языка используемся как знак продолжения строки. Поэтому надо использовать либо двойной знак \\, либо знак /. В нашем примере файл записан в корень диска С. Лучше поместить библиотечный файл в другую папку (например, в библиотеку, уже имеющуюся в составе системы), указав полный путь до нее.

    После всего этого надо убедиться в том, что библиотечный файл записан. После этого можно сразу и считать его. Для этого вначале следует командой restart устранить ранее введенные определения процедур:

    > restart;

    С помощью команды with можно убедиться в том, что этих определений уже нет:

    > with(mylib);

    Error, (in pacman:-pexports) mylib is not a package

    После этого командой read надо загрузить библиотечный файл:

    > read(`с:/mylib.n`);

    Имя файла надо указывать по правилам, указанным для команды save. Если все выполнено пунктуально, то команда with должна показать наличие в вашей библиотеке списка процедур f1, f2 и f3:

    > with(mylib);

    [f1, f2, f3]

    И, наконец, можно вновь опробовать работу процедур, которые теперь введены из загруженной библиотеки:

    > f1(x);

    sin(x) +cos(x)

    > simplifу(f2(у));

    1

    > f3(0);

    1

    > f3(1.);

    .8414709848

    Описанный выше способ создания своей библиотеки вполне устроит большинство пользователей. Однако есть более сложный и более «продвинутый» способ ввода своей библиотеки в состав уже имеющейся. Для реализации этого Maple имеет следующие операции записи в библиотеку процедур s1, s2, … и считывания их из файлов file1, file2, …:

    savelib(s1, s2, sn, filename)

    readlib(f, file1, file2, ...)

    С помощью специального оператора makehelp можно задать стандартное справочное описание новых процедур:

    makehelp(n,f,b)

    где n — название темы, f — имя текстового файла, содержащего текст справки (файл готовится как документ Maple) и b — имя библиотеки. Системная переменная libname хранит имя директории библиотечных файлов. Для регистрации созданной справки надо исполнить команду вида

    libname:=libname, `/mylib`;

    С деталями применения этих операторов можно ознакомиться в справочной системе.

    К созданию своих библиотечных процедур надо относиться достаточно осторожно. Их применение лишает ваши Maple-программы совместимости со стандартной версий Maple. Если вы используете одну-две процедуры, проще поместить их в те документы, в которых они действительно нужны. Иначе вы будете вынуждены к каждой своей программе прикладывать еще и библиотеку процедур. Она нередко оказывается большей по размеру, чем файл самого документа. Не всегда практично прицеплять маленький файл документа к большой библиотеке, большинство процедур которой, скорее всего, для данного документа попросту не нужны.

    Особенно рискованно изменять стандартную библиотеку Maple 9.5/10. Впрочем, идти на это или нет — дело каждого пользователя. Разумеется, если вы готовы создать серьезную библиотеку своих процедур, то ее надо записать, тщательно хранить и подробно документировать.

    10.6. Программирование символьных операций

    10.6.1. Реализация итераций Ньютона в символьном виде

    Найти достаточно простую и наглядную задачу, решение которой отсутствует в системе Maple 9.5/10, не очень просто. Поэтому для демонстрации решения задачи с применением аналитических методов воспользуемся примером, ставшим классическим — реализуем итерационный метод Ньютона при решении нелинейного уравнения вида f(x)=0.

    Как известно, метод Ньютона сводится к итерационным вычислениям по следующей формуле (файл р9):

    xi+1 = xi +f(xi)/f'(xi).

    Реализующая его процедура выглядит довольно просто:

    > restart:

    NI:=proc(expr, х) local iter;

    iter:=x-expr/diff(expr,х);

    unapply(iter,x)

    end;

    NI := proc(expr, x) local iter, iter:= x - expr/diff(expr, x); unapply(iter, x) end proc

    Для получения итерационной формулы в аналитическом виде здесь используется функция unapply. Теперь, если задать решаемое уравнение, то можно получить искомое аналитическое выражение:

    > expr:=sin(х)^2-0.5;

    expr := sin(x)² - .5

    > F:=NI(expr,x);

    Далее, задав начальное приближение для х в виде х=х0, можно получить результаты вычислений для ряда итераций:

    > х0:=0.2;

    х0:= .2

    > to 8 do х0:=F(х0);od;

    х0:= 1.382611210 х0:= .117460944 х0:= 2.206529505 х0:= 2.360830634 х0:= 2.356194357 х0:= 2.356194490 х0:= 2.356194490 х0:= 2.356194490

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

    Можно попробовать с помощью полученной процедуры получить решение и для другой функции:

    > expr:=ln(х^2)-0.5;

    expr: = ln(x² ) - .5

    > F:=NI(expr, х);

    F:=x→x-½(ln(x²) - .5)х

    >> х0:=0.2;

    х0:= 2

    > to 8 do x0:=F(x0);od;

    x0:= .55718875825 x0:= 1.034437603 x0:= 1.258023119 x0:= 1.283760340 x0:= 1.284025389 x0:= 1.284025417 x0:= 1.284025416 x0:= 1.284025417

    Здесь итерационная формула имеет (и вполне естественно) уже другой вид, но сходимость к корню также обеспечивается за несколько итерации.

    Возможна и иная форма задания итерационной процедуры с применением оператора дифференцирования D и заданием исходной функции также в виде процедуры (файл р9):

    > MI:=proc(f::procedure)

    > (х->х)-eval(f)/D(eval(f));

    > end;

    MI := proc(f::procedure) (x→x) -eval(f)/D(eval(f)) end proc

    > g:=x->x-cos(x);

    g := x→x - cos(x)

    > SI:=MI(g);

    > x0:=0.1;

    x0:=.1

    > to 6 do x0:=SI(x0) od;

    x0:= .9137633858 x0:= .7446642419 x0:= .7390919660 x0:= .7390851333 x0:= .7390851332 x0:= .7390851332

    Вообще говоря, в программных процедурах можно использовать любые операторы и функции, присущие Maple-языку, в том числе и те, которые реализуют символьные вычисления. Это открывает широкий простор для разработки новых процедур и функций, обеспечивающих выполнение символьных операций.

    10.6.2. Вычисление интеграла по известной формуле

    Рассмотрим следующий пример (файл р9):

    > Int(e^x*x^n,x)=int(e^x*x^n,x);

    ∫exxndх = -(-1)(-n)ln(e)(-1-n)n(-1)nln(е)nnГ(n)(-х ln(е))(-n) - хn(-1)n ln(е)n е(хln(e)) - хn(-1)nln(е)nn(-х ln(е))(-n)Г(n, -x ln(е)))

    Ранние версии системы Maple не брали этот интеграл, поскольку он не имеет аналитического представления через обычные функции. Maple блестяще вычисляет этот «крепкий орешек», но полученное выражение довольно сложно.

    Из математики известно, что такой интеграл может быть представлен в следующем виде:

    Используя эту формулу, мы можем создать простую процедуру для численного и аналитического вычисления данного интеграла.

    > IntExpMonomial:=proc(n::anything,х::name)

    local i;

    n!*exp(x)*sum(((-1)^(n-i)*х^i)/i!,i=0..n);

    end;

     IntExpMonomial := proc(n::anything, x::name)

     local i;

      n! × exp(x) × sum((-1)^(n-i) × x^i/i!,i=-..n)

     end proc

    Проверим ее в работе:

    > IntExpMonomial(3,х);

    > IntExpMonomial(5,x);

    > IntExpMonomial(n, x);

    Результат в аналитическом виде довольно прост для данного интеграла с конкретным значением n. Более того, мы получили несколько иной результат и для n в общем случае. Но точен ли он? Для ответа на этот вопрос продифференцируем полученное выражение:

    > diff(%,х);

    Результат дифференцирования выглядит куда сложнее, чем вычисленный интеграл. Однако с помощью функции simplify в Maple 9 он упрощается к подынтегральной функции:

    > simplify(%);

    еx хn

    Maple 9.5 выдал более замысловатое выражение:

    (-1)n еx (-x)n

    Это говорит о том, что задача вычисления заданного интеграла в аналитической форме действительно решена. А что касается громоздкости результатов, так ведь системы, подобные Maple, для того и созданы, чтобы облегчить нам работу с громоздкими вычислениями — в том числе аналитическими.

    10.6.3. Вложенные процедуры и интегрирование по частям

    Теперь мы подошли к важному моменту, о котором читатель наверняка уже давно догадался — в составляемых пользователям процедурах можно использовать ранее составленные им (или кем-то еще) другие процедуры! Таким образом, Maple-язык позволяет реализовать процедуры, вложенные друг в друга.

    Для иллюстрации применения вложенных процедур рассмотрим операцию интегрирования по частям. Пусть нам надо вычислить интеграл

    ∫ p(x)exdx,

    где р(х) — выражение, представляющее полином.

    Вначале подготовим процедуру IntExpMonomialR, реализующую вычисление уже рассмотренного ранее интеграла, но рекурсивным способом (файл р9):

    > IntExpMonomialR:=proc(n::nonnegint,х::name)

    local i;

    if n=0 then RETURN(exp(x)) fi;

    х^n*ехр(x)-n*IntExpMonomialR(n-1, x);

    end;

     IntExpMonomialR: = proc(n::nonneg int, x::name)

     local i;

      if n = 0 then RETURN(exp(x)) end if;

      x^n × exp(x) -n × IntExpMonomialR(n - 1, x)

     end proc

    Проверим ее в работе:

    > IntExpMonomialR(4, х);

    x4еx - 4x3еx + 12x2ex - 24хеx + 24 еx

    > collect(%,exp(х));

    4 - 4х3 + 12x2 - 24x + 24) еx

    Теперь составим процедуру для вычисления по частям нашего интеграла:

    > IntExpPolynomial:=proc(р::polynom,x::name) local i, result;

    ### WARNING: degree(0,x) now returns -infinity

    result:=add(coeff(p,x,i)*IntExpMonomialR(i,x),i=0..degree(p, x));

    collect(result,exp(x));

    end;

     IntExpPolynomial: = proc(p::polynom, x::name)

     local i, result;

      result:= add(coeff(p, x, i) × IntExpMonomialR(i, x), i = 0..degree(p, x)); collect(result, exp(x))

     end proc

    В этой процедуре имеется обращение к ранее составленной процедуре IntExpMonomialR. Обратите внимание на то, что в процедуре введено предупреждение об определенных проблемах, связанных с использованием функции degree (сообщение начинается с символов ###). Тем не менее, процедура работает, в чем убеждают, по крайней мере, следующие примеры:

    > р:=(х^2+1)*(1-3*х);

    р := (х² + 1)(1 - 3х)

    > expand(р);

    х² - 3х³ + 1 - 3x

    > int(р*ехр(х),х);

    х(-24 + 23х - 10х² + 3х³)

    > IntExpPolynomial(р,х);

    (24 - 23х + 10х² - 3х³)еx

    > IntExpPolynomial(р,х);

    (24 - 23х + 10х² - 3х³)еx

    10.7. Дополнительные возможности Maple-языка

    10.7.1. Переназначение определений

    В большинстве случаев Maple-язык использует достаточно длинные идентификаторы для своих определений, например функций. Однако с помощью функции alias можно изменить любое определение на другое, если оно кажется пользователю более удобным. Функция alias записывается в виде

    alias(e1, е2, ..., eN)

    где е1, е2, …, eN — ноль или более равенств.

    Эта функция возвращает список переназначений и осуществляет сами переназначения. Например, для замены имени функции BesselJ на более короткое имя BJ достаточно параметром функции alias записать BJ=BesselJ:

    > alias(ВJ=BesselJ);

    BJ, Fx

    > [BJ(0,1.),BesselJ(0,1.)];

    [.7651976866, .7651976866]

    Можно также переназначить функцию пользователя:

    > alias(Fx=F(x));

    BJ, Fx

    > diff(F(x),x);

    > int(F(x),x=a..b);

    Для отмены переназначения, например BJ, используется та же функция alias с повтором переназначения:

    > alias(BJ=BJ);

    Fx

    > BJ(0,1.);

    BJ(0, 1.)

    Обратите внимание на то, что BJ исчезло из списка переназначений и функция BJ(0,1.) уже не вычисляется, поскольку ее больше нет.

    10.7.2. Модули

    Модули придают языку программирования Maple некоторые свойства языков объектно-ориентированного программирования. Они служат для реализации абстрактного типа данных на основе инкапсуляции — объединения данных и процедур их обработки. Модули задаются ключевым словом module с пустыми скобками () и завершаются словами end module или просто end:

    name := module()

    export eseq; local lseq; global gseq;

    option optseq; description desc;

     Тело модуля

    end module (или просто end)

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

    • модуль не имеет списка входных параметров;

    • в модуле могут размещаться данные;

    • модули могут использоваться для создания пакетов процедур, доступ к которым обеспечивается командой with;

    • модули имеют свойства в виде локальных переменных и методы в виде процедур интерфейса модулей;

    • реализация абстрактных типов данных с помощью модулей скрыта от пользователя;

    • модули могут содержать оператор export eseq, объявляющий экспортируемые переменные модуля;

    • для доступа к экспортируемым переменным модуля может использоваться специальный оператор «:-» (двоеточие и минус);

    • модули и процедуры могут вкладываться друг в друга без ограничения уровня вложенности;

    • модули могут иметь специальные конструкторы объектов.

    Следующий пример демонстрирует создание модуля pt в котором заданы две операции (сложения plus и умножения times) и показан доступ к ним:

    > pt:= module()

    export plus, times;

    plus : = (a,b) -> a + b;

    times := (a,b) -> a * b;

    end module;

    pt := module() export plus, times; end module

    > pt:-plus(3,5);

    8

    > pt:-times(3,7);

    21

    Детальную информацию о модулях и о конструкторах объектов можно найти в справках по ним. Некоторые пакеты уже в Maple 8 реализованы не в виде процедур, а в виде модулей (например, в виде модуля сделан пакет LinearAlgebra). В простейшем виде модули могут использоваться всеми пользователями системы Maple, но их серьезное применение (например, с целью создания полноценных пакетов Maple) требует серьезного знакомства с техникой объектно-ориентированного программирования. Такое знакомство выходит за рамки данной книги.

    10.7.3. Макросы

    Макрос — это макрокоманда, короткая запись длинных определений. По сравнению с переназначениями макросы более гибки и могут использоваться для сокращения операций загрузки новых определений из библиотеки и пакетов. Макросы создаются с помощью функции macro:

    macro(e1, е2, ..., en)

    где е1, е2, …, en — ноль или более равенств.

    В следующем примере функция numbperm с помощью макроса заменена на np:

    > with(combinat, numbperm);

    [numbperm]

    > numbperm([1,2,3,4]);

    24

    > macro(np=numbperm(V));

    np

    > V:=[1,2,3,4];

    V:= [1, 2, 3, 4]

    > np(V);

    24

    Макросы могут быть использованы для конструирования выражений из их макроопределений.

    10.7.4. Внешние вызовы

    Maple имеет команду system(string), с помощью которой можно исполнить любую команду MS-DOS, записанную в виде строки string. Например, для форматирования гибкого диска из среды Maple можно использовать стандартную команду MS-DOS:

    > system(`format а:`);

    На экране появится окно MS-DOS с начальным диалогом форматирования диска А. Это окно показано на рис. 10.6.

    Рис. 10.6. Результат выполнения команды форматирования гибкого диска


    При работе в операционной системе Windows эта возможность практически бесполезна, поскольку форматирование диска с большими удобствами можно выполнить средствами Windows.

    Внешние вызовы командой system куда более полезны для MS-DOS-реализаций Maple, которые кое-где используются и по сей день. Но, поскольку данная книга посвящена самым современным Windows-реализациям системы Maple, более подробное рассмотрение операций внешних вызовов не имеет особого смысла.

    10.7.5. Вызов внешних процедур, написанных на языке С

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

    • вся идеология системы Maple основана на максимальном исключении программирования на других языках, помимо Maple-языка;

    • язык С сложен для большинства пользователей Maple, которых трудно отнести к «путным» программистам;

    • отладка комплекса Maple + компилятор С (например, фирмы Microsoft) вряд ли под силу обычным пользователям, тем более, что на практике такой комплекс реально не работает без кропотливой отладки.

    Учитывая сказанное, мы отметим лишь, что для использования внешних процедур (например, остро нужных пользователю или более быстрых, чем аналогичные процедуры Maple) используется специальная команды define external, которая генерирует две интерфейсные программы — на языке С и на языке Maple, соответственно. Программа на языке С компилируется вместе с внешней процедурой, которая будет использоваться. Результирующий код создает динамически подключаемую библиотеку DLL. В свою очередь программа на языке Maple служит как интерфейсная для организации взаимодействия с вызываемой внешней процедурой. Более подробное описание возможностей работы с внешними процедурами можно найти в справке по ним.

    10.8. Визуально-ориентированное программирование интерфейса

    10.8.1. Вызов пакета Maplets

    В последние версии Maple был введен новый пакет расширения Maplets, который обеспечивает построение визуально-ориентированных элементов интерфейса для документов системы. Этот пакет создан на основе применения средств языка Java, так что для его применения надо позаботиться, что бы Java был инсталлирован на применяемом для работы с Maple компьютере.

    О вызове пакета и его составе в Maple 9.5 можно судить по приведенным ниже командам.

    > restart; with(Maplets);

    [Display, Elements, Examples, Tools, Utilities]

    Последний раздел Utilities был добавлен в реализацию Maple 9.5. Детальные данные о составе пакета можно получить, используя следующие команды

    > with(Maplets[Elements]) ;

    > with(Maplets[Examples]);

    > with(Maplets[Tools]);

    > with(Maplets[Utilities]);

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

    10.8.2. Примеры создания визуально-ориентированного интерфейса

    Начнем с простого примера. Следующая команда (файл mmp0)

    > c:=parse(Maplets[Examples][GetInput]("Введите целое число:", 'type'

    = plain));

    выводит диалоговое маплет-окно ввода с сообщением «Введите целое число:». Это окно показано на рис. 10.7. В нем можно ввести любое целое положительное или отрицательное число, например 1. Нажатие кнопки OK закрывает окно ввода и задает переменной С значение вводимого числа — в строке вывода будет С=1.

    Рис. 10.7. Создание кнопки для остановки и запуска вычислений


    Строка

    > if с>0 then lprint("Число положительно!") fi;

    анализирует знак числа и если оно положительно, то выводит сообщение

    "Число положительно!"

    Этот пример поясняет возможность диалогового ввода и последующей его обработки, например в составе той или иной процедуры. Более солидное действие производит функция вызова диалогового окна вычисления интегралов (файл mmp1), представленная ниже:

    > with(Maplets[Examples]): Integration(sin(х^3)*х^2);

    Это функция вначале вызывает появление окна с запросом типа вычисляемого интеграла — определенного или неопределенного. Оно показано на рис. 10.8.

    Рис. 10.8. Вызов окна задания интегралов


    Задав, к примеру, вычисление неопределенного интеграла можно получить окно с заданным интегралом. Но можно (см. рис. 10.9) задать в панели ввода и любое другое подынтегральное выражение, а также указать переменную интегрирования. Кнопка Clear очищает окно, а кнопка Integrate обеспечивает вычисление интеграла, что и показано на рис. 10.7. Если нажать кнопку OK, то вычисленное значение интеграла будет перенесено в строку вывода. А кнопка Cancel обеспечивает отказ от данной операции.

    Рис. 10.9. Вывод окна задания и вычисления неопределенных интегралов


    Еще один пример (файл mmp2)

    > with(Maplets[Elements]): maplet3d := Maplet([["Enter a function of 'x' and 'y':", TextField['TF3d']()], Plotter['PL1'](),

    [Button("Plot", Evaluate('PL1' = 'plot3d(TF3d, x = 0..10, y=0..10)'} ), Button("OK", Shutdown(['TF3d']))]]): result := Maplets[Display](maplet3d);

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

    Рис. 10.10. Вызов и применение окна построения трехмерного графика, заданной в его поле функции

    10.8.3. Управление цветом

    Пакет Maplets можно использовать для эффективного (и эффектного) управления цветом. Для этого достаточно использовать команду:

    > with(Maplets[Examples]):

    GetColor('title' = "Get Color");

    При исполнении этой команды появляется окно задания цвета, показанное на рис. 10.11. В этом окне имеется три вкладки дня установки цвета в одной из трех цветовых систем: Swathes, HSB и RGB. Все они дают разные способы задания цвета в интерактивном режиме. Рис. 10.11 демонстрирует наиболее распространенный способ задания цвета в системе RGB. При этом с помощью ползунковых регуляторов можно задать интенсивность каждой составляющей света. Red — красной, Green — зеленой и Blue — синей. В части окна Preview (Предварительный Просмотр) можно наблюдать за изменением цвета текста, основы и пикселей.

    Рис. 10.11. Окно задания цвета


    Если после установки подходящего цвета нажать кнопку OK, то будет сформирована строка с командами задания выбранного цвета. Для примера, показанного на рис. 10.11, эта строка имеет вид:

    >

    Если использовать эту команду в любой графической функции, то объект (или часть объекта) будет окрашена в заданный цвет.

    Разумеется, пакет Maplets предназначен, прежде всего, для создания диалоговых и прочих окон и элементов интерфейса при создании программных модулей. С пакетом пока не все гладко — иногда окна появляются с заметной задержкой, случаются и сбои при работе с ними. Кроме того, пользователь, уже привыкший к простоте и наглядности работы с обычными документами в одном общем для всех объектов окне, может критически оценивать представленные выше возможности. Тем не менее, корпорация MapleSoft явно сделала ставку на широкое применение маплет-средств для разработки обучающих средств с повышенной наглядностью и работой в интерактивном (диалоговом) режиме.

    10.9. Моделирование RLC-цепи с применением маплет-интерфейса

    10.9.1. Подготовка процедуры моделирования и тестового примера

    Теперь рассмотрим пример на моделирование последовательной RLС-цепи, подключенной к источнику напряжения с заданной произвольно временной зависимостью v(t). Наша задача заключается в нахождении тока i(t) из решения системы из двух дифференциальных уравнений заряда:

    где q(t) — временная зависимость заряда в конденсаторе С и i(t) — искомая временная зависимость тока в цепи. Полный текст документа, решающего данную задачу представлен в файле RCL_maplets.

    Maple-процедура lrc, позволяющая вычислять i(t) по этой системе дифференциальных уравнений представлена ниже:

    > restart;

    > lrc := proc(L, R, С, q0, i0, tf, v)

     local de, ics, sol, q, i, p;

     de :=L*diff(q(t),t,t)+ R*diff(q(t),t)+(1/C)*q(t)= v;

     ics :=q(0) = q0,D(q)(0)= i0;

     sol :=dsolve({de, ics},q(t), range=0..tf,numeric);

     plots[odeplot](sol, [[t,v,color=red],[t, diff(q(t),t), color=blue]],

     t=0..tf,legend=["v(t)", "i(t)"], numpoints=1000);

    end proc:

    Подготовим тестовый пример. Пусть L=250 mH, С=500 mF, R=100 mOhm, v(t)=sin(10*t)*exp(t/2) при нулевых начальных условиях и интервале времени от 0 до 5 обращение к процедуре lrc имеет вид

    > lrc(.25, .1, .5, 0, 0, 5, sin(10*t)*ехр(-t/2));

    и ведет к построению графика переходных процессов — v(t) и i(t), показанного на рис. 10.12.

    Рис. 10.12. Временные зависимости v(t) и i(t) при моделировании LCR-цепи


    Нетрудно заметить, что переходные процессы достаточно сложны, хотя и вполне понятны читателю, разбирающемуся в радиотехнических цепях.

    10.9. 2. Подготовка окна маплет-интерфейса

    Теперь зададимся целью построить окно маплет-интерфейса, имеющего следующие детали:

    • поле для задания индуктивности L в mH;

    • слайдеры для задания резистивности R в mOhm и емкости С в mF;

    • поля для задания начальных значений q0 и i0 и конечного времени t;

    • поле для задания временной зависимости i(t) по умолчанию sin(10*t);

    • кнопки Plot для построения графиков временных зависимостей v(t) и i(t) и Close для закрытия окна;

    • подокно для отображения графиков временных зависимостей v(t) и i(t).

    Поскольку построение маплет-интерфейса уже было подробно описано, приведем процедуру lrc_maplet, реализующую эти возможности:

    > lrc_maplet : = proc()

    local OPTIONS, COMMAND, WINDOW, MAPLET,LINE1,LINE2, LINE3, LINE4, LINE5, LINE6, L, R, C, q0, i0, tf, v;

    use Maplets, Maplets[Elements] in L, R,C,q0,i0,tf: = 1/10,1/10,1/10,0,0,10;

     v := sin(10*t);

     OPTIONS:= title="RLC Circuit Simulator";

     COMMAND:= Evaluate(function="lrc_simulate");

     LINE1:= "L(mH):",TextBox[L_](value=L*1000, onchange=COMMAND);

     LINE2 := "R (mOhm): ", Slider[R_]

     (value=R*1000,lower=0,upper=1*1000, majorticks=100, minorticks=10,filled=true,onchange=COMMAND);

     LINE3 := "C (mF): ", Slider[C_](value=C*1000, lower=0, upper=1*1000,majorticks=100, minorticks=10, filled=true, onchange=COMMAND);

     LINE4 := "q0: ", TextBox[q0_](value=q0,onchange=COMMAND), "i0: ", TextBox[i0_](value=i0, onchange=COMMAND),"tf: ", TextBox[tf_](value=tf, onchange=COMMAND);

     LINE5 := "v(t): TextBox[v_](value=v,onchange=COMMAND), Button("Plot", COMMAND), Button("Close", Shutdown());

     LINE6 := Plotter[p_]();

     WINDOW := Window[W_](OPTIONS,[[LINE1],[LINE2],[LINE3],[LINE4],[LINE5],[LINE6]]);

     MAPLET := Maplet(WINDOW); Display(MAPLET);

    end use;

    end proc:

    10.9.3. Организация связи между процедурой моделирования и маплет-интерфейсом

    Следующая процедура служит для связи между процедурой моделирования RLC-цепи и процедурой задания маплет-окна:

    > lrc_simulate := proc()

    local L, R, С, q0, i0, tf, v, p;

    use Maplets[Tools] in

     L := Get(L_(value)::algebraic, corrections=true);

     R := Get(R_(value)::algebraic, corrections=true);

     С := Get(С_(value)::algebraic, corrections=true);

     L, R, С := (L, R, C)/1000; # преобразование mH -> H, etc.

     q0 := Get(q0_(value)::algebraic, corrections=true);

     i0 := Get(i0_ (value)::algebraic, corrections=true);

     tf := Get(tf_(value)::algebraic, corrections=true);

     v := Get(v_(value)::algebraic, corrections=true);

     p := lrc(L, R, C, q0, i0, tf, v);

     Set(p_(value) = p);

    end use;

    end proc:

    В эту процедуру включены проверки на алгебраичность вводимых с маплет-окна параметров.

    10.9.4. Моделирование RLC-цепи в окне маплет-интерфейса

    Теперь все готово к началу моделирования RLС-цепи с применением маплет-интерфейсного окна. Для этого достаточно исполнить команду:

    > lrc_maplet();

    Появится окно, представленное на рис. 10.13 поначалу с пустым подокном вывода графиков. Графики, показанные на рис. 10.13, появятся после активизации кнопки Plot.

    Рис. 10.13. Моделирование RLC-цепи с параметрами, заданными по умолчанию


    При параметрах взятых по умолчанию частота собственных колебаний RLC-контура близка к частоте синусоидального воздействия и наблюдаются нарастающие почти синусоидальные колебания тока — случай сам по себе интересный, хотя и хорошо известный.

    А теперь зададим в окне данные для тестового примера. Для этого изменим значения L, С (R остается прежним) и конечное время tf, а также изменим временную зависимость v(t) добавив в нее экспоненциальный член. Запустив моделирование кнопкой Plot, получим новый рисунок 10.14. Сравнив его с тестовым примером (рис. 10.14) убеждаемся в полной идентичности расчетных переходных процессов.

    Рис. 10.14. Моделирование RLC-цепи в маплет-окне с параметрами тестового примера


    Следует отметить, что кнопка Plot должна нажиматься только при изменении параметров, вводимых в полях. При перемещении слайдеров для R и С перестройка графиков происходит автоматически. Это позволяет наглядно оценивать переходные процессы при плавном изменении этих параметров. На рис. 10.15 показан случай, когда движком слайдера значительно уменьшена емкость С, что привело к близости частот синусоидальной компоненты входного сигнала и собственной частоты контура. В итоге получен еще один интересный вариант переходного процесса — вначале амплитуда ставших почти синусоидальными колебаний тока нарастает, но затем падает (из-за экспоненциального уменьшения входного напряжения).

    Рис. 10.15. Моделирование RLС-цепи в маплет-окне с уменьшенным значением емкости С


    Нетрудно заметить, что моделирование RLC-цепи в интерфейсном маплет-окне весьма наглядно. По этому и описанным ранее примерам читатель может легко конструировать свои маплет-окна и готовить в Maple 9.5/10 программные утилиты вполне профессионального качества.

    10.10. Визуально-ориентированное проектирование маплетов в Maple 10

    10.10.1. Ассистент по проектированию маплетов Maplet Builder

    В Maple 10, наряду с описанным выше программным заданием маплетов, возможно визуально-ориентированное проектирование их. Для этого в состав ассистентов включен Maplet Builder. Его окно в полностью открытом виде до начала проектирования маплета показано на рис. 10.16.

    Рис. 10.16. Окно ассистента по проектированию маплета


    Это окно по вертикали делится на три области:

    • наборы элементов маплета в виде кнопок;

    • окна проектирования и наблюдения маплета;

    • задания параметров и опций элементов маплета.

    Конструирование маплета сводится к переносу мышью (методом Drag And Drop) того или иного элемента (или нескольких элементов) и установке параметров расположения, исполнения, цветового оформления и т.д. Именно последнее представляет основные трудности в реализации маплетов. К сожалению, поддержка символов кириллицы в созданных этим методом маплетов не поддерживается — хотя надписи с такими символами вводятся, но при записи маплетов в виде файла сообщается о недопустимости использования таких символов.

    10.10.2. Пример проектирования маплета — окна с текстовой надписью

    Рассмотрим простой пример проектирования маплета — окна с текстовой надписью, которое соответствует канонам создания окон для приложений операционной системы Windows и внутри содержи надпись «My first maplet!». Для создания такого маплета достаточно в разделе Body найти кнопку с именем Label и перетащить ее в окно конструирования маплета. Затем в области задания параметров надо в разделе caption задать нужную надпись и открыв позицию File меню выбрать команду Run. Это приведет к появлению в окне будущего маплета заданной надписи и окна с предупреждением о необходимости записи маплета в файл — рис. 10.17.

    Рис. 10.17. Подготовка маплета в виде окна с надписью


    После записи файла маплета он окончательно формируется в виде стандартного окна Windows и надписью в нем — рис. 10.18. Маплет можно перемещать по окну документа, сворачивать в бирку в панели задач, разворачивать во весь экран и сворачивать к минимальному размеру и закрывать. Для этого в конце титульной строки имеются три обычные кнопки управления окном.

    Рис. 10.18. Маплет в окне текущего документа

    10.10.3. Пример проектирования маплета — окна с графиком функции

    Построим еще един простой маплет — окно с графиком заданной функции. Для этого перетащим в окно проектирования маплета элемент типа окна графики — рис. 10.19. Затем в области параметров этого элемента для параметра value введем строку с командой построения графика функции sin(x)/x: plot(sin(x)/х, x=-10..10). Остальные параметры оставляем заданными по умолчанию, хотя их можно изменять, например для изменения цвета фона, размера и положения рисунка и т.д. Затем в меню File надо исполнить команду Run — появится окно записи маплета в файл.

    Рис. 10.19. Подготовка к созданию маплета — окна с графиком функции


    После записи маплета в файл он сформируется окончательно в виде стандартного окна Windows-приложения с графиком заданной функции — рис. 10.20. Это окно можно перемещать, сворачивать и разворачивать и закрывать.

    Рис. 10.20. Завершение создания маплета — окна с графиком функции

    10.10.4. Справка по проектированию маплетов

    Характер и объем данной книги не позволяют описать подробно визуально-ориентированное проектирование маплетов. Однако, разобрав приведенные выше примеры, читатель может обратиться к справке по проектированию маплетов, которая вызывается активизацией позиции Help меню окна ассистента Maplet Builder. Один из разделов справки с простыми примерами проектирования маплетов представлен в окне, показанном на рис. 10.21.

    Рис. 10.21. Раздел справки с простыми примерами проектирования маплетов


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







     

    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх