Prolog CLPFD约束:是一个素数

Prolog CLPFD约束:是一个素数,prolog,primes,swi-prolog,clpfd,Prolog,Primes,Swi Prolog,Clpfd,我甚至不确定这是否可行,但我正在尝试编写一个谓词prime/1,它将其参数限制为质数 我的问题是,我没有找到任何表达“将该约束应用于小于变量整数的所有整数”的方法 以下是一个无效的尝试: prime(N) :- N #> 1 #/\ % Has to be strictly greater than 1 ( N #= 2 % Can be 2 #\/

我甚至不确定这是否可行,但我正在尝试编写一个谓词
prime/1
,它将其参数限制为质数

我的问题是,我没有找到任何表达“将该约束应用于小于变量整数的所有整数”的方法

以下是一个无效的尝试:

prime(N) :-
    N #> 1 #/\                       % Has to be strictly greater than 1
    (
        N #= 2                       % Can be 2
        #\/                          % Or
        (
            N #> 2 #/\               % A number strictly greater than 2
            N mod 2 #= 1 #/\         % which is odd
            K #< N #/\
            K #> 1 #/\
            (#\ (
                N mod K #= 0         % A non working attempt at expressing:
                                         “there is no 1 < K < N such that K divides N”
            ))
        )
    ).
基本上,这与
2\/{大于2}
的奇数整数一致

编辑 表示一个数不是素数非常容易:

composite(N) :-
    I #>= J,
    J #> 1,
    N #= I*J.
基本上:“
N
是复合的,如果它可以用
I>=J>1
写成
I*J

我仍然无法“否定”这些限制。我尝试过使用类似于
#==>
(暗示)的东西,但这似乎一点也不简单
N#=I*J#=>J#=1
将适用于复合数字,即使
12=I*J
并不意味着一定
J=1

prime/1
这花了我相当长的时间,我相信这远不是很有效,但这似乎有效,所以这里什么都没有:

我们为约束
prime/1
创建一个自定义约束传播器(如下所示):

:- use_module(library(clpfd)).
:- multifile clpfd:run_propagator/2.

prime(N) :-
    clpfd:make_propagator(prime(N), Prop),
    clpfd:init_propagator(N, Prop),
    clpfd:trigger_once(Prop).

clpfd:run_propagator(prime(N), MState) :-
    (
        nonvar(N) -> clpfd:kill(MState), prime_decomposition(N, [_])
        ;
        clpfd:fd_get(N, ND, NL, NU, NPs),
        clpfd:cis_max(NL, n(2), NNL),
        clpfd:update_bounds(N, ND, NPs, NL, NU, NNL, NU)
    ).
如果
N
是一个变量,我们将其下限约束为
2
,如果它大于
2
,则保留其原始下限

如果
N
是ground
,那么我们使用这个
prime\u分解/2
谓词检查
N
是prime:

prime_decomposition(2, [2]).
prime_decomposition(N, Z) :-
    N #> 0,
    indomain(N),
    SN is ceiling(sqrt(N)),
    prime_decomposition_1(N, SN, 2, [], Z).

prime_decomposition_1(1, _, _, L, L) :- !.
prime_decomposition_1(N, SN, D, L, LF) :-
    (   
        0 #= N mod D -> !, false
        ;
        D1 #= D+1,
        (    
            D1 #> SN ->
            LF = [N |L]
            ;
            prime_decomposition_2(N, SN, D1, L, LF)
        )
    ).

prime_decomposition_2(1, _, _, L, L) :- !.
prime_decomposition_2(N, SN, D, L, LF) :-
    (   
        0 #= N mod D -> !, false
        ;
        D1 #= D+2,
        (    
            D1 #> SN ->
            LF = [N |L]
            ;
            prime_decomposition_2(N, SN, D1, L, LF)
        )
    ).
显然,您可以用任何确定性素数检查算法来替换该谓词。这是对素因子分解算法的改进,该算法被修改为一旦找到一个因子就失败

一些疑问 当我们应该知道
8
16
是不可能的,因为它们是偶数


