2016-02-25 117 views
3

我有一個解決方案,它非常快速變慢的問題。速度問題與代碼

下面的代碼確定是否「規則」的陣列是有效的 - 和例子可以是

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). 

UPDATE

因此,在切換到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的狀態更改爲批准狀態是我接受第一個請求並批准它,並因此從具有重疊請求的一天的所有ruleGroup中刪除userId,因爲該用戶不再能夠滿足當天的規則。

我有很大的麻煩看到我如何更新這些域從用戶中刪除用戶。

問題是我一直在研究列表而不是域,並且圍繞它們有很多邏輯我也必須改變。

+0

我可能必須注意到,我不在乎這些規則是如何有效的,我只需要一個真/假的結果。 –

回答

4

查看CLP(FD)約束條件。許多Prolog系統,包括SICStus Prolog和SWI,都帶有一個稱爲all_distinct/1的強大約束:它是真的iff來自給定列表的所有變量都可以指定爲不同整數。

例如,讓我們在陳述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)約束來檢測不一致的代碼,這通常比天真的方法更有效。我把這個翻譯作爲一個簡單的練習來實施。

+1

我一直在玩弄這些建議,也許我錯過了一些東西,但它似乎要求該領域必須是一個明確定義的數字行,即1,2,3。我的例子沒有說明這一點,但一個現實的列表可能是[1,6,102] –

+1

使用CLP(FD),你可以聲明這個域爲'1 \/6 \/102'。 – mat

+1

我已經使用CLPFD重寫了我的應用程序,現在它閃電般快!謝謝! –