2017-09-27 2 views
3

Ich versuche, einige reine Prädikate aus früheren Stapelüberlauffragen zu kombinieren, um mein eigenes Prädikat zu erstellen.Kombinieren von reinen Prädikaten

Ich möchte eine Liste von cs geben (die zugeordnete Fakten haben -'ats 'mit ihnen) und einen' Merkmal'-Begriff, der einen Operator und einen Schwellenwert für ein 'at' hat. Ich möchte die Listen von cs partitionieren, wenn das c nicht das entsprechende "at" von dem "Feature" hat, wird es in die falsche Partition gehen, sonst wird der Operator das "at" für das "c" testen und die c ist angemessen.

Zum Beispiel:

?-cpgpartition_ts_fs_feature([c1,c2,c3],Ts,Fs,feature(at2,_,>=,10)). 

Sollte ergeben:

Ts = [c3], %c3 has an at2 >= 10 
Fs = [c1,c2]. %c1 has at2 <10 and c2 does not have an at2 

Dies ist der Code, den ich habe:

:-use_module(library(clpfd)). 

cpgpartition_ts_fs_feature([],[],[],_). 
cpgpartition_ts_fs_feature([X|Xs0],Ts,Fs,Feature):- 
    Feature = feature(At,_,Op,FValue), 
    cpg_ats_i(X,AtList), 
    atom_concat(#,Op,Op2), %make clpfd operator 
    Test =..[Op2,AtValue3,FValue], 
    if_(memberd_t(attribute(At,AtValue3),AtList), 
     (
     if_(call(Test), (Ts=[X|Ts0],Fs=Fs0), 
     ( Ts =Ts0,Fs=[X|Fs0])) 
     ) 
     ,Fs=[X|Fs0]), 
    cpgpartition_ts_fs_feature(Xs0,Ts0,Fs0,Feature). 

if_(If_1, Then_0, Else_0) :- 
    call(If_1, T), 
    ( T == true -> call(Then_0) 
    ; T == false -> call(Else_0) 
    ; nonvar(T) -> throw(error(type_error(boolean,T),_)) 
    ; /* var(T) */ throw(error(instantiation_error,_)) 
    ). 

bool01_t(1,true). 
bool01_t(0,false). 

=(X, Y, T) :- 
    ( X == Y -> T = true 
    ; X \= Y -> T = false 
    ; T = true, X = Y 
    ; T = false, 
     dif(X, Y)        % ISO extension 
     % throw(error(instantiation_error,_)) % ISO strict 
    ). 

#=<(X,Y,Truth) :- X #=< Y #<==> B, bool01_t(B,Truth). 

#<(X,Y,Truth) :- X #< Y #<==> B, bool01_t(B,Truth). 

#>(X,Y,Truth) :- X #> Y #<==> B, bool01_t(B,Truth). 

#>=(X,Y,Truth) :- X #>= Y #<==> B, bool01_t(B,Truth). 

list_memberd_t([] ,_,false). 
list_memberd_t([Y|Ys],X,Truth) :- 
    if_(X=Y, Truth=true, list_memberd_t(Ys,X,Truth)). 

list_memberd_truth(Xs,X,Truth) :- list_memberd_t(Xs,X,Truth). 

memberd_t(X,Xs,Truth) :- list_memberd_t(Xs,X,Truth). 

value_intvalue(attribute(_A,X),attribute(_A,Y)):- 
     AtValue2 is X *100, %Convert decimal number to integer. 
     Y is integer(AtValue2). 

cpg_ats_i(C,AtList):- 
     cpg_ats(C,Ats), 
     maplist(value_intvalue,Ats,AtList). 

cpg_ats(c1,[attribute(at1,0.5),attribute(at2,0.03)]). 
cpg_ats(c2,[attribute(at1,0.02)]). 
cpg_ats(c3,[attribute(at2,0.1),attribute(at3,0.04),attribute(at4,0.08)]). 

Wenn die Testabfrage versucht, erhalte ich:

cpgpartition_ts_fs_feature([c1,c2,c3],Ts,Fs,feature(at2,_,>=,10)). 
Fs = [c1, c2] ; 
Fs = [c1, c2, c3] ; 
Fs = [c1, c2] ; 
Fs = [c1, c2, c3]. 

Und interessanterweise ändern sich die Ergebnisse, wenn die Reihenfolge der CLIST unterschiedlich ist.

?- cpgpartition_ts_fs_feature([c3,c1,c2],Ts,Fs,feature(at2,_,>=,10)). 
Ts = [c3|_12950], 
Fs = [c1, c2] ; 
Ts = [c3|_12950], 
Fs = [c1, c2] ; 
Fs = [c3, c1, c2] ; 
Fs = [c3, c1, c2]. 

Ich denke, das liegt daran, dass die folgende Abfrage liefert Ergebnisse mit dif/2 Zwängen, die für unangemessen erscheinen, was ich zu tun versuchen, nur ich die konkreten Lösungen wollen.

?- cpg_ats_i(C,Ats), if_(memberd_t(attribute(at2,AtValue),Ats),Q=true,Q=false). 
C = c1, 
Ats = [attribute(at1, 50), attribute(at2, 3)], 
AtValue = 3, 
Q = true ; 
C = c1, 
Ats = [attribute(at1, 50), attribute(at2, 3)], 
Q = false, 
dif(AtValue, 3) ; 
C = c2, 
Ats = [attribute(at1, 2)], 
Q = false ; 
C = c3, 
Ats = [attribute(at2, 10), attribute(at3, 4), attribute(at4, 8)], 
AtValue = 10, 
Q = true ; 
C = c3, 
Ats = [attribute(at2, 10), attribute(at3, 4), attribute(at4, 8)], 
Q = false, 
dif(AtValue, 10). 

Auch ist das Ziel für diesen Code auf einer großen Menge von Daten ausgeführt werden, die Liste der c Hunderttausende in der Länge und jeder c könnte 50k von ats haben sein, wie ich die Speicheranforderungen arbeiten können ? und ist ein anderer Ansatz mit unreinen Prädikaten, die wahrscheinlich weniger Speicher benötigen?

+1

Auf den ersten Blick ersetzen "Test = .. [Op2, AtValue3, FValue], ..., Aufruf (Test)" durch 'Aufruf (Op2, AtValue3, FValue)' – false

+0

Fertig. Aber es scheint keinen Unterschied zu machen ... – user27815

Antwort

4

Wie Sie das Problem erwähnt in der dif (X, Y) Linie in der Definition von:

=(X, Y, T) :- 
    ( X == Y -> T = true 
    ; X \= Y -> T = false 
    ; T = true, X = Y 
    ; T = false, 
     dif(X, Y)        % ISO extension 
     % throw(error(instantiation_error,_)) % ISO strict 
    ). 

, die da ist, wenn Sie versuchen:

memberd_t(attribute(at2,X),[attribute(at1,0.5),attribute(at2,0.03)],T). 
X = 0.03, 
T = true ; 
T = false, 
dif(X, 0.03). 

hier die Wahl Punkt das gibt die Lösung: T = false,dif(X, 0.03). führt den Teil Fs=[X|Fs0] des auszuführen:

if_(memberd_t(attribute(At,AtValue3),AtList), 
     (
     if_(call(Test), (Ts=[X|Ts0],Fs=Fs0), 
     ( Ts =Ts0,Fs=[X|Fs0])) 
     ) 
     ,Fs=[X|Fs0]), 

auch Dies ist nicht die richtige Antwort, da, wenn Sie Attribut (at2,0.03) in Atlist haben, erwarten X = 0.03, T = true, die den Then_0 Teil von if_/3 auslösen wird (und keine andere Lösung mit T = falsch, die zu anderen Wahlpunkten führt Else_0 führen Teil).

So könnte man die T = false,dif(X, Y) von =/3 entfernen und nun wollen wir versuchen:

?- cpgpartition_ts_fs_feature([c1,c2,c3],Ts,Fs,feature(at2,_,>=,10)). 
Fs = [c1, c2]. 

gut, aber wo ist Ts ??

So gibt es einen weiteren Fehler:

Die oben sagt, dass es für Fs = [c1,c2] und für alle Ts erfolgreich ist. Das ist, weil die Ausführung Else_0 Teil von if_/3, die die Fs Liste erfüllt, die Sie nicht beschränken Ts Liste einfach als Ts verlassen und später cpgpartition_ts_fs_feature(Xs0,Ts0,Fs0,Feature) mit einer anderen Ts0 Liste unabhängig von Ts aufrufen. So fügen:

if_(memberd_t(attribute(At,AtValue3),AtList), 
     (
     if_(call(Test), (Ts=[X|Ts0],Fs=Fs0), (Ts =Ts0,Fs=[X|Fs0])) 
     ) 
     ,(Fs=[X|Fs0], Ts = Ts0)), 
        ^^^^^^^^ 
        here added 

Schließlich ich wie empfohlen von @False es besser ist, Test =..[Op2,AtValue3,FValue], ..., call(Test) zu ersetzen durch call(Op2,AtValue3,FValue) seit call/N Teil der ISO ist und es passt in das ursprüngliche Typ-System Mycroft O'Keefe.

wir jetzt wieder versuchen:

?- cpgpartition_ts_fs_feature([c1,c2,c3],Ts,Fs,feature(at2,_,>=,10)). 
Ts = [c3], 
Fs = [c1, c2]. 

scheint richtig und deterministisch :) !!.

