Prolog 如何解决CLP中的背包问题(B)
我想知道是否有办法解决中电(B)的背包问题。 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=
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)