我曾尝试在传播器中添加其他约束,但它们似乎比任何其他约束都要慢,因此我不确定我是否做错了什么,或者更新约束是否比在标记时检查素数慢。

剩余的约束没有显示在顶层。使用
call_residence_vars/2
查看它们:
?-call_residence_vars((X#<100,prime(X),indomain(X)),Vs.
@mat所以从我看到的情况来看,我得到了我预期的问题,即它只检查至少有一个整数不除以
N
,当我希望它检查
2
N-1
之间的所有整数时。我不知道该怎么做。@Fatalize,你只想用clpfd吗?因为我认为你可以写一份更容易给出素数的预告书…@coder是的。我不想反复尝试整数,直到我找到正确的一个是进一步的表达式,我想有一个被约束为素数的变量。正如我所说,我甚至不知道这是否可能超出我的答案(这只是说数字必须在这组素数中)@coder当然不,因为我不想
prime
返回
2,3,
我希望它约束
X
(以及在标记时“return”
2,3,
)。否则,这就像在(1100000,I)之间使用
,152399025是I*I
(24k个推论),而不是
X*X#=152399025
(584个推论)。很好的解决方案,+1!根据经验,我建议不要进行域大小最坏情况下的线性传播(在本例中:域内修剪),因为这意味着指数时间传播。其他注释:一些
/0
是不必要的!使用
zcompare/3
比if-then-else更好(更通用)。事实上,这些构造在您的案例中都不是必需的,因为您可以编写
0\\=N mod D
!重要的一点是:
ceiling(sqrt(N))
对于较大的整数将溢出。出于这些原因,我建议避免使用
(is)/2
。使用约束代替!这就是说,至少要保持边界的一致性,这意味着至少要确保边界与约束一致。在您给出的示例中,这将首先消除16,在重新触发时消除8,因此在这个具体的情况下,甚至只有素元素仍然存在。由于素数之间存在任意大的间隔,因此在这种情况下实现这一点会导致最坏情况下的指数行为。约束的一个关键优势,即使核心关系有效,同时将困难部分放在标签中,将因此消失。。。
prime_decomposition(2, [2]).
prime_decomposition(N, Z) :-
    N #> 0,
    indomain(N),
    SN is ceiling(sqrt(N)),
    prime_decomposition_1(N, SN, 2, [], Z).

prime_decomposition_1(1, _, _, L, L) :- !.
prime_decomposition_1(N, SN, D, L, LF) :-
    (   
        0 #= N mod D -> !, false
        ;
        D1 #= D+1,
        (    
            D1 #> SN ->
            LF = [N |L]
            ;
            prime_decomposition_2(N, SN, D1, L, LF)
        )
    ).

prime_decomposition_2(1, _, _, L, L) :- !.
prime_decomposition_2(N, SN, D, L, LF) :-
    (   
        0 #= N mod D -> !, false
        ;
        D1 #= D+2,
        (    
            D1 #> SN ->
            LF = [N |L]
            ;
            prime_decomposition_2(N, SN, D1, L, LF)
        )
    ).
?- prime(X).
X in 2..sup,
prime(X).


?- X in -100..100, prime(X).
X in 2..100,
prime(X).


?- X in -100..0, prime(X). 
false.


?- X in 100..200, prime(X).
X in 100..200,
prime(X).


?- X #< 20, prime(X), indomain(X).
X = 2 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 11 ;
X = 13 ;
X = 17 ;
X = 19.

?- prime(X), prime(Y), [X, Y] ins 123456789..1234567890, Y-X #= 2, indomain(Y).
X = 123457127,
Y = 123457129 ;
X = 123457289,
Y = 123457291 ;
X = 123457967,
Y = 123457969
…


?- time((X in 123456787654321..1234567876543210, prime(X), indomain(X))).
% 113,041,584 inferences, 5.070 CPU in 5.063 seconds (100% CPU, 22296027 Lips)
X = 123456787654391 .
?- prime(X), X in {2,3,8,16}.
X in 2..3\/8\/16,
prime(X).