Как добавить многочлены в Prolog?

У меня есть следующая задача:

Напишите метод, который будет добавлять два полинома. То есть 0+2*x^3 и 0+1*x^3+2*x^4 дадут 0+3*x^3+2*x^4.

Я также написал следующий код:

add_poly(+A1*x^B1+P1,+A2*x^B2+P2,+A3*x^B3+P3):-
    (
       B1=B2,
       B3 = B2,
       A3 is A1+A2,
       add_poly(P1,P2,P3)
    ;
       B1<B2,
       B3=B1,
       A3=A1,
       add_poly(P1,+A2*x^B2+P2,P3)
    ;
       B1>B2,
       B3=B2,
       A3=A2,
       add_poly(+A1*x^B1+P1,P2,P3)
    ).
add_poly(X+P1,Y+P2,Z+P3):-
    Z is X+Y,
    add_poly(P1,P2,P3).

Моя проблема в том, что я не знаю, как остановиться. Я хотел бы остановиться, когда один из аргументов равен нулю, а затем добавить второй аргумент к третьему. Но как я могу проверить, что они равны нулю? Спасибо.


person Vitali Pom    schedule 28.07.2012    source источник


Ответы (2)


Несколько замечаний:

Старайтесь избегать дизъюнкций (;)/2 в начале. Они нуждаются в специальном отступе, чтобы быть читаемыми. И они усложняют чтение одного правила, подумайте обо всех дополнительных (=)/2 целях, которые вам нужно написать и отслеживать.


Тогда я не уверен, что вы можете предположить о своих полиномах. Можете ли вы предположить, что они написаны в канонической форме?


И для вашей программы: рассмотрите заголовок вашего первого правила:

add_poly(+A1*x^B1+P1,+A2*x^B2+P2,+A3*x^B3+P3):-

Я обобщу некоторые аргументы:

add_poly(+A1*x^B1+P1,_,_):-

и некоторые подтермины:

 add_poly(+_+_,_,_):-

Это соответствует:

add_poly(+(+(_),_),_,_) :-

Не уверен, что тебе это нравится.

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

Также обратите внимание, что +-оператор левоассоциативен. Это означает, что 1+2+3+4 ассоциируется слева:

?- write_canonical(1+2+3+4).
+(+(+(1,2),3),4)

Итак, если у вас есть термин 0+3*x^3+2*x^4, первое, что вы «видите», это _+2*x^4. Термины слева вложены глубже.


Для вашего фактического вопроса (как остановиться) - вам нужно будет явно проверить, что крайний левый подтермин является целым числом, используйте integer/1 - или, возможно, термин (*)/2 (это зависит от ваших предположений).

person false    schedule 28.07.2012

Я предполагаю, что полиномы, о которых вы говорите, находятся в 1 переменной и с целыми показателями.

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

:- [library(clpfd)].

add_poly(P1, P2, Sum) :-
    normalize(P1, N1),
    normalize(P2, N2),
    append(N1, N2, Nt),
    aggregate_all(max(L), (member(M, Nt), length(M, L)), LMax),
    maplist(rpad(LMax), Nt, Nn),
    clpfd:transpose(Nn, Tn),
    maplist(sumlist, Tn, NSum),
    denormalize(NSum, Sum).

rpad(LMax, List, ListN) :-
    length(List, L),
    D is LMax - L,
    zeros(D, Z),
    append(List, Z, ListN).

% the hardest part is of course normalization: here a draft

normalize(Ts + T, [N|Ns]) :-
    normalize_fact(T, N),
    normalize(Ts, Ns).
normalize(T, [N]) :-
    normalize_fact(T, N).

% build a list with 0s left before position E
normalize_fact(T, Normal) :-
    fact_exp(T, F, E),
    zeros(E, Zeros),
    nth0(E, Normal, F, Zeros).

zeros(E, Zeros) :-
    length(Zeros, E),
    maplist(copy_term(0), Zeros).

fact_exp(F * x ^ E, F, E).
fact_exp(x ^ E, 1, E).
fact_exp(F * x, F, 1).
fact_exp(F, F, 0).

% TBD...
denormalize(NSum, NSum).

контрольная работа:

?- add_poly(0+2*x^3, 0+1*x^3+2*x^4, P).
P = [0, 0, 0, 3, 2]

ответ все еще в нормальной форме, нужно написать denormalize/2...

person CapelliC    schedule 28.07.2012
comment
Нит: лучше использовать use_module(library(clpfd)) или еще лучше use_module(library(clpfd),[]). - person false; 29.07.2012
comment
... или, может быть, даже лучше и больше раскрывает намерения: use_module(library(clpfd),[transpose/2]). - person false; 29.07.2012
comment
@false: но я получаю сообщение об ошибке, используя предложенный синтаксис: import/1: нет разрешения на импорт clpfd:transpose/2 в пользователя (уже импортированного из ugraphs), поэтому я вынужден объявить модуль... - person CapelliC; 29.07.2012
comment
Общая проблема заключается в том, что вы полностью импортировали ugraphs. Нет? Так что вы должны точно указать, что вы хотите (я знаю, что это это утомительно...). Но в конкретном случае, вероятно, лучше всего сделать то, что сделал SICStus: переименовать в transpose_ugraph/2. Если SICStus может измениться, это не должно быть слишком сложно для других систем. В идеале такие вещи должны решаться в прологе Пролога. - person false; 29.07.2012
comment
@false:теперь я изо всех сил пытаюсь понять, почему ugraph загружается (автоматически?)... у меня его нет в .plrc - person CapelliC; 29.07.2012