2016-07-23 2 views
11

J'ai un prédicat qui trouve la bonne solution, mais continue à trouver des solutions qui ne sont pas correctes.Supprimer les solutions incorrectes suivantes sans une seule fois

?- data(D),data_threshold_nonredundantbumps(D,5,Bs),write(D). 
[3,6,7,8,2,4,5,6,9,4,7,3] 
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...], 
Bs = [bump([11], [7]), bump([8, 9], [6, 9]), bump([2, 3, 4], [6, 7, 8])] ; 
[3,6,7,8,2,4,5,6,9,4,7,3] 
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...], 
Bs = [bump([8, 9], [6, 9]), bump([2, 3, 4], [6, 7, 8])] ; 
[3,6,7,8,2,4,5,6,9,4,7,3] 
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...], 
Bs = [bump([8], [6]), bump([2, 3, 4], [6, 7, 8])] ; 
[3,6,7,8,2,4,5,6,9,4,7,3] 
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...], 
Bs = [bump([9], [9]), bump([2, 3, 4], [6, 7, 8])] ; 
[3,6,7,8,2,4,5,6,9,4,7,3] 
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...], 
Bs = [bump([11], [7]), bump([2, 3, 4], [6, 7, 8])] ; 
[3,6,7,8,2,4,5,6,9,4,7,3] 
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...], 
Bs = [bump([2, 3, 4], [6, 7, 8])] ; 

etc

L'idée est qu'il trouvera toutes les bosses non redondants dans les données, où une bosse est une sous-liste consécutive de data qui est au-dessus threshold, retour d'un ordre (par la taille) liste des bump/2s où le premier argument de bump/2 est une liste d'indices à partir de données et le second argument est la liste de valeurs. Donc bump([2, 3, 4], [6, 7, 8]) signifie que dans les indices de données 2,3 et 4 sont supérieurs à 5, ils sont 6,7,8. Comment ajouter des conditions pour que ces solutions supplémentaires ne soient pas trouvées?

-Sans utiliser once/1.

Si mon code peut être simplifié d'une autre manière, veuillez me le faire savoir. Cela semble un peu compliqué pour ce qu'il essaie de faire.

Alors:

Voici mon code:

:-use_module(library(clpfd)). 

fd_length(L, N) :- 
N #>= 0, 
fd_length(L, N, 0). 

fd_length([], N, N0) :- 
N #= N0. 
fd_length([_|L], N, N0) :- 
N1 is N0+1, 
N #>= N1, 
fd_length(L, N, N1). 

equidistant_stride([],_). 
equidistant_stride([Z|Zs],D) :- 
foldl(equidistant_stride_(D),Zs,Z,_). 

equidistant_stride_(D,Z1,Z0,Z1) :- 
Z1 #= Z0+D. 

consecutive_ascending_integers(Zs) :- 
equidistant_stride(Zs,1). 

consecutive_ascending_integers_from(Zs,Z0) :- 
Zs = [Z0|_], 
consecutive_ascending_integers(Zs). 

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

if_(C_1,Then_0,Else_0) --> 
{ call(C_1,Truth) }, 
{ functor(Truth,_,0) }, % safety check 
( { Truth == true } -> phrase(Then_0) 
; { Truth == false }, phrase(Else_0) 
). 

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


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

tinclude(P_2,Xs,Zs) :- 
list_tinclude_list(Xs,P_2,Zs). 

list_tinclude_list([], _P_2,[]). 
list_tinclude_list([i_v(E0,E1)|Es],P_2,Fs0) :- 
if_(call(P_2,E1), Fs0 = [i_v(E0,E1)|Fs], Fs0 = Fs), 
list_tinclude_list(Es,P_2,Fs). 


tfilter(P_2,As,Bs) :- 
tinclude(P_2,As,Bs). 

%% ===================================================================== 
%% ===================================================================== 

data([5,6,7,8,3,2,6,7]). 

