我遇到了一个解决方案的问题,这个问题很快就会变慢。
下面的代码确定“规则”数组是否有效 - 例如可以是
rules_valid([rule(2,[1,2,3]), rule(2,[1,2,3])],[])
这应该是假的,因为无法从列表中选择4(2 + 2)个不同的数字,并且
rules_valid([rule(2,[1,2,3]), rule(2,[3,4,5])],[])
因此是真的。
对于非常小的查询,这样做很好,但速度很慢。如果可能的话,任何人都可以指出如何加速这段代码。
rules_valid([], _).
rules_valid( [ rule(RequiredUserNumber, UserIds) | RemainingRules ], UsedUserIds) :-
n_users_from_rule(RequiredUserNumber, UserIds, UsedUserIds, UpdatedUsedUserIds),
rules_valid(RemainingRules, UpdatedUsedUserIds).
n_users_from_rule(0, _, UsedUserIds, UsedUserIds).
n_users_from_rule(RequiredUserNumber, UserIds, UsedUserIds, UpdatedUsedUserIds) :-
0 < RequiredUserNumber,
UpdatedRequiredUserNumber is RequiredUserNumber - 1,
select(UserId, UserIds, UpdatedUserIds),
not(member(UserId, UsedUserIds)),
n_users_from_rule(UpdatedRequiredUserNumber, UpdatedUserIds, [ UserId | UsedUserIds ] , UpdatedUsedUserIds ).
更新
因此,为这条逻辑切换到CLPFD会使该部分更快。但是,我似乎无法理解如何使我的应用程序的其余部分使用CLPFD,因此它将适用于整个应用程序。
我有一个userRequests列表:
userRequest(UserId, PrioritizedRequestList)
request(State, PeriodList)
period(FromDay, ToDay)
i.e.
userRequest( 1 , [request(State,[period(1,5)]),request(State,[period(1,2),period(1,5)])] )
然后我有一个规则组列表,这是我的问题包含在
中的结构ruleGroup(Day, [rules])
所以我所做的是将userRequest的状态更改为已批准是我接受第一个请求并批准它,从而从所有与请求重叠的规则组中删除userId,因为该用户不再能够那天完成规则。
我很难看到如何更新这些域名,从中删除用户。
问题在于我一直在研究列表而不是域名,并且围绕它们有很多逻辑我也必须改变。
答案 0 :(得分:4)
检查CLP(FD)约束。许多Prolog系统,包括SICStus Prolog和SWI,都附带一个名为all_distinct/1
的强大约束:确实 iff 来自给定列表的所有变量都可以分配 distinct 整数。
例如,让我们根据CLP(FD)声明您的第一个查询:
?- length(Ls, 4), Ls ins 1..3, all_distinct(Ls). false.
由此,我们发现没有可接受的解决方案。
在第二种情况下,我们得到:
?- length(Ls, 4), Ls ins 1..5, all_distinct(Ls). Ls = [_G3409, _G3412, _G3415, _G3418], _G3409 in 1..5, all_distinct([_G3409, _G3412, _G3415, _G3418]), _G3412 in 1..5, _G3415 in 1..5, _G3418 in 1..5.
,即一个在声明上等同于原始查询的剩余程序,在这个特定情况下我们知道确实有一个解决方案。 (注意:这是可行的,因为all_distinct/1
实现了域一致性。)
因此,在规则验证中,您可以编写使用CLP(FD)约束来检测不一致的代码,这通常比天真的方法更有效。我将实现这个翻译作为一个简单的练习。