【问题标题】:Using Prolog to compute the GCD of a polynomial使用 Prolog 计算多项式的 GCD
【发布时间】:2016-09-26 20:13:56
【问题描述】:

标题说明了一切。我正在寻找计算两个多项式的 GCD。有什么方法可以在 Prolog 中完成吗?如果是这样,什么是一个好的起点?具体来说,我在如何使用 Prolog 实现多项式除法方面遇到了麻烦。

编辑以包含示例输入和输出:

示例输入:

?-  GCD(x^2 + 7x + 6, x2 − 5x − 6, X).

示例输出:

X = x + 1.

解决方案

万一其他人需要这样做,这是我的最终解决方案:

tail([_|Tail], Tail).
head([Head | _], Head).

norm(Old, N, New) :- 
    length(Tail, N),
    append(New, Tail, Old).
norm(Old, N, []) :-
    length(Old, L),
    N > L.

mult_GCD(List, GCD) :- length(List, L),
    L > 2, tail(List, Tail),
    mult_GCD(Tail, GCD).
mult_GCD([H | T], GCD) :-
    length(T, L),
    L == 1, head(T, N),
    gcd(H, N, GCD).

lead(List, List) :-
    length(List, L),
    L == 1.
lead([0 | Tail], Out) :- 
    !, lead(Tail, Out).
lead([Head | Tail], [Head | Tail]) :- Head =\= 0.

poly_deg([], 0).
poly_deg(F, D) :-
    lead(F, O),
    length(O, N),
    D is N - 1.

poly_red([0], [0]).
poly_red(Poly, Out) :-
    mult_GCD(Poly, GCD),
    scal_div(Poly, GCD, Out).

poly_sub(Poly,[],Poly) :- Poly = [_|_].
poly_sub([],Poly,Poly).
poly_sub([P1_head|P1_rest], [P2_head|P2_rest], [PSub_head|PSub_rest]) :-
    PSub_head is P1_head-P2_head,
    poly_sub(P1_rest, P2_rest, PSub_rest).

scal_prod([],_Sc,[]).
scal_prod([Poly_head|Poly_rest], Sc, [Prod_head|Prod_rest]) :-
    Prod_head is Poly_head*Sc,
    scal_prod(Poly_rest, Sc, Prod_rest).

scal_div([],_,[]).
scal_div([Poly_head|Poly_rest], Sc, [Prod_head|Prod_rest]) :-
    Prod_head is Poly_head / Sc,
    scal_div(Poly_rest, Sc, Prod_rest).

poly_div(Num, Den, OutBuild, Out) :-
    poly_deg(Num, X),
    poly_deg(Den, Y),
    X < Y,
    Out = OutBuild.
poly_div(INum, IDen, OutBuild, Out) :-
    lead(INum, [NumHead | NumTail]), lead(IDen, [DenHead | DenTail]),
    Q is NumHead / DenHead,
    append(OutBuild, [Q], Out1),
    append([DenHead], DenTail, DenNorm), append([NumHead], NumTail, Num),
    scal_prod(DenNorm, Q, DenXQ),
    poly_sub(Num, DenXQ, N),
    poly_div(N, IDen, Out1, Out).

poly_mod(Num, Den, Out) :-
    poly_deg(Num, X), poly_deg(Den, Y),
    X < Y,
    lead(Num, Out1),
    poly_red(Out1, Out2),
    lead(Out2, Out).
poly_mod(INum, IDen, Out) :-
    lead(INum, [NumHead | NumTail]), lead(IDen, [DenHead | DenTail]),
    Q is NumHead / DenHead,
    append([DenHead], DenTail, DenNorm), append([NumHead], NumTail, Num),
    scal_prod(DenNorm, Q, DenXQ),
    poly_sub(Num, DenXQ, N),
    poly_mod(N, IDen, Out).

poly_gcd(X, Y, X):- poly_deg(Y, O), O == 0, !.
poly_gcd(Y, X, X):- poly_deg(Y, O), O == 0, !.
poly_gcd(X, Y, D):- poly_deg(X, Xd), poly_deg(Y, Yd), Xd > Yd, !, poly_mod(X, Y, Z), poly_gcd(Y, Z, D).
poly_gcd(X, Y, D):- poly_mod(Y, X, Z), poly_gcd(X, Z, D).

gcd(X, Y, Z) :-
    X < 0, X > Y, !,
    X1 is X - Y,
    gcd(-X, Y, Z).
