Previous: Введение в программирование на Maxima, Up: Программы Maxima   [Contents][Index]

38.2 Функции и переменные для программирования на Maxima

Функция: backtrace ()
Функция: backtrace (n)

Печатает стек вызовов, т.е. список функций, которые вызывают текущую активную функцию.

Вызов backtrace() печатает весь стек вызовов.

Вызов backtrace (n) печатает n последних функций, включая текущую.

Функция backtrace может вызываться внутри программы, функции или из интерактивного приглашение а не только из контекста отладки.

Примеры:

Специальный оператор: do

Команда do используется для выполнения итераций. Т.к. команда do довольно обща, то она будет описана в двух частях. Сначала будет описана обычная форма, аналогична используемым в нескольких других языках программирования (Fortran, Algol, PL/I и т.д.). Далее будут описаны другие возможности.

Существует три формы команды, отличающиеся только условием завершения. А именно:

(Как альтернатива, команда step может быть задана после условия завершения или границы.)

Параметры initial_value, increment, limit и body могут быть произвольными выражениями. Если приращение равно 1, то команда "step 1" может быть опущена.

Перед выполнение команды do, переменной variable (далее называемой управляющей переменной) присваивается начальное значение initial_value. Далее: (1) если значение управляющей переменной превышает верхнюю границу, задаваемую thru, или если условие unless равно true, или условие while равно false, то do завершается. (2) Вычисляется body. (3) Приращение добавляется к управляющей переменой. Шаги (1) – (3) повторяются до выполнения условия завершения. Можно задавать несколько условий завершения. В этом случае команда do завершается при удовлетворении любого из них.

Обычно тест thru выполняется, когда управляющая переменная становится больше limit, когда приращение increment неотрицательно, или, если переменная становится меньше limit, когда приращение increment отрицательно. Параметры increment и limit могут быть нечисловыми выражениями, если может быть определено их неравенство. Однако, если increment не является синтаксически отрицательным (например, отрицательным числом) в момент начала выполнения команды do, то Maxima предполагает положительность increment во время выполнения do. Если на самом деле increment окажется неположительным, то do может не завершиться надлежащим образом.

Отметим, что limit, increment и условие завершения вычисляются заново для каждой итерации. Таким образом, если какое-либо из этих выражений требует длительного вычисления, но не меняется от итерации к итерации при вычислении body, то будет более эффективным присвоить их значение переменной до выполнения do и использовать эту переменную.

Значение, обычно возвращаемое командой do, есть атом done. Однако, функция return может быть использована внутри body для завершения do и задания возвращаемого значения. Отметим, что вызов return внутри цикла do, расположенного в блоке block, завершает do а не блок block. Функция go не может быть использована для выхода из команды do в объемлющий блок block.

Управляющая переменная всегда локальна в рамках do, т.е. эту переменную можно использовать внутри цикла и это не окажет влияния на переменную с тем же именем вне do. После завершения do, управляющая переменная остается несвязанной.

(%i1) for a:-3 thru 26 step 7 do display(a)$
                             a = - 3

                              a = 4

                             a = 11

                             a = 18

                             a = 25
(%i1) s: 0$
(%i2) for i: 1 while i <= 10 do s: s+i;
(%o2)                         done
(%i3) s;
(%o3)                          55

Отметим, что условие while i <= 10 эквивалентно условию unless i > 10 или условию thru 10.

(%i1) series: 1$
(%i2) term: exp (sin (x))$
(%i3) for p: 1 unless p > 7 do
          (term: diff (term, x)/p, 
           series: series + subst (x=0, term)*x^p)$
(%i4) series;
                  7    6     5    4    2
                 x    x     x    x    x
(%o4)            -- - --- - -- - -- + -- + x + 1
                 90   240   15   8    2

что дает 8 членов ряда Тейлора для e^sin(x).

(%i1) poly: 0$
(%i2) for i: 1 thru 5 do
          for j: i step -1 thru 1 do
              poly: poly + i*x^j$
(%i3) poly;
                  5      4       3       2
(%o3)          5 x  + 9 x  + 12 x  + 14 x  + 15 x
(%i4) guess: -3.0$
(%i5) for i: 1 thru 10 do
          (guess: subst (guess, x, 0.5*(x + 10/x)),
           if abs (guess^2 - 10) < 0.00005 then return (guess));
(%o5)                  - 3.162280701754386

