Prolog 使用clpfd生成闰年序列

Prolog 使用clpfd生成闰年序列,prolog,clpfd,Prolog,Clpfd,下面的代码检查给定年份是否为闰年。该算法是使用库中的声明性整数算法制定的,以便查询可以“反向”运行以生成闰年序列。代码有两种变体,改变了对一年是否为一个世纪的测试,但每种变体的行为都不同,它们都不能正常工作 我想生成从1990年到2005年的闰年序列。为此,我要输入查询yearin1990..2005,leap_year1(Year),indomain(Year)。(或者leap_year2来测试第二个变量) 我编写的代码是(使用SWI Prolog 8.0.2): 查询结果如下(SWI Pro

下面的代码检查给定年份是否为闰年。该算法是使用库中的声明性整数算法制定的,以便查询可以“反向”运行以生成闰年序列。代码有两种变体,改变了对一年是否为一个世纪的测试,但每种变体的行为都不同,它们都不能正常工作

我想生成从1990年到2005年的闰年序列。为此,我要输入查询
yearin1990..2005,leap_year1(Year),indomain(Year)。
(或者
leap_year2
来测试第二个变量)

我编写的代码是(使用SWI Prolog 8.0.2):

查询结果如下(SWI Prolog 8.0.2):

如您所见,两个查询都不能正确生成闰年的完整序列(1992、1996、2000、2004)

此外,以下1900年前后的查询也会产生异常结果(添加注释):

这种行为有什么解释吗?我应该如何修改
leap\u year()
,以便生成完整的序列

更新:(更多?)完成,但不理解原因(!)

将支票拆分几个世纪可以提高查询的完整性:

leap_year_century_fix(Year) :-
  Year mod 100 #\= 0.

leap_year_century_fix(Year) :-
  Year mod 100 #= 0,
  Year mod 400 #= 0.      % 2000 is a leap year, 1900 is not

leap_year3(Year) :-
  Year #> 0,
  Year mod 4 #= 0,
  leap_year_century_fix(Year).
现在:


简单地用表达,并对使用物化:

leap(Y) :-
    Y #> 0,
    Y mod 4 #= 0,
    (Y mod 100 #\= 0) #\/ (Y mod 400 #= 0).

不要混合使用
->
和约束。相反,对于这两种情况,直接使用析取和“卫士”。更好,用户
% Verify that 1900 is not a leap year
?- not(leap_year1(1900)), not(leap_year2(1900)).
true.

% Verify that 1892, 1896, 1904 are leap years
?- leap_year1(1892), leap_year1(1896), leap_year1(1904).
true.

?- leap_year2(1892), leap_year2(1896), leap_year2(1904).
true.

% No solutions found (!)
?- Year in 1890..1905,leap_year1(Year),indomain(Year).
false.

% Solutions found as expected (complete result)
?- Year in 1890..1905,leap_year2(Year),indomain(Year).
Year = 1892 ;
Year = 1896 ;
Year = 1904.
leap_year_century_fix(Year) :-
  Year mod 100 #\= 0.

leap_year_century_fix(Year) :-
  Year mod 100 #= 0,
  Year mod 400 #= 0.      % 2000 is a leap year, 1900 is not

leap_year3(Year) :-
  Year #> 0,
  Year mod 4 #= 0,
  leap_year_century_fix(Year).
?- Year in 1890..1905,leap_year3(Year),indomain(Year).
Year = 1892 ;
Year = 1896 ;
Year = 1904 ;
false.

?- Year in 1990..2015,leap_year3(Year),indomain(Year).
Year = 1992 ;
Year = 1996 ;
Year = 2004 ;
Year = 2008 ;
Year = 2012 ;
Year = 2000.
leap(Y) :-
    Y #> 0,
    Y mod 4 #= 0,
    (Y mod 100 #\= 0) #\/ (Y mod 400 #= 0).