gcd(X, Y, Z) :-
    Y < 0, Y >= X, !,
    Y1 is Y - X,
    gcd(X, -Y, Z).
gcd(X, 0, X).
gcd(0, Y, Y).
gcd(X, Y, Z) :-
    X > Y, Y > 0,
    X1 is X - Y,
    gcd(Y, X1, Z).
gcd(X, Y, Z) :-
    X =< Y, X > 0,
    Y1 is Y - X,
    gcd(X, Y1, Z).
gcd(X, Y, Z) :-
    X > Y, Y < 0,
    X1 is X + Y,
    gcd(Y, X1, Z).
gcd(X, Y, Z) :-
    X =< Y, X < 0,
    Y1 is Y + X,
    gcd(X, Y1, Z).

【问题讨论】:

  • 是的,它应该能够处理任何指数。这完全有可能在 Prolog 中不太可能,我只是希望真正擅长 Prolog 的人告诉我。
  • Prolog 是一种通用编程语言。如果你可以用电脑来做,你应该可以用 Prolog 来做。首先,尝试搜索并查找您的问题是否尚未解决。然后,如果没有,请找到一个满足您需要的算法,并尝试在 Prolog 中实现它。如果你遇到了你自己无法解决的问题,展示你的代码,解释问题,解释你自己无法解决的问题。我不打算投票结束这个问题,但它现在已经成熟了。
  • 我的问题是我真的不知道如何开始。我有一个为整数计算 GCD 的版本,但我不知道从哪里开始多项式除法。这不是我第一次来这里,我知道在问之前先搜索一下,据我所知,网上确实没有关于这个话题的任何内容。
  • 好吧,关于多项式 gcd 的维基百科页面有用于对多项式进行欧几里德除法的伪代码,并展示了如何使用它来查找多项式的 gcd。你试过阅读这篇文章吗?
  • 是的,我已经阅读了这篇文章。不幸的是,它似乎假设多项式除法,这正是我遇到的麻烦。同样,我的问题是我不知道如何开始,如果我写了一些代码,我会发布它,但事实上,我什至想不出办法来解决这个问题。跨度>

标签: prolog polynomial-math greatest-common-divisor


【解决方案1】:

这个答案意味着朝着正确的方向前进。

首先,暂时忘记您需要解析像x^2 + 7x + 6 这样的表达式;这在 Prolog 中甚至还不是一个合适的术语。如果你试图在顶层写它,你会得到一个错误:

?- Expr = x^2 + 7x + 6.
ERROR: Syntax error: Operator expected
ERROR: Expr = x^2 + 
ERROR: ** here **
ERROR: 7x + 6 . 

Prolog 不知道如何处理您那里的7x。解析表达式本身就是一个问题,如果您假设您已经解析了它并获得了一个看起来像这样的表示,也许会更容易:

[6, 7, 1]

同样,x^2 − 5x − 6 变为:

[-6, -5, 1]

要表示 0,您将使用空列表:

[]

现在,看看algorithm at the Wikipedia page。它使用deg 作为度数,使用lc 作为主要系数。使用上面的列表表示,您可以将它们定义为:

度数比保存系数的列表的长度小一。

poly_deg(F, D) :-
    length(F, N),
    D is N - 1.

前导系数是列表的最后一个元素。

poly_lc(F, C) :-
    last(F, C).

您还需要能够使用多项式进行简单的算术运算。使用Wikipedia page 上的定义,我们看到例如添加[][1] 应该得到[1],将[-2, 2] 乘以[1, -3, 1] 应该得到[-2, 8, -8, 2]precursory search 给了我this question here on Stackoverflow。使用那里定义的谓词:

?- poly_prod([-2,2], [1, -3, 1], P).
P = [-2.0, 8.0, -8.0, 2] .

?- poly_sum([], [1], S).
S = [1].

从这里开始,您应该可以尝试实现我在上面链接的 Wiki 文章中概述的多项式除法。如果您遇到更多麻烦,您应该编辑您的问题或提出一个新问题。

【讨论】:

  • 现在我觉得有点傻。如果我尝试用任何其他语言来实现它,我可能会想到使用列表,但不知何故,这对我来说从未发生过。这正是我想要的,谢谢!
  • @bendl 我很高兴这对你有帮助:) 祝你好运
  • 一条评论:在您的代码中 poly_deg(F, D) :- length(P, N), D is N - 1. 应该是 poly_deg(F, D) :- length(F, N ), D 是 N - 1。除非我弄错了。
  • @bendl 是的,这是一个错字,很好发现
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-22
  • 2016-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多