Prolog 如何解决CLP中的背包问题(B)

Prolog 如何解决CLP中的背包问题(B),prolog,Prolog,我想知道是否有办法解决中电(B)的背包问题。 CLP(B)似乎是合适的,因为包装物品可以建模为布尔变量 示例: x1,x2,x3,x4,x5 e{0,1} x1*12+x2*2+x3*1+x4*1+x5*4=

我想知道是否有办法解决中电(B)的背包问题。 CLP(B)似乎是合适的,因为包装物品可以建模为布尔变量

示例:
x1,x2,x3,x4,x5 e{0,1}
x1*12+x2*2+x3*1+x4*1+x5*4=<15
最大化x1*4+x2*2+x3*2+x4*1+x5*10

我有点不知所措,不知道如何表述背包容量有限的附带条件。SWI Prolog似乎加权了_max/3,这将允许进行优化


图片来源

您可以通过发布新变量来说明重量,然后使用
约束来模拟背包的容量,最后使用
加权_最大值/2
来最大化目标:

:- use_module(library(clpb)).

knapsack_sample([X1,X2,X3,X4,X5], Maximum):-
  knapsack([X1-12/4,X2-2/2,X3-1/2,X4-1/1,X5-4/10], 15, Maximum).

% Data is a list of BucketVar-Value/Weight
knapsack(Data, Capacity, Maximum):-
  buckets(Data, [], [], Buckets, AndEqAll, Weights, Xs),
  sat(card([0-Capacity], Buckets)),
  sat(AndEqAll),
  weighted_maximum(Weights, Xs, Maximum).

buckets([], [EqAll|LEqAll], LBuckets, Buckets, AndEqAll, [], []):-
  foldl(andall, LEqAll, EqAll, AndEqAll),
  append(LBuckets, Buckets).
buckets([X-Count/Weight|Counts], LEqAll, LBuckets, Buckets, AndEqAll, [Weight|Weights], [X|Xs]):-
  length([B|Bs], Count),
  foldl(eqall(X), Bs, (X=:=B), EqAll),
  buckets(Counts, [EqAll|LEqAll], [[B|Bs]|LBuckets], Buckets, AndEqAll, Weights, Xs).

eqall(B, X, Y, (B=:=X)*Y).

andall(X, Y, X*Y).
因此,在您的示例中,您可以使用
Data=[X1-12/4、X2-2/2、X3-1/2、X4-1/1、X5-4/10]
15
作为容量调用背包:

?- knapsack([X1-12/4,X2-2/2,X3-1/2,X4-1/1,X5-4/10], 15, Maximum).
X1 = 0,
X2 = X3, X3 = X4, X4 = X5, X5 = 1,
Maximum = 15.

更新:

实际上,
card
约束可以很好地处理重复,因此无需添加新变量,解决方案变得更简单:

knapsack2(Data, Capacity, Maximum):-
  maplist(knap, Data, LBuckets, Weights, Xs),
  append(LBuckets, Buckets),
  sat(card([0-Capacity], Buckets)),
  weighted_maximum(Weights, Xs, Maximum).

knap(X-Value/Weight, Ws, Weight, X):-
  length(Ws, Value),
  maplist(=(X), Ws).
样本运行:

?- knapsack2([X1-12/4,X2-2/2,X3-1/2,X4-1/1,X5-4/10], 15, Maximum).
X1 = 0,
X2 = X3, X3 = X4, X4 = X5, X5 = 1,
Maximum = 15.

我最近在CLP(B)中添加了一个约束伪/4,类似于CLP(FD)中的约束标量乘积/4,它不会创建电路,而是以更传统的方式维护约束。代码如下:

knapsack([X1,X2,X3,X4,X5], M) :-
   pseudo([12,2,1,1,4], [X1,X2,X3,X4,X5], =<, 15),
   weighted_maximum([4,2,2,1,10], [X1,X2,X3,X4,X5], M).
我做了一些测试,也测量了模型的建立时间。新的pseudo/4约束似乎是本例的赢家。以下是我的系统中的结果:

Jekejeke Prolog 3, Runtime Library 1.3.8 (May 23, 2019)

?- time((between(1,100,_), knapsack(_,_), fail; true)).
% Up 95 ms, GC 3 ms, Thread Cpu 93 ms (Current 07/05/19 20:03:05)
Yes

?- time((between(1,100,_), knapsack3(_,_), fail; true)).
% Up 229 ms, GC 5 ms, Thread Cpu 219 ms (Current 07/05/19 20:02:58)
Yes
以下是SWI Prolog中的结果:

?- time((between(1,100,_), knapsack3(_,_), fail; true)).
% 8,229,000 inferences, 0.656 CPU in 0.656 seconds (100% CPU, 12539429 Lips)

pseudo/4
在SWI Prolog CLP(B)中可用吗?不,我在上一个版本1.3.8中添加到Jekejeke Prolog CLP(B)中。CLP(B)的Prolog代码是开源的,模块“clpb”和模块“tree”,另请参见其使用verify_attributes/2钩子实现。钩子里没有回溯。SWI Prolog没有这样的钩子,但我想您也可以使用attr\u unify\u hook/2钩子来实现它。另见
?- time((between(1,100,_), knapsack3(_,_), fail; true)).
% 8,229,000 inferences, 0.656 CPU in 0.656 seconds (100% CPU, 12539429 Lips)