В этом примере вычисляется отрицательный квадратный корень числа 10 с использованием метода Ньютона-Рафсона с максимальным числом итераций 10. Если условие сходимости не будет выполнено, то возвращается значение done.

Вместо добавления значения к управляющей переменной возможен другой способ ее изменения на каждом цикле итерации. В этом случае можно использовать next expression вместо step increment. Что вызывает присваивание управляющей переменной значения expression при каждой итерации.

(%i6) for count: 2 next 3*count thru 20 do display (count)$
                            count = 2

                            count = 6

                           count = 18

Синтаксис for variable from value ...do... может быть использован как альтернатива for variable: value ...do.... Что позволяет располагать from value после значений step или next, или после условия завершения. Если from value опущено, то в качестве начального значения предполагается 1.

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

(%i1) x: 1000$
(%i2) thru 20 do x: 0.5*(x + 5.0/x)$
(%i3) x;
(%o3)                   2.23606797749979
(%i4) sqrt(5), numer;
(%o4)                   2.23606797749979

Если необходимо, то можно полностью опустить условия завершения и использовать только do body, что вызывает бесконечное вычисление body. В этом случае для завершения do следует использовать return.

(%i1) newton (f, x):= ([y, df, dfx], df: diff (f ('x), 'x),
          do (y: ev(df), x: x - f(x)/y, 
              if abs (f (x)) < 5e-6 then return (x)))$
(%i2) sqr (x) := x^2 - 5.0$
(%i3) newton (sqr, 1000);
(%o3)                   2.236068027062195

(Заметим, что return вызывает возвращение текущего значения x в качестве значения do. Блок block завершается, и значение do возвращается в качестве значения блока, т.к. do является последней командой block.)

В Maxima доступна еще одна форма команды do. Ее синтаксис:

for variable in list end_tests do body

Элементы списка list (произвольные выражения) последовательно присваиваются переменной variable Для каждой итерации вычисления body. Необязательное условие end_tests может использоваться для завершения do, иначе цикл завершится при исчерпании list или при выполнении return внутри body. (На самом деле, list может быть любым неатомарным выражением, последовательные части которого будут использованы в итерации.)

(%i1)  for f in [log, rho, atan] do ldisp(f(1))$
(%t1)                                  0
(%t2)                                rho(1)
                                     %pi
(%t3)                                 ---
                                      4
(%i4) ev(%t3,numer);
(%o4)                             0.78539816
Функция: errcatch (expr_1, ..., expr_n)

Вычисляет одно за другим выражения expr_1, ..., expr_n и, если не возникает ошибок, возвращает [expr_n] (список). Если при вычислении одного из аргументов возникает ошибка, то errcatch предотвращает дальнейшее распространение ошибки и возвращает пустой список [] без дальнейшего вычисления аргументов.

Функция errcatch полезна в пакетных batch файлах, если ожидается возможное возникновение ошибки, что без перехвата ошибки приводит к завершению batch.

Функция: error (expr_1, ..., expr_n)
Системная переменная: error

Вычисляет и печатает expr_1, ..., expr_n, и затем вызывает ошибку, что возвращает управление на верхний уровень Maxima или ближайшему объемлющему errcatch.

Значением переменной error является список, описывающий ошибку. Первый элемент error – строка форматирования, которая объединяет все строки из параметров expr_1, ..., expr_n, остальные элементы – есть значения нестроковых аргументов.

Функция errormsg() форматирует и печатает error, что повторяет печать самой последней ошибки.

Функция: errormsg ()

Повторяет печать самой последней ошибки. Информация об ошибке содержится в переменной error, и errormsg форматирует и печатает ее.

Специальный оператор: for

Используется в циклах. См. do для описания средств Maxima для организации итераций.

Функция: go (tag)

Используется внутри блока block для передачи управления на команду, помеченную параметром go. Для пометки команды в блоке, перед ней помещают другую команду в виде атома (метки). Например:

block ([x], x:1, loop, x+1, ..., go(loop), ...)

Аргументом go должна быть метка, определенная в том же блоке block. Нельзя использовать go для передачи управления на метку в блоке отличном от того, где находится сама команда go.

Специальный оператор: if

Условное вычисление. Существуют различные формы условного выражения if.

if cond_1 then expr_1 else expr_0 вычисляет и возвращает значение expr_1, если значение cond_1 равно true, иначе вычисляет и возвращает значение expr_0.

if cond_1 then expr_1 elseif cond_2 then expr_2 elseif ... else expr_0 вычисляет и возвращает значение expr_k, если cond_k равно true а все предыдущие условия равны false. Если не одно из условий не равно true, то вычисляется и возвращается значение expr_0.

Если завершающее else отсутствует, то в конце подразумевается else false. Т.е. if cond_1 then expr_1 эквивалентно if cond_1 then expr_1 else false, а if cond_1 then expr_1 elseif ... elseif cond_n then expr_n эквивалентно if cond_1 then expr_1 elseif ... elseif cond_n then expr_n else false.

Альтернативы expr_0, ..., expr_n могут быть произвольными выражениями Maxima, включая вложенные if выражения. Альтернативы не упрощаются и не вычисляются до тех пор пока соответствующее условие не равно true.

Условия cond_1, ..., cond_n являются выражениями, которые потенциально или фактически вычисляются в true или false. Если значение условия не равно ни true, ни false, то поведение if управляется глобальной переменной prederror. Если prederror равна true, то любое значение условия, отличное от true или false, считается ошибкой. Иначе, условия, которые не вычисляются в true или false, считаются допустимыми и результатом вычисления является условное выражение.

Вместе с другими элементами, условия могут включать следующие логические операторы и операторы отношения.

Операция                    Символ      Тип
 
меньше                      <           отношение, инфиксный
меньше или равно            <=          отношение, инфиксный
равенство (синтаксическое)  =           отношение, инфиксный
отрицание =                 #           отношение, инфиксный
равенство (значение)        equal       отношение, функция
отрицане equal              notequal    отношение, функция
больше или равно            >=          отношение, инфиксный
больше                      >           отношение, инфиксный
и                           and         логический, инфиксный
или                         or          логический, инфиксный
нет                         not         логический, префиксный
Функция: map (f, expr_1, ..., expr_n)

Возвращает выражение, с оператором верхнего уровня таким же как у выражений expr_1, ..., expr_n но аргументы которого являются результатами применения f к соответствующим аргументам выражений expr_i. Здесь, f – либо функция n аргументов, либо lambda выражение с n аргументами.

Если переменная maperror равна false, то map: (1) остановится на самом коротком выражении expr_i, если не все expr_i имеют одинаковую длину; (2) применит f к [expr_1, expr_2,...], если не все expr_i имеют одинаковый тип. Если maperror равна true, то в оба вышеуказанных случая считаются ошибкой.

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

(%i1) map(f,x+a*y+b*z);
(%o1)                        f(b z) + f(a y) + f(x)
(%i2) map(lambda([u],partfrac(u,x)),x+1/(x^3+4*x^2+5*x+2));
                           1       1        1
(%o2)                     ----- - ----- + -------- + x
                         x + 2   x + 1          2
                                         (x + 1)
(%i3) map(ratsimp, x/(x^2+x)+(y^2+y)/y);
                                      1
(%o3)                            y + ----- + 1
                                    x + 1
(%i4) map("=",[a,b],[-0.5,3]);
(%o4)                          [a = - 0.5, b = 3]


Функция: mapatom (expr)

Возвращает true тогда и только тогда, когда выражение expr рассматривается map-процедурами как атомарное выражение. К таким "mapatoms" относятся атомы, числа (включая рациональные) и переменные с индексом.

Управляющая переменная: maperror

Значение по умолчанию: true

Если переменная maperror равна false, то все map функции, например:

map (f, expr_1, expr_2, ...)

(1) остановится на самом коротком выражении expr_i, если не все expr_i имеют одинаковую длину; (2) применит f к [expr_1, expr_2,...], если не все expr_i имеют одинаковый тип.

Если maperror равна true, то в оба вышеуказанных случая считаются ошибками.

Управляющая переменная: mapprint

Значение по умолчанию: true

Если переменная mapprint равна true, то функции map, mapl и fullmap в определенных ситуациях выдают различные сообщения. Включая ситуации, когда map использует apply или map обрезает до самого короткого списка.

Если mapprint равна false, то данные сообщения подавляются.

Функция: maplist (f, expr_1, ..., expr_n)

Возвращает список с f, примененной к частям выражений expr_1, ..., expr_n. f – есть имя функции или лямбда-выражение.

Функция maplist отличается от map (f, expr_1, ..., expr_n), которая возвращает выражение с главным оператором, одним для всех выражений expr_i (за исключеним упрощений и случая, когда map выполняет apply).

Управляющая переменная: prederror

Значение по умолчанию: false

Если prederror равна true, то ошибка случается всякий раз, как только вычисленное значение предиката команды if или функции is отлично от true или false.

Если false, то в этом случае возвращается unknown. Работа с prederror: false не поддерживается транслированном коде. Однако, maybe поддерживается в транслированном коде.

См. также is и maybe.

Функция: return (value)

Используется для явного выхода из блока, делая value значением этого блока. См. block для более детального описания.

Функция: scanmap (f, expr)
Функция: scanmap (f, expr, bottomup)

Применяет функцию f к expr рекурсивно начиная с верхнего уровня и глубже. Это может быть полезно, если, например, требуется полная факторизация:

(%i1) exp:(a^2+2*a+1)*y + x^2$
(%i2) scanmap(factor,exp);
                                    2      2
(%o2)                         (a + 1)  y + x

Отметим, что то, как scanmap применяет данную функцию factor к подвыражениям expr, зависит от формы этого выражения. И если дана другая форма expr, то результат scanmap может быть другим. Так, %o2 не получится, если scanmap применить к раскрытому варианту exp:

(%i3) scanmap(factor,expand(exp));
                           2                  2
(%o3)                      a  y + 2 a y + y + x

Еще один пример рекурсивного применения scanmap ко всем подвыражениям, включая экспоненты:

(%i4) expr : u*v^(a*x+b) + c$
(%i5) scanmap('f, expr);
                    f(f(f(a) f(x)) + f(b))
(%o5) f(f(f(u) f(f(v)                      )) + f(c))

scanmap (f, expr, bottomup) применяет f к expr с самого глубокого уровня вверх. Например, для неопределенной функции f,

scanmap(f,a*x+b) ->
   f(a*x+b) -> f(f(a*x)+f(b)) -> f(f(f(a)*f(x))+f(b))
scanmap(f,a*x+b,bottomup) -> f(a)*f(x)+f(b)
    -> f(f(a)*f(x))+f(b) ->
     f(f(f(a)*f(x))+f(b))

В данном случае результат одинаков для обоих вариантов вызова.

Функция: throw (expr)

Вычисляет выражение expr и "бросает" его значение вверх до ближайшего catch. Функции throw и catch реализуют механизм нелокального возврата.

Специальный оператор: while
Специальный оператор: unless

См. do.

Функция: outermap (f, a_1, ..., a_n)

Применяет функцию f к каждому элементу внешнего произведения a_1 x a_2 ... x a_n.

f – есть имя функции с n аргументами или лямбда-выражение с n аргументами. Каждый элемент a_k может быть списком, списком списков, матрицей или любым другим выражением.

Значение outermap является вложенной структурой. Пусть x является возвращаемым значением. Тогда x имеет ту же структуру, как первый аргумент (список, список списков или матрица), x[i_1]...[i_m] имеет ту же структуру, как второй аргумент (список, список списков или матрица), x[i_1]...[i_m][j_1]...[j_n] имеет ту же структуру, как третий аргумент (список, список списков или матрица), и т.д., где m, n, ... – есть число индексов, необходимых для для доступа к элементам каждого из аргументов (один для списка, два для матрицы, еще один для вложенного списка). Аргументы, не являющиеся списками и матрицами, не оказывают влияния на возвращаемое значение.

Отметим, что результат outermap отличается от применения f ко всем элементам внешнего произведения, возвращаемого cartesian_product. Функция outermap сохраняет структуру аргументов в возвращаемом значении, а cartesian_product нет.

Функция outermap вычисляет свои аргументы.

См. также map, maplist и apply.

Примеры:

Простые примеры outermap. Для прояснения комбинации аргументов, F оставлена неопределенной.

(%i1) outermap (F, [a, b, c], [1, 2, 3]);
(%o1) [[F(a, 1), F(a, 2), F(a, 3)], [F(b, 1), F(b, 2), F(b, 3)], 
                                     [F(c, 1), F(c, 2), F(c, 3)]]
(%i2) outermap (F, matrix ([a, b], [c, d]), matrix ([1, 2], [3, 4]));
         [ [ F(a, 1)  F(a, 2) ]  [ F(b, 1)  F(b, 2) ] ]
         [ [                  ]  [                  ] ]
         [ [ F(a, 3)  F(a, 4) ]  [ F(b, 3)  F(b, 4) ] ]
(%o2)    [                                            ]
         [ [ F(c, 1)  F(c, 2) ]  [ F(d, 1)  F(d, 2) ] ]
         [ [                  ]  [                  ] ]
         [ [ F(c, 3)  F(c, 4) ]  [ F(d, 3)  F(d, 4) ] ]
(%i3) outermap (F, [a, b], x, matrix ([1, 2], [3, 4]));
       [ F(a, x, 1)  F(a, x, 2) ]  [ F(b, x, 1)  F(b, x, 2) ]
(%o3) [[                        ], [                        ]]
       [ F(a, x, 3)  F(a, x, 4) ]  [ F(b, x, 3)  F(b, x, 4) ]
(%i4) outermap (F, [a, b], matrix ([1, 2]), matrix ([x], [y]));
       [ [ F(a, 1, x) ]  [ F(a, 2, x) ] ]
(%o4) [[ [            ]  [            ] ], 
       [ [ F(a, 1, y) ]  [ F(a, 2, y) ] ]
                              [ [ F(b, 1, x) ]  [ F(b, 2, x) ] ]
                              [ [            ]  [            ] ]]
                              [ [ F(b, 1, y) ]  [ F(b, 2, y) ] ]
(%i5) outermap ("+", [a, b, c], [1, 2, 3]);
(%o5) [[a + 1, a + 2, a + 3], [b + 1, b + 2, b + 3], 
                                           [c + 1, c + 2, c + 3]]

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

(%i1) arg_1 :  matrix ([a, b], [c, d]);
                            [ a  b ]
(%o1)                       [      ]
                            [ c  d ]
(%i2) arg_2 : [11, 22];
(%o2)                       [11, 22]
(%i3) arg_3 : matrix ([xx, yy]);
(%o3)                      [ xx  yy ]
(%i4) xx_0 : outermap (lambda ([x, y, z], x / y + z), arg_1, 
                                                     arg_2, arg_3);
               [  [      a        a  ]  [      a        a  ]  ]
               [ [[ xx + --  yy + -- ], [ xx + --  yy + -- ]] ]
               [  [      11       11 ]  [      22       22 ]  ]
(%o4)  Col 1 = [                                              ]
               [  [      c        c  ]  [      c        c  ]  ]
               [ [[ xx + --  yy + -- ], [ xx + --  yy + -- ]] ]
               [  [      11       11 ]  [      22       22 ]  ]
                 [  [      b        b  ]  [      b        b  ]  ]
                 [ [[ xx + --  yy + -- ], [ xx + --  yy + -- ]] ]
                 [  [      11       11 ]  [      22       22 ]  ]
         Col 2 = [                                              ]
                 [  [      d        d  ]  [      d        d  ]  ]
                 [ [[ xx + --  yy + -- ], [ xx + --  yy + -- ]] ]
                 [  [      11       11 ]  [      22       22 ]  ]
(%i5) xx_1 : xx_0 [1][1];
           [      a        a  ]  [      a        a  ]
(%o5)     [[ xx + --  yy + -- ], [ xx + --  yy + -- ]]
           [      11       11 ]  [      22       22 ]
(%i6) xx_2 : xx_0 [1][1] [1];
                      [      a        a  ]
(%o6)                 [ xx + --  yy + -- ]
                      [      11       11 ]
(%i7) xx_3 : xx_0 [1][1] [1] [1][1];
                                  a
(%o7)                        xx + --
                                  11
(%i8) [op (arg_1), op (arg_2), op (arg_3)];
(%o8)                  [matrix, [, matrix]
(%i9) [op (xx_0), op (xx_1), op (xx_2)];
(%o9)                  [matrix, [, matrix]

Функция outermap сохраняет структуру аргументов в возвращаемом значении, а cartesian_product нет.

(%i1) outermap (F, [a, b, c], [1, 2, 3]);
(%o1) [[F(a, 1), F(a, 2), F(a, 3)], [F(b, 1), F(b, 2), F(b, 3)], 
                                     [F(c, 1), F(c, 2), F(c, 3)]]
(%i2) setify (flatten (%));
(%o2) {F(a, 1), F(a, 2), F(a, 3), F(b, 1), F(b, 2), F(b, 3), 
                                       F(c, 1), F(c, 2), F(c, 3)}
(%i3) map (lambda ([L], apply (F, L)), 
(%o3) {F(a, 1), F(a, 2), F(a, 3), F(b, 1), F(b, 2), F(b, 3), 
                                       F(c, 1), F(c, 2), F(c, 3)}
(%i4) is (equal (%, %th (2)));
(%o4)                         true

Previous: Введение в программирование на Maxima, Up: Программы Maxima   [Contents][Index]