Как упростить алгебраические уравнения, представленные в виде списка списка

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

алгебраическое уравнение

f = 3x+2

список списка

[[3,1],[2,0]]

3 и 2 — коэффициенты
1 и 0 — показатели степени

Это должно быть очевидно.

Я ищу несколько советов или предложений о том, как кодировать упрощения для этого примера:

f = 3x+2x+1+2
[[3,1],[2,1],[1,0],[2,0]]

упрощенный:

f = 5x+3
[[5,1],[3,0]]

Я пробовал некоторые встроенные функции, но не понял, как их использовать.


person kisaw88    schedule 29.01.2019    source источник
comment
В вашем примере есть ошибка? f=3x+2x+1+2 должно быть [[3,1],[2,1],[1,0],[2,0]] вместо [[1,3],[2,1],[1,0],[2,0]]?   -  person damianodamiano    schedule 29.01.2019
comment
да спасибо, поправил   -  person kisaw88    schedule 29.01.2019
comment
Вы тоже хотите решать системы уравнений?   -  person repeat    schedule 30.01.2019
comment
Это все о полиномиальных выражениях одной переменной?   -  person repeat    schedule 30.01.2019
comment
да, все дело только в одной переменной, я решил систему, но можно ли найти решение, манипулирующее только списками?   -  person kisaw88    schedule 02.02.2019


Ответы (3)


Один лайнер, похожий на то, что предложил joel76:

simplify(I,O) :-
    bagof([S,E],L^(bagof(C,member([C,E],I),L),sum_list(L,S)),O).

Внутренний bagof собирает C (коэффициенты), заданные E (показатели степени), результирующий список L суммируется в S, а в паре с E становится [S,E], элементом (мономом) O. Если вы опускаете спецификатор универсального количественного определения (то есть L^) вы получаете одиночные мономы при возврате.

person CapelliC    schedule 30.01.2019
comment
Я использовал предварительную сортировку для получения Out = [[5, 1], [3, 0]] ; вы получаете Out = [[3, 0], [5, 1]] . Не знаю, важно ли это! - person joel76; 30.01.2019
comment
Порядок мономов должен быть неважен, я думаю. Агрегат BTW основан на setof и т. д., поэтому порядок уже подразумевается. - person CapelliC; 30.01.2019

Вы можете решить свою проблему следующим образом:

simplify(_,_,S,S,[]):- !.
simplify(L,I,Sum,NTot,[[I,S]|T]):-
    Sum =< NTot,
    findall(X,member([X,I],L),LO),
    length(LO,N),
    S1 is Sum + N,
    sum_list(LO,S),
    I1 is I+1,
    simplify(L,I1,S1,NTot,T).           

write_function([]).
write_function([[D,V]|T]):-
    write(' + '),write(V),write('x^'),write(D),
    write_function(T).

test:-
    L = [[3,1],[2,1],[1,0],[2,0]],
    length(L,N),
    simplify(L,0,0,N,LO), 
    LO = [[D,V]|T],
    write('f='),write(V),write('x^'),write(D),
    write_function(T).

Основным предикатом является simplify/5, который использует findall/3 для поиска всех коэффициентов с одинаковой степенью, а затем суммирует их, используя sum_list/2. Затем вы можете написать результат причудливым образом, используя write_function/1.

person damianodamiano    schedule 29.01.2019
comment
большое спасибо, но не могли бы вы предложить мне решение, использующее только манипулирование списком? - person kisaw88; 02.02.2019

В SWI-Prolog вы можете использовать агрегат:

pred(>, [_,X], [_,Y]) :- X > Y.
pred(<, [_,X], [_,Y]) :- X < Y.
pred(=, [_,X], [_,X]).

simplify(In, Out) :-
    aggregate(set([S,X]), aggregate(sum(P), member([P,X], In), S), Temp),
    predsort(pred, Temp, Out).

Например :

?- simplify([[3,1],[2,1],[1,0],[2,0]], Out).
Out = [[5, 1], [3, 0]] ;
false.
person joel76    schedule 29.01.2019
comment
большое спасибо, но не могли бы вы предложить мне решение, использующее только манипулирование списком? - person kisaw88; 02.02.2019