2017-09-27 2 views
3

J'essaie de combiner des prédicats purs à partir de questions précédentes de débordement de pile pour créer mon propre prédicat. Je veux donner une liste de c (qui ont des faits associés -'ats 'avec eux) et un terme' feature 'qui a un opérateur et un seuil pour un' at '. Je veux partitionner les listes de c, si le c ne possède pas le 'at' correspondant à partir de la 'feature' il ira dans la fausse partition, sinon l'opérateur testera le 'at' pour ce 'c' et divise le c est approprié.Combinaison de prédicats purs

Par exemple:

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

devrait se traduire par:

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

C'est le code que j'ai:

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

Lorsque vous essayez la requête de test je reçois:

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

Et il est intéressant que les résultats changent si l'ordre du clist est différent.

?- 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]. 

Je pense que cela est parce que les requête suivante renvoie les résultats avec dif/2 contraintes qui semblent inappropriées pour ce que je suis en train de faire, je veux que les solutions concrètes.

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

De plus, le but est de ce code à exécuter sur un grand ensemble de données, la liste des c sera des centaines de milliers de longueur et chaque c pourrait avoir 50k de ats, comment puis-je travailler sur les besoins en mémoire ? et est une approche différente utilisant des prédicats impurs susceptibles de prendre moins de mémoire?

+1

À première vue, remplacer 'Test = .. [Op2, AtValue3, FValue], ..., appel (Test)' par 'appel (Op2, AtValue3, FValue)' – false

+0

Terminé. Mais cela ne semble pas faire la différence ... – user27815

Répondre

4

Comme vous l'avez mentionné le problème est dans la dif (X, Y) ligne dans la définition de:

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

qui est parce que si vous essayez:

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

Ici, le point de choix qui donne la solution: T = false,dif(X, 0.03). conduira à exécuter la partie Fs=[X|Fs0] du:

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

également ce n'est pas la bonne réponse puisque si vous avez l'attribut (at2,0.03) dans le Atlist vous attendez memberd_t pour retourner X = 0.03, T = true qui déclenchera la partie Then_0 de if_/3 (et aucune autre solution avec T = false qui mènera à d'autres points de choix exécutant Else_0 partie).

Vous pouvez supprimer le T = false,dif(X, Y) de =/3 et maintenant nous allons essayer:

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

bon, mais où est Ts ??

Donc il y a un autre bug:

Le dit ci-dessus qu'il réussit à Fs = [c1,c2] et pour tous les Ts. C'est parce que l'exécution Else_0 partie de if_/3 qui remplit la liste Fs vous ne limite pas Ts liste juste laisser comme Ts et plus tard appeler cpgpartition_ts_fs_feature(Xs0,Ts0,Fs0,Feature) avec une autre liste Ts0 indépendante de Ts. Alors ajouter:

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 

Enfin, je tel que recommandé par @false il est mieux remplacer Test =..[Op2,AtValue3,FValue], ..., call(Test) par call(Op2,AtValue3,FValue) depuis call/N fait partie de l'ISO et il se glisse dans le système de type Mycroft O'Keefe d'origine.

Maintenant, nous allons essayer à nouveau:

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

Semble droite et déterministe :) !!. En ce qui concerne la partie mémoire de votre question, je ne suis pas sûr, mais je préfère les prédicats déterministes qui ne laissent pas de choix pour l'efficacité de la mémoire. Utiliser des prédicats purs vous permettra de programmer plus de relations et aura un meilleur comportement mais je ne suis pas sûr si if_/3 est si efficace en mémoire car il contient beaucoup d'appels mais je ne suis pas sûr que quelqu'un d'autre pourrait répondre plus clairement à cette partie.

+0

Great spot! Merci :) – user27815

+0

@ user27815, heureux d'aider !!! – coder

1

Merci à la réponse de Coder je suis venu avec:

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

Ce qui m'a permis d'obtenir le même résultat sans changer la définition de =/3.