MAXIMA HOWTO

По материалам различных документаций, распространяемых с системой MAXIMA, равно как и доступных в Интернете; список рассылки MAXIMA mailing list; личные эксперименты с системой.


Как сгруппировать коэффициенты перед моими переменными?

Пусть в сложном выражении надо сгруппировать сомножители при переменных r1, r2, ... . Один из способов сделать это - занести переменные в список рациональных переменных, так, чтобы в дальнейшем выражения? в которых эти переменные встретятся, рассматривались как рациональные выражения от этих переменных. Для этого служит функция RATVARS(var1, var2, ..., varm). После этого функция RATSIMP перегруппирует выражение нужным образом.

ПРИМЕР:

(D3) -d[1][1]*d[1][3]*a[4]+d[3][1]*d[1][2]*a[4]-d[1][1]*d[0][3]*a[3]
                          +d[2][1]*d[1][2]*a[3]+d[0][1]*a[1]*d[1][2]
                          -d[1][1]*d[2][1]*a[1]
(C4) ratvars(a[1],a[2],a[3],a[4]);
(D4) [a[1],a[2],a[3],a[4]]
(C5) ratsimp(d3);
(D5) (d[3][1]*d[1][2]-d[1][1]*d[1][3])*a[4]
      +(d[2][1]*d[1][2]-d[1][1]*d[0][3])*a[3]
      +a[1]*(d[0][1]*d[1][2]-d[1][1]*d[2][1])

Как провести тригонометрические преобразования внутри моего выражения?

В одном из писем, поступившем в список рассылки, содержался вопрос о преобразовании выражения cos(a+b+c)+cos(a+b-c). Решение основывается на последовательном применении функций TRIGEXPAND, FACTOR и TRIGREDUCE. Однако оказалось, что это упрощение нужно выполнить внури другого выражения, и стандартные средства делали либо слишком много, ибо слишком мало. Именно, требовалось упростить выражение r*sin(a+b+c)-r*sin(a+b-c)+d*cos(a+b+c)-d*cos(a+b-c). Предлагаемое здесь решение основано на функции MAPAT, отсутствующей в библиотеке MAXIMA.

mapat([x]):=block([func:first(x),level:second(x),elist:rest(x,2)],
  if length(elist)=1 then elist:first(elist),
  if level>1 then return(mapat(func,level-1,elist)),
  map(func,elist)
  );
(C1) load("c:/tmp/.maxima/mapat.mac");

(D1) 			   c:/tmp/.maxima/mapat.mac
(C2) r*sin(a+b+c)-r*sin(a+b-c)+d*cos(a+b+c)-d*cos(a+b-c)$

(C3) ratvars(r,d);

(D3) 				    [r, d]
(C4) trigexpand(c2);

(D4) (- SIN(a) SIN(b) SIN(C) + COS(a) COS(b) SIN(C) + COS(a) SIN(b) COS(C)

 + SIN(a) COS(b) COS(C)) r + (- SIN(a) SIN(b) SIN(C) + COS(a) COS(b) SIN(C)

 - COS(a) SIN(b) COS(C) - SIN(a) COS(b) COS(C)) r

 - (COS(a) SIN(b) SIN(C) + SIN(a) COS(b) SIN(C) - SIN(a) SIN(b) COS(C)

 + COS(a) COS(b) COS(C)) d + (- COS(a) SIN(b) SIN(C) - SIN(a) COS(b) SIN(C)

 - SIN(a) SIN(b) COS(C) + COS(a) COS(b) COS(C)) d
(C6) ratsimp(d4);

(D6) (2 COS(a) COS(b) - 2 SIN(a) SIN(b)) SIN(C) r

			       + (- 2 COS(a) SIN(b) - 2 SIN(a) COS(b)) SIN(C) d
(C7) mapat(trigreduce,3,d6);

(D7) 		 2 COS(b + a) SIN(C) r - 2 SIN(b + a) SIN(C) d
Похожее решение, данное в списке рассылки,
(C1) r*sin(a+b+c)-r*sin(a+b-c)+d*cos(a+b+c)-d*cos(a+b-c)$
(C2) ratsimp(%);
(C3) r*(sin(a+b+c)-sin(a+b-c))+d*(cos(a+b+c)-cos(a+b-c))$
(C4) trigexpand(%);
(C5) trigsimp(%);
(C6) trigreduce(%);
(D6)  2 COS(b + a) SIN(c) r - 2 SIN(b + a) SIN(c) d
использует вызов функции TRIGSIMP, которая, в свою очередь, вызывает RADCAN. именно последняя функция делает работы по вынесению множителей перед r и d и вынесению также за скобки SIN(c).
Как лучше создать и использовать новопорожденный символ в блоковой переменой?