Was den Speicherteil Ihrer Frage betrifft, bin ich nicht so sicher, aber bevorzuge deterministische Prädikate, die keine Auswahlpunkte für die Speichereffizienz hinterlassen. Wenn Sie reine Vergleichselemente verwenden, werden Sie relationaler programmieren und ein besseres Verhalten haben, aber ich bin mir nicht sicher, ob if_/3 so speichereffizient ist, da es viele Aufrufe enthält, aber ich bin mir nicht sicher, ob jemand anders diesen Teil deutlicher beantworten könnte.

+0

Großartiger Ort! Danke :) – user27815

+0

@ user27815, froh, zu helfen !!! – coder

1

Dank der Antwort von Coder kam ich mit:

cpgpartition_ts_fs_feature([],[],[],_). 
cpgpartition_ts_fs_feature([X|Xs0],Ts,Fs,feature(At,_,Op,FValue)):- 
    cpg_ats_i(X,AtList), 
    atom_concat(#,Op,Op2), %make clpfd operator 
    maplist(atterm_atname,AtList,Ats), 
    if_(memberd_t(At,Ats), 
     (
     memberchk(attribute(At,AtValue3),AtList), 
     if_(call(Op2,AtValue3,FValue), (Ts=[X|Ts0],Fs=Fs0), 
     ( Ts =Ts0,Fs=[X|Fs0])) 
    ), 
     (Fs=[X|Fs0],Ts=Ts0) 
    ), 
    cpgpartition_ts_fs_feature(Xs0,Ts0,Fs0,feature(At,_,Op,FValue)). 


atterm_atname(attribute(At,_),At). 

Welche mir erlaubt das gleiche Ergebnis zu erhalten, ohne die Definition von =/3 zu ändern.

Verwandte Themen