2016-07-23 33 views
11

Ich habe ein Prädikat, das die richtige Lösung findet, aber dann geht es weiter, um Lösungen zu finden, die nicht richtig sind.Entfernen Sie falsche nachfolgende Lösungen ohne einmal

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

Die Idee ist, dass sie alle nicht redundanten Beulen in den Daten zu finden, wo eine Beule ein konsekutiver sublist von data ist, die über threshold ist, Return eine geordnete (nach Größe) Liste bump/2s, wobei das erste Argument von bump/2 eine Liste von Indizes aus Daten und das zweite arg die Liste von Werten ist. So bedeutet bump([2, 3, 4], [6, 7, 8]), dass in Datenindizes 2,3 und 4 über 5 sind, sind sie 6,7,8.

Wie füge ich Bedingungen hinzu, damit diese zusätzlichen Lösungen nicht gefunden werden? -ohne Verwendung once/1.

Wenn mein Code auf andere Arten optimiert werden könnte, lassen Sie es mich bitte wissen. Es scheint ein wenig kompliziert für das, was es versucht zu tun.

So:

Hier ist mein 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). 

Antwort

7

Mein Eindruck ist, dass Sie diese leicht sind Grübeln. Es gibt eine direkte Formulierung für läuft von Zahlen, die den Schwellenwert überschreiten, die definiert werden können, indem die Elemente von Anfang bis Ende in einem einzigen Durchlauf der Liste berücksichtigt werden. Insbesondere tun wir nicht brauchen append/3, dies zu tun.

betrachten immer DCG Notation () bei der Beschreibung Listen in Prolog verwenden. In diesem Fall dauert es einen Moment der Reflexion, zu entscheiden, wie man am besten   DCGs bewerben, weil wir beschreiben zwei Listen:

  • Listen verläuft (aufeinanderfolgende Elemente Überschreiten der Schwelle)
  • innerhalb Läufe, Listen von Indizes und Werte.

jedoch ein paar Tricks und Erweiterungen mit Ausnahme von einem DCG im Wesentlichen läßt uns nur eine einzelne Liste beschreiben, nicht getrennte Listen zur gleichen Zeit. Wir haben also diesen leistungsfähigen und wahrscheinlich sehr geeigneten Mechanismus zur Verfügung und müssen wählen, für welche Art von Liste wir ihn anwenden wollen in erster Linie.

Im Folgenden mir eine Lösung zeigen, die einen DCG verwendet eine Liste von Bump/1 zu beschreiben, das heißt, I „widmen“, um den Mechanismus, um die erste Art von Listen oben erwähnt, zu beschreiben, und einer anderen verwenden DCG, um die zweite Art der Liste zu beschreiben, die ich über phrase/2 aus der ersten   DCG aufrufen.

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

Beispiel Abfrage und Antwort:

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

Beachten Sie, dass dies nicht ganz genau die gleiche Datendarstellung, die Sie benötigen, aber es ist trivial es zu diesem   ein zu konvertieren.

Hier sind ein paar Ideen auf diese Lösung zu verbessern, von leichter zu schwerer:

  • Sie sich von unnötigen Wahl-Punkte zu befreien, if_/3 verwenden.
  • Macht es tatsächlich Sinn, DCG-Notation für bumps//3 und run//5 im obigen Code zu verwenden? Was sind die Vorteile und Nachteile der Verwendung von DCGs hier gegenüber regulären Prädikaten?
  • Spielen Sie mit verschiedenen Ansichten des Problems: Können Sie die DCG-Ansicht umdrehen? Zum Beispiel, was ist mit der Beschreibung der tatsächlichen Daten mit einem DCG, anstelle der Unebenheiten?
  • Verfolgen Sie die Herkunft (en) unerwünschter Lösungen in dem von Ihnen geposteten Code.

By the way, zu negate a (reifiable) CLP (FD) Einschränkung, müssen Sie (#/\)/2 verwenden, um eine Verbindung zu bezeichnen. Es tut nicht arbeiten mit (,)/2.

+2

Vermutlich meinst du '(',')/2' – false

+2

Danke für die saubere Lösung. Sind meine unerwünschten Lösungen mit meiner Verwendung von append zu tun? Versuche, über deine Ideen nachzudenken :) – user27815

+2

Auch ohne in die Details deines Codes geschaut zu haben, würde ich sagen, dass "append/3" definitiv zu den * Hauptverdächtigen * gehört, mehr Antworten zu generieren als wir in diesem Fall wollen. Beachten Sie, dass häufige Verwendung von 'append/3' fast immer ein Problem mit Ihren Datenstrukturen anzeigt: Sie sollten Ihren Algorithmus entweder neu schreiben, so dass Sie immer über den Kopf Ihrer Listen nachdenken können (Beispiel:' Ls = [First, Second | Rest ] '), oder verwenden Sie DCGs, um Listen effizienter zu beschreiben. – mat

2

im folgenden Code, werden Sie eine Reihe von Abschnitten von

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

alle diese Abschnitte erhalten das gleiche Ergebnis

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

Der Code selbst, es ist nur eine Anwendung von Pattern-Matching klammert finden und, vom letzten zum ersten, zeigen einen möglichen Weg, um das gleiche grundlegende Beule/5 Prädikat umzuformen, um bessere Lesbarkeit zu bekommen (aber, um wahr zu sein, mein bevorzugtes ist es das letzte ...)

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

Clevere Verwendung von Anweisungen zur bedingten Kompilierung. –