Третий необязательный аргумент определяет форму приведенного выражения, допуская два значения recursive (по умолчанию) и distributed. В первом случае производится рекурсивное приведение выражения относительно каждой из ведущих переменных {x1, x2, ..., xn}, во втором - относительно термов x1p*x2q*...*xnk. Наконец, четвертый необязательный аргумент collect-процедуры позволяет задавать процедуру (Proc), применяемую к коэффициентам приведенного выражения. В качестве такой процедуры наиболее употребительны такие как simplify, factor и sort, рассмотренные выше. В качестве основных приложений collect-процедуры отметим следующие.
Прежде всего, collect-процедура применяется с целью упрощения выражений обобщенной полиномиальной формы путем приведения термов с одинаковыми степенями по обобщенным ведущим переменным. Второй целью является последующая работа с коэффициентами полиномов, для чего желательна их группировка при одинаковых степенях переменных. Для случая полиномов от нескольких переменных collect-процедура позволяет представлять их в различных формах, удобных для конкретных приложений. Указанные случаи применения collect-процедуры весьма наглядно иллюстрирует следующий достаточно простой фрагмент:
> collect(x*y + a*x*y + 9*y*x^2 - a*y*x^2 + x + a*x + b*x^3 - c*x^2, x); b x3 + (9 y - a y - c) x2 + (y + a y + 1 + a) x > collect(x*y + a*x*y + 9*y*x^2 - a*y*x^2 + x + a*x + b*x^3 - c*x^2, x, 'sort'); b x3 + (-y a + 9 y - c) x2 + (y a + y + a + 1) x > collect(x*y + a*x*y + 9*y*x^2 - a*y*x^2 + x + a*x + b*x^3 - c*x^2, {x, y}); b x3 + ((-a + 9) y - c) x2 + ((a + 1) y + a + 1) x > collect(x*y + a*x*y + 9*y*x^2 - a*y*x^2 + x + a*x + b*x^3 - c*x^2, {x, y}, 'distributed'); (a + 1) x + (-a + 9) y x2 + (a + 1) x y + b x3 - c x2 > collect(3*x*y^2 + 3*x^2*y + y^3 - 3*x^2 + 6*x*y - 3*y^2 + 9*x + x^3 + 3*y, x); x3 + (-3 + 3 y) x2 + (3 y2 + 9 + 6 y) x + 3 y - 3 y2 + y3 > collect(3*x*y^2 + 3*x^2*y + y^3 - 3*x^2 + 6*x*y - 3*y^2 + 9*x + x^3 + 3*y, y); y3 + (-3 + 3 x) y2 + (6 x + 3 x2 + 3) y + 9 x - 3 x2 + x3 > collect(3*x*y^2 + 3*x^2*y + y^3 - 3*x^2 + 6*x*y - 3*y^2 + 9*x + x^3 + 3*y, y, 'factor'); |
y3 + (-3 + 3 x) y2 + 3 (x + 1)2 y + x (9 - 3 x + x2) > collect(64*x^3 + x^2*ln(y) + ln(y) + 4*x^3*ln(y)^2 - 2*x*ln(y), 'ln'); 4 x3 ln(y)2 + (x2 + 1 - 2 x) ln(y) + 64 x3 > collect(64*x^3 + x^2*ln(y) + ln(y) + 4*x^3*ln(y)^2 - 2*x*ln(y), ln, 'factor'); 4 x3 ln(y)2 + (x - 1)2 ln(y) + 64 x3 > collect(b*x*y^2 + b*x*y + c*x*y - a*x*y^2 + a*x*y, y, ['factor', 'sqrt']); [−x (a − b), −a x + b x ] y2 + [x (a + b + c), a x + b x + c x ] y > collect(b*x*y^2 + b*x*y + c*x*y - a*x*y^2 + a*x*y, y, ln@sqrt@abs@factor); ln( x (a − b) ) y2 + ln( x (a + b + c) ) y> collect(b*x*y^2 + b*x*y + c*x*y - a*x*y^2 + a*x*y, y, ln@(H^2)@sqrt@abs@factor); 2 2 ln H(( x (a − b) ) ) y2 + ln H(( x (a + + b c) ) ) y |
В частности, из трех последних примеров фрагмента следует, что в качестве четвертого аргумента collect-процедуры могут выступать более сложные конструкции, чем отдельные функции/процедуры. В частности, можно использовать @-конструкции, позволяющие обеспечивать различного рода рекурсивную обработку коэффициентов приведенного выражения, определенного первым фактическим аргументом collect-процедуры.
В данном пункте был рассмотрен ряд базовых средств, обеспечивающих важные задачи по упрощению символьных выражений. Среди них следует еще раз акцентировать ваше внимание на таких часто используемых средствах как: convert, simplify, factor, combine, collect, map, expand. При этом, следует иметь в виду, что в задачах упрощения (а в более жестком понимании и канонизации) выражений используются также и другие функции Maple-языка, имеющие иную основную направленность или более узкую ориентацию, например, на задачи полиномиальной арифметики, представленные в языке достаточно хорошо. Однако и задачу упрощения выражений следует понимать в существенно более широком смысле, как представление выражений в наиболее приемлемом для конкретных приложений виде. В следующем пункте настоящего раздела рассматриваются базовые средства, обеспечивающие символьные преобразования выражений и их алгебраическую обработку в целом.
Символьная обработка выражений. Для обеспечения работы с символьными конструкциями, в первую очередь на формальном уровне, Maple-язык располагает рядом достаточно развитых средств, из которых мы акцентируем внимание на тех, которые носят более прикладной характер; некоторые из них были рассмотрены нами выше в связи с другим контекстом. Наряду с этим для формальных преобразований используются и другие ранее рассмотренные средства Maple-языка; здесь же представлены, в основном, средства, ориентированные, в первую очередь, на такого типа обработку символьных выражений, которые позволяют осознанно использовать их уже на ранней стадии работы в среде Maple-языка. Данные средства относятся к группе средств формального манипулирования символьными выражениями.
Прежде всего, задачи символьной обработки предполагают проведение определенных видов анализа символьных выражений: определение типа выражения, определение функциональной зависимости и др. Из данных средств можно отметить наиболее важные на начальной стадии освоения средств символьной обработки. Рассмотренные ранее функции nops и op многофункциональны и с успехом могут использоваться для общего анализа внутренней структуры ряда типов объектов, тогда как по функциям typematch, type и whattype-процедуре и можно получать тип анализируемого объекта.
Для выявления факта зависимости алгебраического выражения от переменных служит логическая процедура depends(<Выражение>, <Переменные>), возвращающая true-значение, если указанные вторым аргументом ведущие переменные (отдельная, список либо множество) входят в заданное первым фактическим аргументом выражение, и false-значение в противном случае. При этом, переменная полагается ведущей, если она не связана внутренним соотношением (переменная индексная, суммирования, интегрирования, произведения и т.п.). В качестве как первого, так и второго фактических аргументов depends-процедуры могут выступать список или множество соответственно выражений и ведущих переменных. Функция возвращает true-значение, если обнаруживает указанного типа зависимость по меньшей мере для одной из пар <выражение, переменная>. Следующий фрагмент иллюстрирует применение depends-процедуры для установления факта наличия зависимости выражения от заданных переменных:
> depends([ln(x) + sin(y), ln(t + sqrt(z)), sqrt(Art(x) + Kr(z))], {x, z}); ⇒ true
> [depends(ln(x) + sin(y), {x, z}), depends(ln(t + sqrt(z)), {z, h})]; ⇒ [true, true]
> [depends(F(x)$x = a..b, x), depends(F(x)$x = a..b, {b, h})]; ⇒ [true, true]
> [depends(int(GS(y), y = a..b), y), depends(int(GS(y), y = a..b), b)]; ⇒ [false, true] > [depends(M[n]*x, n), depends(M[n]*x, x), depends(diff(H(y), y), y)]; ⇒ [true, true, true] > F:= x -> (cosh(x)^2 + sinh(x)^2)*(cos(x)^2 + sin(x)^2)/(2*cosh(x)^2 - 1):
> [depends(F(x), x), depends(simplify(F(x)), x), simplify(F(x))]; ⇒ [true, false, 1]
В случае сложных выражений depends-процедура может возвращать некорректные результаты, поэтому в подозрительных случаях следует упрощать исходное выражение посредством simplify-процедуры, как это демонстрирует последний пример фрагмента. В ряде случаев при определении для depends-процедуры в качестве ведущей связанную переменную инициируется ошибка, например в случае ранжирования:
> depends(F(x)$x = 1 .. 64, x);
Error, invalid input: depends expects its 2nd argument, x, to be of type {name, list(name), set(name)}, but received F(2)
Для тестирования произвольного V-выражения на предмет вхождения в него заданного элементарного H-подвыражения можно использовать Etest-процедуру, созданную на основе рассмотренных выше функций {op, nops} и процедуры charfcn:
Etest := proc(V::anything, H::anything, R::evaln) local k S L Z, , , ; assign(S = {op(V)}, L = { }, Z = { }); do for k to nops {( op(S)}) do `if`(nops {( op(S k[ ])}) ≠ 1, assign('L' = {op(S[k]), op(L)}), assign('Z' = {S[k], op(Z)})) end do; if L = { } then break else S := ;L L := { } end if end do; assign (' 'R = Z), [false true, ][1 + charfcn Z[ ](H)] end proc > Etest(x*cos(y) + y*(a + b*exp(x))/(ln(x) - tan(z)) - sqrt(Art + Kr)/(Sv + Ag^z), Art, R), R; true, {-1 1 2, , , cos( )y , ex, ln( )x , tan( )z , , , , , ,x y a b z Art Kr Sv Ag, , , } > Etest(x*tan(y) + y*(gamma + b*G(x))/(ln(x) - S(z)) <> sqrt(Art + Av)/(c^2 + d^2), Kr, V), V; false, {-1, 1, 2, Av, d, γ, ln(x), c, x, y, b, Art, tan(y), G(x), S(z)} |
Данная процедура возвращает true-значение в случае установления факта вхождения элементарного H-терма в качестве подвыражения в V-выражение, и false-значение в противном случае, где под элементарным будем полагать G-терм, для которого имеет место определяющее соотношение nops({op(G)}) ⇒ 1. Предыдущий фрагмент представляет исходный текст Etest-процедуры с примерами ее конкретного вызова. Процедура Etest(V, H, R) тестирует наличие факта вхождения в V-выражение элементарного H-терма и через третий фактический R-аргумент возвращает множество всех элементарных термов тестируемого V-выражения без учета их кратности. Процедура может представить определенный практический интерес и читателю рекомендуется в качестве полезного упражнения рассмотреть ее организацию.
Функция indets(W) возвращает множество, содержащее все независимые переменные алгебраического W-выражения, включая такие константы как {false, gamma, infinity, true, Pi, Catalan, FAIL}. Между тем, во многих случаях требуется найти все именно независимые переменные алгебраического W-выражения, т.е. X-переменные, удовлетворяющие определяющему соотношению type(eval(X), 'symbol'); ⇒ true. Процедура Indets [103,109] решает данную задачу. Вызов процедуры Indets(W) возвращает множество, содержащее все независимые переменные алгебраического W-выражения, удовлетворяющие вышеупомянутому условию, например:
> W:= Catalan*sin(x) + sqrt(Art^2 + Kr^2)/(AG(h, x) + VS(t) + VA(r)): map2(indets, W, 'symbol'); ⇒ {x, h, Catalan, t, Kr, Art, r} > indets(W); ⇒ {t h r x Art Kr, , , , , , sin( )x , AG(h x, ), VS( )t , VA( )r , Art2 + Kr2 }> Indets(W); ⇒ {x, h, t, Kr, Art, r} |
В отличие от предыдущей процедуры вызов процедуры indetval(A) [42,103] возвращает множество всех возможных неопределенных символов произвольного Maple-выражения А, базируясь на его операндах всех уровней. В случае кодирования в качестве второго необязательного аргумента t допустимого Maple-типа вызов процедуры indetval(A, t) возвращает операнды А-выражения, имебщие t-тип. Приведенные ниже примеры хорошо иллюстрируют сказанное: