Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 在Prolog中对列表进行分区_List_Prolog_Sum_Subset Sum_Clpfd_Meta Predicate - Fatal编程技术网

List 在Prolog中对列表进行分区

List 在Prolog中对列表进行分区,list,prolog,sum,subset-sum,clpfd,meta-predicate,List,Prolog,Sum,Subset Sum,Clpfd,Meta Predicate,我试图创建一个Prolog谓词,在这里,给定一个列表,可以看到该列表是否可以拆分为两个总和相同的列表 我有一个工作列表和谓词,所以我在分区谓词中使用它。我首先尝试编写谓词代码,以查看列表的第一个元素是否等于列表其余部分的总和([2,1,1])。这就是我对那种情况的看法 partitionable([X|Y]) :- sum([X],SUM), sum([Y],SUM2), SUM = SUM2. 但是,我收到以下错误消息: ERROR: is/2: Arithmetic: `

我试图创建一个Prolog谓词,在这里,给定一个列表,可以看到该列表是否可以拆分为两个总和相同的列表

我有一个工作列表和谓词,所以我在分区谓词中使用它。我首先尝试编写谓词代码,以查看列表的第一个元素是否等于列表其余部分的总和([2,1,1])。这就是我对那种情况的看法

partitionable([X|Y]) :-
   sum([X],SUM),
   sum([Y],SUM2),
   SUM = SUM2.
但是,我收到以下错误消息:

ERROR: is/2: Arithmetic: `[]/0' is not a function. 

在我深入研究列表其余部分的递归之前,我希望能够完成这一部分,尽管我对这条消息的含义感到困惑,因为我还没有编写
“[]/0”函数
。非常感谢您的帮助。

我认为需要将X作为[X]传递,因为X只是元素(示例中的数字2)。 另一方面,Y本身就是一个列表,不应该放在另一个列表中。 以下是修改后的版本:

partitionable([X|Y]) :- sum([X],SUM), sum(Y,SUM2), SUM=SUM2.
sum([X|Y],SUM) :- sum(Y, SUBSUM), SUM is SUBSUM + X.
sum([X],SUM) :- X=SUM.
partitionable([2,1,1])
在我的例子中返回true

编辑: 由于未使用
is/2
这可能是
sum
谓词中的错误

另一方面:据我所知,您不需要为
partitionable
提供解决方案,而是需要您收到的错误消息。 尽管如此,以下是我对实施该计划的看法(可能会有更大的冲击力):


要将列表划分为两个不重叠的部分, 我们使用
list\u subseq\u subseq/3

list_subseq_subseq([]    ,[]    ,[]).
list_subseq_subseq([X|Xs],[X|Ys],Zs) :-
   list_subseq_subseq(Xs,Ys,Zs).
list_subseq_subseq([X|Xs],Ys,[X|Zs]) :-
   list_subseq_subseq(Xs,Ys,Zs).
对于执行整数算术,我们使用:

让我们把它放在一起!在下面的示例查询中,我们对列表进行了分区
[1,2,3,4,5,6,7]

?- Xs = [1,2,3,4,5,6,7],
   sum(Xs,#=,Total),
   Half*2 #= Total,
   list_subseq_subseq(Xs,Ys,Zs),
   sum(Ys,#=,Half),
   sum(Zs,#=,Half).
  Xs = [1,2,3,4,5,6,7], Total = 28, Half = 14, Ys = [1,2,4,7], Zs = [3,5,6]
; Xs = [1,2,3,4,5,6,7], Total = 28, Half = 14, Ys = [1,2,5,6], Zs = [3,4,7]
; Xs = [1,2,3,4,5,6,7], Total = 28, Half = 14, Ys = [1,3,4,6], Zs = [2,5,7]
; Xs = [1,2,3,4,5,6,7], Total = 28, Half = 14, Ys = [1,6,7]  , Zs = [2,3,4,5]
; Xs = [1,2,3,4,5,6,7], Total = 28, Half = 14, Ys = [2,3,4,5], Zs = [1,6,7]
; Xs = [1,2,3,4,5,6,7], Total = 28, Half = 14, Ys = [2,5,7]  , Zs = [1,3,4,6]
; Xs = [1,2,3,4,5,6,7], Total = 28, Half = 14, Ys = [3,4,7]  , Zs = [1,2,5,6]
; Xs = [1,2,3,4,5,6,7], Total = 28, Half = 14, Ys = [3,5,6]  , Zs = [1,2,4,7]
; false.

我还将为分区问题提供另一种解决方案。助手谓词有助于将列表剪切为两个列表。例如[1,2,3]可以被削减:

[1,2](左侧)和[3](右侧)或

[3] (左侧)和[1,2](右侧)

输出为:

1 ?- partition([1,2,3,4],L,R).
L = [1, 4],
R = [2, 3] ;
L = [2, 3],
R = [1, 4] ;
false.

也许我在想这个,但是

如果“划分列表”,您的意思是“将列表一分为二,保持顺序,而不是创建列表的各种排列),那么解决方案似乎不应该比下面这样的事情更复杂:

partitionable( Ns ) :-
  append( Prefix , Suffix , Ns ) ,
  compute_sum(Prefix,Sum) ,
  compute_sum(Suffix,Sum) .

compute_sum( Ns , S ) :- compute_sum(Ns,0,S) .

compute_sum( []     , S , S ) .
compute_sum( [N|Ns] , T , S ) :- T1 is N+T , compute_sum(Ns,T1,S) .
_ * true.
_ * false.
如果您想避免使用内置,您可以这样做,这在减少列表遍历的同时还具有优雅的额外好处:

partitionable( List ) :-
  sum_prefix( List , Sum , Sfx ) ,
  sum_prefix( Sfx  , Sum , []  ) .

sum_prefix( List , Sum , Suffix ) :- sum_prefix(List,0,Sum,Suffix) .

sum_prefix( Suffix   , Sum , Sum , Suffix ) .
sum_prefix( [H|List] , Acc , Sum , Suffix ) :-
  Acc1 is Acc+H ,
  sum_prefix(List,Acc1,Sum,Suffix)
  .
越来越好了

对于非确定性分区列表,我们不需要实现递归辅助谓词,就像使用正确的元谓词/谓词组合一样

在这个答案中,我们使用 “具体化通配符”谓词
(*)/2
作为传递给
tpartition/4
(*)/2
的谓词可以这样定义:

partitionable( Ns ) :-
  append( Prefix , Suffix , Ns ) ,
  compute_sum(Prefix,Sum) ,
  compute_sum(Suffix,Sum) .

compute_sum( Ns , S ) :- compute_sum(Ns,0,S) .

compute_sum( []     , S , S ) .
compute_sum( [N|Ns] , T , S ) :- T1 is N+T , compute_sum(Ns,T1,S) .
_ * true.
_ * false.
让我们将
t部分/4
(*)/2
一起使用,并使用以下约束:


我意识到我将X和Y作为列表传递到sum谓词中,而它们本应作为自身传递,因此我不再收到错误消息。但是,即使我传入partitionable([2,1,1]),谓词仍然返回false-这应该返回true。这可能是因为我的求和谓词吗?请不要在注释中详细说明您的问题,否则它会变得非常混乱。
X
是单个元素,列表的头
[X | Y]
,而
Y
是列表的尾(另一个列表)。因此
[Y]
是一个元素的列表,它本身就是一个列表。这可能不是您想要的。您还需要明确元素的顺序是否重要。例如,如果列表成功,
[1,2,1]
?列表的顺序很重要,因此列表中任何地方都只能生成一个满足求和约束的分区(因此[1,2,1]不起作用)。好的,我理解为什么我需要将X放在括号中,而将Y放在括号中。不过在更改后,请使用除可分区([2,1,1])之外的任何东西.产生一个错误:错误:is/2:算术:`[]/“0”不是一个函数。我不知道是什么导致了这种情况的发生。@red_student,你能给我举一些错误出现的例子吗?我知道这个答案对于partitionable来说不是一个正确的解决方案,但我不明白你提到的错误。你使用的是什么版本的prolog?对于
list\u subseq\u subseq,什么是不相交的([a,a],Ys,Zs)
?这可能是天生不确定的。可能是为了诊断目的。@false。我认为“不重叠的子序列”比“不相交的子序列”更适合。当我们说“分区”时“应该很清楚,
Xs
中的每一项都恰好进入
Ys
Zs
中的一项,你不这么认为吗?
_ * true.
_ * false.
?- use_module(library(clpfd)).   % use clp(FD) library
true.

?- ABs = [1,2,3,4,5,6,7],        % same data as in the earlier answer
   sum(ABs,#=,NN),
   N*2 #= NN,
   tpartition(*,ABs,As,Bs),
   sum(As,#=,N),
   sum(Bs,#=,N).
  NN = 28, N = 14, ABs = [1,2,3,4,5,6,7], As = [1,2,4,7], Bs = [3,5,6] 
; NN = 28, N = 14, ABs = [1,2,3,4,5,6,7], As = [1,2,5,6], Bs = [3,4,7]
; NN = 28, N = 14, ABs = [1,2,3,4,5,6,7], As = [1,3,4,6], Bs = [2,5,7]
; NN = 28, N = 14, ABs = [1,2,3,4,5,6,7], As = [1,6,7]  , Bs = [2,3,4,5]
; NN = 28, N = 14, ABs = [1,2,3,4,5,6,7], As = [2,3,4,5], Bs = [1,6,7]    
; NN = 28, N = 14, ABs = [1,2,3,4,5,6,7], As = [2,5,7]  , Bs = [1,3,4,6]    
; NN = 28, N = 14, ABs = [1,2,3,4,5,6,7], As = [3,4,7]  , Bs = [1,2,5,6]
; NN = 28, N = 14, ABs = [1,2,3,4,5,6,7], As = [3,5,6]  , Bs = [1,2,4,7]
; false.