list_index_element(L,I,E):- 
nth1(I,L,E). 

filter(Threshold,DataPairs,FilterdPairs):- 
tfilter(#<(Threshold),DataPairs,FilterdPairs). 

i_v_pair(I,V,i_v(I,V)). 

data_indices_indicespairs(D,Is,Pairs):- 
same_length(D,Is), 
consecutive_ascending_integers_from(Is,1), 
maplist(i_v_pair,Is,D,Pairs). 

list_ascending(List,MinLength,MaxLength):- 
Max in MinLength..MaxLength, 
labeling([max(Max)],[Max]), 
fd_length(List,Max), 
consecutive_ascending_integers(List). 

region_minlength_maxlength(Region,MinLength,MaxLength,All):- 
list_ascending(Region,MinLength,MaxLength), 
append(_Before,End,All), 
append(Region,_End2,End). 

data_threshold_bumpvalues_bumplocation(Data,Threshold,Bumpvalues,Bumplocation):- 
length(Data,MaxBump), 
data_indices_indicespairs(Data,_Is,Pairs), 
filter(Threshold,Pairs,FilteredPairs), 
maplist(i_v_pair,FilteredIndices,_FilteredValues,FilteredPairs), 
%Test =test(FilteredIndexes,FilteredValues), 
dif(Bumplocation,[]), 
region_minlength_maxlength(Bumplocation,0,MaxBump,FilteredIndices), 
maplist(list_index_element(Data), Bumplocation,Bumpvalues). 


list_first_last([H|T],H,L):- 
last(T,L). 

listoflists_firsts_lasts(Listoflists,Firsts,Lasts):- 
maplist(list_first_last,Listoflists,Firsts,Lasts). 

%start is not between location1 and location2 
start_location1_location2(Start,Location1,Location2) :- 
#\( Location1 #=< Start, 
Start #=< Location2). 

bumplocation_notsublist_of_any_acs(Bumplocation,Acs):- 
listoflists_firsts_lasts(Acs,Firsts,Lasts), 
%the start of bumplocation can not be between the start of any Acs 
Bumplocation =[Bumpstart|_], 
maplist(start_location1_location2(Bumpstart),Firsts,Lasts). 


loc_val_bump(Location,Value,bump(Location,Value)). 

data_bumplocations_bumpvalues(Data,Bumplocations,Bumpvalues):- 
maplist(list_index_element(Data),Bumplocations,Bumpvalues). 

%this works but finds extra solutins so needs to be refined. 
data_threshold_nonredundantbumps(Data,Threshold,Bumps):- 
data_threshold_nonredundantbumps_ac(Data,Threshold,Nonredundantbumpslocations,[]), 
maplist(data_bumplocations_bumpvalues(Data),Nonredundantbumpslocations,Nonredundantbumps), 
maplist(loc_val_bump,Nonredundantbumpslocations,Nonredundantbumps,Bumps). 

data_threshold_nonredundantbumps_ac(Data,Threshold,Nonredundantbumps,Ac0):- 
bumplocation_notsublist_of_any_acs(Bumplocation,Ac0), 
data_threshold_bumpvalues_bumplocation(Data,Threshold,_Bumpvalues,Bumplocation), 
append([Bumplocation],Ac0,Ac1), 
data_threshold_nonredundantbumps_ac(Data,Threshold,Nonredundantbumps,Ac1). 

data_threshold_nonredundantbumps_ac(_Data,_Threshold,Ac0,Ac0). 

Répondre

7

Mon impression est que vous Overthinking ce peu. Il existe une formulation directe pour qui exécute des nombres qui dépassent le seuil, ce qui peut être défini en considérant les éléments du premier au dernier dans une seule traversée de la liste. En particulier, nous faisons pas besoin de append/3 pour ce faire.

Il faut toujours considérer l'utilisation notation DCG () lors de la description listes en Prolog. Dans ce cas, il faut un moment de réflexion pour décider comment mieux appliquer   DCG, parce que nous décrivons deux listes:

  • listes de séries (éléments successifs dépassant le seuil)
  • au sein exécute, les listes de indices et les valeurs.

Cependant, à l'exception de quelques trucs et extensions, un DCG essentiellement que nous permet de décrire une seule liste , pas de listes séparées en même temps. Donc, nous avons ce mécanisme puissant et probablement très approprié à notre disposition, et nous devons choisir pour quel type de liste nous voulons l'appliquer principalement. Dans ce qui suit, je montre une solution qui utilise un DCG pour décrire une liste de termes bump/1, c'est-à-dire que je "dédie" le mécanisme pour décrire le premier type de liste mentionné ci-dessus, et utilise un autre DCG pour décrire le deuxième type de liste, que j'appelle via phrase/2 à partir de la première   DCG.

data_threshold_bumps(Ds, T, Bs) :- 
     phrase(bumps(Ds, 1, T), Bs). 

bumps([], _, _) --> []. 
bumps([D|Ds0], I0, T) --> 
     { D #> T, 
      phrase(bump(D, T, Ds0, Ds, I0, I), Bs) }, 
     [bump(Bs)], 
     bumps(Ds, I, T). 
bumps([D|Ds0], I0, T) --> 
     { D #=< T, 
      I #= I0 + 1 }, 
     bumps(Ds0, I, T). 


bump(D, T, Ds0, Ds, I0, I) --> [I0-D], 
     { I1 #= I0 + 1 }, 
     run(Ds0, Ds, T, I1, I). 

run([], [], _, I, I) --> []. 
run([D|Ds0], Ds, T, I0, I) --> [I0-D], 
     { D #> T, 
      I1 #= I0 + 1 }, 
     run(Ds0, Ds, T, I1, I). 
run([D|Ds0], [D|Ds0], T, I, I) --> 
     { D #=< T }. 

Exemple requête et réponse:

 
?- data_threshold_bumps([3,6,7,8,2,4,5,6,9,4,7,3], 5, Bs). 
Bs = [bump([2-6, 3-7, 4-8]), bump([8-6, 9-9]), bump([11-7])] ; 
false. 

Notez que ce n'est pas tout à fait exactement la même représentation des données que vous avez besoin, mais il est trivial de le convertir à cette   un.

Voici quelques idées pour améliorer cette solution, de plus facile à plus difficile:

  • Débarrassez-vous de points de choix inutiles, en utilisant if_/3.
  • Est-il vraiment logique d'utiliser la notation DCG pour bumps//3 et run//5 dans le code ci-dessus? Quels sont les avantages et les inconvénients de l'utilisation des DCG ici par rapport aux prédicats réguliers? Jouer avec différentes vues du problème: Pouvez-vous tourner la vue DCG? Par exemple, qu'en est-il de décrire les données réelles avec un DCG, au lieu des bosses?
  • Repérez les origines des solutions non désirées dans le code que vous avez publié.

Soit dit en passant, à negate une contrainte (réifiable) CLP (FD), vous devez utiliser (#/\)/2 pour désigner une conjonction. Il ne fonctionne pas avec (,)/2.

+2

Vous voulez probablement dire '(',')/2' – false

+2

Merci pour la solution soignée. Mes solutions indésirables sont-elles liées à l'utilisation de l'adjonction? Essayer de penser à vos idées :) – user27815

+2

Même sans avoir examiné les détails de votre code, je dirais que «append/3» est certainement parmi les * principaux suspects * de générer plus de réponses que nous voulons dans ce cas. Notez que l'utilisation fréquente de 'append/3' indique presque toujours un problème avec vos structures de données: vous devez soit réécrire votre algorithme pour pouvoir toujours raisonner sur la tête de vos listes (exemple:' Ls = [First, Second | Rest ] '), ou utilisez des DCG pour décrire les listes plus efficacement. – mat

2

dans le code suivant, vous trouverez un certain nombre de sections entre crochets par

:- if(false). 
... 
:- endif. 

toutes ces sections obtiennent le même résultat

?- data_threshold_bumps([3,6,7,8,2,4,5,6,9,4,7,3], 5, Bs). 
Bs = [bump([11], [7]), bump([8, 9], [6, 9]), bump([2, 3, 4], [6, 7, 8])] ; 
false. 

Le code lui-même, il est juste une application de correspondance de motif , et, du dernier au premier, montrer un moyen possible de refactoriser le même prédicat de base bump/5 pour obtenir une meilleure lisibilité (mais, pour être vrai, mon préféré c'est le dernier ...)

data_threshold_bumps(Es, T, Sorted) :- 
    bumps(Es, 1, T, Bs), 
    predsort(by_len, Bs, Sorted). 

bumps([], _, _, []). 
bumps([E|Es], P, T, Bs) :- 
    succ(P, Q), 
    bumps(Es, Q, T, Cs), 
    bump(E, P, T, Cs, Bs). 

by_len(<, bump(Xs,_), bump(Ys,_)) :- 
    length(Xs, Xl), 
    length(Ys, Yl), Xl < Yl. 
by_len(>, _, _). 

:- use_module(library(clpfd)). 

bump(E, _, T, Bs, Bs) :- E #=< T. 
bump(E, P, T, Cs, Bs) :- E #> T, elem_placed(E, P, Cs, Bs). 

elem_placed(E, P, [], [bump([P], [E])]). 
elem_placed(E, P, [X|Bs], [Y|Bs]) :- 
    X = bump([Q|Ps], [F|Es]), 
    P #= Q-1, 
    Y = bump([P,Q|Ps], [E,F|Es]). 
elem_placed(E, P, [X|Bs], [bump([P],[E]), X|Bs]) :- 
    X = bump([Q|_Ps], _Es), 
    P #\= Q-1. 

:- if(false). 

bump(E, _, T, Bs, Bs) :- E =< T. 
bump(E, P, T, Cs, Bs) :- E > T, elem_placed(E, P, Cs, Bs). 

% first stored: tail 
elem_placed(E, P, [], [bump([P], [E])]). 
% extend current 
elem_placed(E, P, [X|Bs], [Y|Bs]) :- 
    X = bump([Q|Ps], [F|Es]), 
    succ(P, Q), 
    Y = bump([P,Q|Ps], [E,F|Es]). 
% place new 
elem_placed(E, P, [X|Bs], [bump([P],[E]), X|Bs]) :- 
    X = bump([Q|_Ps], _Es), 
    \+ succ(P, Q). 

:- endif. 

:- if(false). 

bump(E, _, T, Bs, Bs) :- E =< T. 
bump(E, P, T, Cs, Bs) :- E > T, enabled(E, P, Cs, Bs). 

enabled(E, P, [], [bump([P], [E])]). 
enabled(E, P, [bump([Q|Ps], [F|Es])|Bs], [bump([P,Q|Ps], [E,F|Es])|Bs]) :- succ(P, Q). 
enabled(E, P, [bump([Q|Ps], [F|Es])|Bs], [bump([P],[E]), bump([Q|Ps],[F|Es])|Bs]) :- \+ succ(P, Q). 

:- endif. 

:- if(false). 

bump(E, _, T, Bs, Bs) :- E =< T. 
bump(E, P, T, [], [bump([P], [E])]) :- E > T. 
bump(E, P, T, [bump([Q|Ps], [F|Es])|Bs], [bump([P,Q|Ps], [E,F|Es])|Bs]) :- E > T, succ(P, Q). 
bump(E, P, T, [bump([Q|Ps], [F|Es])|Bs], [bump([P],[E]), bump([Q|Ps],[F|Es])|Bs]) :- E > T, \+ succ(P, Q). 

:- endif. 
+1

Utilisation intelligente de directives de compilation conditionnelles. –