%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% AGOSTINO DOVIER
%%% August 29, 2012
%%% Tested in BProlog
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:-set_prolog_flag(compiling,debugcode).

repairing(Labels,Errors) :-
   findall(X,node(X),Nodes),
   length(Nodes,N),
   length(Labels,N),
   length(Errors,N),
   %%%
   set_domains(Labels,-1,1),
   set_domains(Errors,-1,1),
   %%
   initial_assignment(Nodes,Labels,Errors),
   %%
   constraint(Nodes,Labels,Errors),
   sum(Errors,#=,E),
   append(Labels,Errors,VARS),
   labeling([maximize(E)],VARS),
   B is (N-E)//2,
   format("~d repairs are needed~n",[B]).
   
set_domains([],_,_).
set_domains([L|Labels],A,B) :-
    L in [A,B],  %%%% L in {A,B},
    set_domains(Labels,A,B).   
      
initial_assignment([],[],[]).
initial_assignment([N|Nodes],[L|Labels],[E|Errors]) :-
    ((   input(N),  partial(N,A)) -> (L=A,E=1); %%% Input nodes have fixed values. No errors.
     (\+ input(N),  partial(N,A)) -> (L=A); %%% Non input and assigned nodes can change
     (\+ partial(N,A)) -> (E=1) ), %%% we have still to assing them, don't need to assign them wrongly
     initial_assignment(Nodes,Labels,Errors).

constraint(Nodes,Labels,Errors) :-
    constraint(Nodes,Labels,Errors,Nodes,Labels).

constraint([],_,_,_,_).
constraint([N|Odes],[_|Abels],[_|Rrors],Nodes,Labels) :-
       input(N),!, 
       constraint(Odes,Abels,Rrors,Nodes,Labels).

%%% Non input nodes (main case)
constraint([N|Odes],[L|Abels], [E|Rrors], Nodes,Labels) :-
       %%% Find the incoming edges A1 S1, ..., Ak Sk
       findall([A,Sign],edge(A,N,Sign),EdgeList),    
       product_list(EdgeList, Nodes,Labels,PLIST), 
       Prod in [-1,1],
       Prod #= L*E,
       element(_,PLIST,Prod),
       constraint(Odes, Abels, Rrors, Nodes,Labels).

product_list([],_,_,[]).
product_list([[A,Sign]|EdgeList],Nodes,Labels,[P|LIST]) :-
       nth1(I,Nodes,A),nth1(I,Labels,LA), 
       P #= Sign*LA,
       product_list(EdgeList,Nodes,Labels,LIST).
           
printlab([])    :- nl.
printlab([ 1|L]) :- print(' 1 ||'),printlab(L).
printlab([-1|L]) :- print('-1 ||'),printlab(L).
    
% Graph (Veber example)
%%% Launch commenting and decommenting last line

input(1).    input(3).

%
node(1).    node(2).    node(3).   node(4).
node(5).    node(6).    node(7).   node(8).

%
edge(1,2,1).
edge(2,3,1).
edge(3,8,-1).
edge(4,1,-1).
edge(4,2,1).
edge(5,2,-1).
edge(5,3,1).
edge(5,7,1).
edge(6,4,-1).
edge(6,5,-1).
edge(7,6,-1).
edge(8,5,1).
edge(8,4,1).
%
partial(1,1).
partial(3,1).
%
partial(2,1).
partial(4,1).
partial(5,1).
partial(6,1).
partial(7,1).
%partial(8,1).