Ричард Фейтман:
Если вам нужет массив новопорожденных символов, можно сделать так:

block([a],a[1]:?gensym(),a[2]:?gensym() , .....   делаем что-нибудь с ними...);

Как установить число знаков для вычислений с плавающей точкой?

Бартон Уиллис:
Чтобы установить число знаков для вычислейний с большой точностью, надо присвоить новое значение переменной fpprec. Например,

(C1) fpprec : 50;
(D1)                                  50
(C2) sqrt(2.0b0);
(D2)         1.414213562373095048801688724209698078569671875377B0
Числа 2.0 и 2.0d0 оба являются числами с двойной точностью, поэтому значение fpprec не имеет значения для этих чисел


MAXIMA не позволяет писать некторые строки в интерпретаторе, и интерпретатор переписывает их посвоему.

Gosei Furuya :

(C2) sump(f):=not(atom(f)) and part(f,0)='SUM$
sump(f) should return true for expr f, sum(,,,). 
(C3) sump(sum(y^n,n,0,inf));
(D3)             FALSE
(C4) part('sum(x^n,n,0,inf),0)='SUM; //....(1)
(D4)  SUM = SUM
(C5) is(%);
(D5) FALSE
(C6) :lisp (print $d4)
((MEQUAL SIMP) %SUM $SUM)
Нельзя написать $SUM потому, что MAXIMA перепишет это в виде
$%SUM. Остается только написать 
(C7) sump(f):=not(atom(f))and part(f,0)=part('sum(_x^_n,_n,0,1),0)$
not elegant but
(C8) sump(sum(x^n,n,0,inf));
(D9)       TRUE
Ставрос Макракис:
Возможное решение при обращение с существительными и глаголами:
 sump(f):=not(atom(f)) and part(f,0)=nounify('sum)$
или даже
sump(f):=not(atom(f)) and part(f,0)=''(nounify('sum))$
так как nounify будет выполнено только один раз
Как устроены функции с переменным числом аргументов с точки зрения Лиспа?

Ричард Фейтман:

Определить в MAXIMA функцию? принимающую переменной число аргументов можно так:

 f([x]:=x;
Чтобы получить доступ к частям этого x. можно использовать PART, INPART, индексы, FIRST, REST и т.д.
Из Лиспа можно написать
(elt $x 0) --> (mlist simp)
(elt $x 1) --> $a (для f(a,b,c))
Когда MAXIMA была впервые написана, существовали много путей определения функции с различными техниками оценивания аргументов. Это были expr (обычная техника), fexpr, lexpr, и другие. Они все еще могутвстречаться в виде mexpr, mfexpr, и возможно некоторые другие вариации. В сущности все они были включены в Коммон Лисп другими способами? включая аргументы &resr и defmacro.
Как из строки получить список букв? Ричард Фейтман:
(defun $stringtomaximalist(x)(cons '(mlist)(mapcar #'(lambda(z)(concat
'$ z))(cdr (explodec x)))))
Эта функция еще создает символы вида $G, $A, $T etc.
(C9) stringtomaximalist("CGATATATGAGAGAT");
(D9) 		 [C, G, A, T, A, T, A, T, G, A, G, A, G, A, T]

Ваши шаблоны работают неправильно! Рассмотрим пример,
matchdeclare(u,freeof(x))$
matchdeclare(y,freeof(t))$
defmatch(pat1, u*v)$
pat1(exp(x+t));
Ожидаемое разложение
[u=%E^t, v=%E^x]
не получается. В чем причина?
Данный шаблон задает впролне определенную конструкцию и Maxima будет только искать совпадения, не пробуя все возможные разбиения. А выражение
exp(x+y)
даже не является произведением.
Как собрать все члены выражения, удовлетворяющие моему предикату?
Надо напиcать маленький цикл:
selectremove(expr,pred,[ops]):=block([p1:[], p2:[],r], 
    for i:1 thru length(expr) do 
      if (apply(pred,reverse(cons(r:part(expr,i),ops))))  then p1:cons(r,p1) else p2:cons(r,p2),
      [p1,p2]);

Какие уравнения может решать MAXIMA?
Линейные уравнения: функция linsolve
Системы алгебраических уравнений: algsys
Иррациональные уравнения: функция solve_irrat (не входит в дистрибутив, ее код есть в рассылке)
Рекуррентные уравнения: функция char из пакета recur,
также для разностных уравнений первого и второго порядков функция difference (пакет differ)
Простейшие тригонометрические, логарифмические и трансцендентные: функция solve
Как "поймать" результат команды tex()?
Команда tex() имеет второй необязательный аргумент. Так, вызов tex(...,false) вернет строку, содежращую выключенную формулу (то есть в двойных значках доллара). С помощью функции concat строки можно объединять в математический текст:
(C1) concat("Все знают, что $(a+b)^2$ равно ", tex(expand((a+b)^2),false));

(D1) 	      Все знают, что $(a+b)^2$ равно $$b^2+2\,a\,b+a^2$$
Руководство говорит, что вторым аргументом команды tex() может быть имя файла. Однако проблема вознимает, когда это имя передается через переменную. Команда tex() автоматически заковычивает второй аргумент, так что, например, команда tex(expr, expr) запишет значение выражения expr в файл с именем "expr". Итак, возможны следующие решения:
Как нарисовать кардиоиду?
Отвечает Stavros Macrakis: Для создания графиков в полярной системе координат можно воспользоваться следующим приемом. Определим функцию plot_polar
plot_polar(expr,range) :=
    block([theta_var: range[1]],
      plot2d( ['parametric, 
               cos(theta_var)*expr,
               sin(theta_var)*expr,
               range]))$
Теперь, чтобы нарисовать полукруг, введем команду
  plot_polar(1,[t,0,%pi]);
А для кардиоиды достаточно ввести
  plot_polar( 1 + 2 * cos(t), [t,0,2*%pi]);

Как создать функцию из выражения?
Частый вопрос. Вариант типа
f(x):=diff(sin(x),x);
не работает. Работающий вариант
f(x):=subst(t=x,diff(sin(t),t));
неудовлетворителен, поскольку он каждый раз наново перевычисляет производную. И, кроме того, если с переменной t связано значение, то будет получено сообщение об ошибке при дифференцировании. Защитой от этого могло бы быть использование оператора block([t,...],...). Но правильным решением будет использование двойного апострофа: expr: diff(sin(t),t); f(t):= ''expr $ Как указывал Ричард Фейтман, это, на самом деле, главное использование оператора '', который в общем случае не должен использоваться как замена команды ev().
Как вычислить сумму тригонометрических слагаемых?
Сумму
sum(cos(j/N), j, 1, N)
не вычилсить, даже если установить simpsum:true. Надо воспользоваться командой неопределенного суммирования nusum:
(C1) realpart(nusum(exp(%i*j*x),j,1,N));

     SIN(x) SIN(N x + x) + (COS(x) - 1) COS(N x + x)
(D2) -----------------------------------------------
		    2		       2
		 SIN (x) + (COS(x) - 1)

						     2
						  SIN (x) + (COS(x) - 1) COS(x)
					        - -----------------------------
							2		   2
						     SIN (x) + (COS(x) - 1)


Как осуществить присваивание элементов одного вектора элементам другого? Stavros Macrakis рекомендует использовать оператор "::", например:
A_0 : [ x, y, z ] $
q : [ 1, 2, 3 ] $
map("::", A_0, q);

Как избавится от иррациональности в знаменателе?
Это, по существу, школььная задачка: избавиться от иррациональных чисел в знаменателе дроби. Решается она "домножением на сопряженное выражение". Проблемы в том, что для нетривиальных алгебраических чисел растет объем вычислений. В MAXIMA эта задача решается комбинацией функции ratsimp и ключа algebraic:true
(%i1) x : 2/(sqrt(5)+7^(1/3))$

(%i2) ratsimp(x), algebraic:true;
                3/2       2/3                     1/3    5/2
              (5    - 7) 7    + (7 sqrt(5) - 25) 7    + 5    - 35
(%o2)         ---------------------------------------------------
                                      38


Собиратель: Андрей Зорин.
E-mail:
zoav1@uic.nnov.ru