代码速度问题

时间:2016-02-25 18:10:48

标签: prolog clpfd

我遇到了一个解决方案的问题,这个问题很快就会变慢。

下面的代码确定“规则”数组是否有效 - 例如可以是

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,因为该用户不再能够那天完成规则。

我很难看到如何更新这些域名,从中删除用户。

问题在于我一直在研究列表而不是域名,并且围绕它们有很多逻辑我也必须改变。

1 个答案:

答案 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)约束来检测不一致的代码,这通常比天真的方法更有效。我将实现这个翻译作为一个简单的练习。