/* run with ga(). reads .pl and writes output in .out Algorithm taken from Mitchell's book "Machine Learning" two valued version Two valued case: only positive abducible are printed memes version single or multiple agent case: single agent: only one agent in the list chromosomes are exchanged among those of the agent multiple agents: chromosomes are exchanged with those of another agent chose randomly parameters: memes: on or off, if on memes are taken into account p number of individuals r crossover rate: percentage of people that should be crossed over m mutation rate: percentage of people that should mutate (after cross over has been applied l lamarckian rate: percentage of people that should evolve lamarckianly (after cross over has been applied max_gen maximum number of generations accuracy set(,) to set a parameter Format of the input file: %:-dynamic %e.g. :-dynamic obs/2,conn/2,val/2,nand2_table/3,and2_table/3, not1_table/2,id1_table/2,xor2_table/3,eq2_table/3,nor2_table/3, or2_table/3,nand4_table/5,and4_table/5. %list of agents %agents(). agents([ag1,ag2,ag3,ag4]). % observations: obs(,). obs(out(inpt0, cain3), 0). ...... obs(out(or2, cout0), 1). % integrity constraint % ic(,). % e.g. ic([ obs(out(or2, cout3), 0), val(out(or2, cout3), 1)],ag1). ...... ic([ obs(out(or2, cout0), 0), val(out(or2, cout0), 1)],ag4). ic([ obs(out(or2, cout0), 1), val(out(or2, cout0), 0)],ag4). %revisables(). % specifies the list of revisables main code of the algorithm */ :- dynamic par/2. par(version,'all'). % total number of individuals for all agents par(p,40). % crossover rate: of people that should be crossed over par(r,0.6). % mutation rate: percentage of people that should mutate (after % cross over has been applied par(m,0.4). % lamarckian rate: percentage of people that should evolve lamarckianly (after % cross over has been applied par(l,0.6). % maximum number of generations par(max_gen,10). par(memes,on). % can be on or off par(fitness,hybrid). % can be % accuracy: accuracy only % hybrid: accuracy + percentage of false/2 % weighted_hybrid: weighted means of accuracy + percentage of false par(selection,probabilistic). % can be % probabilistic: select probabilistically (1-r)*p individuals % bestn: select the best (1-r)*p individuals par(new_population,ps). % can be % ps % best_n_of_p_and_ps (see paper) % not implemented yet count0([],N,N):-!. count0([0|T],Ni,No):-!, N1 is Ni+1, count0(T,N1,No). count0([_|T],Ni,No):- count0(T,Ni,No). :-op(1200,fx,[<-]). :-op(900,fx,not). :-use_module(library(random)). :-use_module(library(lists)). :-[check_ic]. ga(File):- [File], retract_old_pred, statistics(runtime,[_,_]), start_ga, statistics(runtime,[_,T]), name(File,FileStr), append(FileStr,".out",FileOutStr), name(FileOut,FileOutStr), tell(FileOut), listing(par), T1 is T /1000, format("Execution time ~f seconds~N",[T1]), last_gen(G), findall([Rev,Ag,F,_],best_global_chromosome_of_an_agent(G,Ag,Rev,F),List), find_max_fitness_in_list(List,[_,_,0,_],[Rev,Ag,MF,_]), format("Solution:~n~nGlobal Fitness: ~f~nLiterals: ~p Found in agent: ~p~n~n",[MF,Rev,Ag]), format("Local fitness of individuals~n",[]), print_fitnesses, told. print_fitnesses:- agents(AGL), print_fitnesses_for_each_agent(AGL). print_fitnesses_for_each_agent([]):-!. print_fitnesses_for_each_agent([Ag|Tail]):- format("~nAgent ~p ~nGeneration\tFitnesses~n",[Ag]), print_fitnesses_of_an_agent_for_each_generation(Ag,0), print_fitnesses_for_each_agent(Tail). print_fitnesses_of_an_agent_for_each_generation(Ag,G):- last_gen(G), format("~d\t",[G]), fitness_list(G,Ag,FitnessList), print_fitness_list(FitnessList), !. print_fitnesses_of_an_agent_for_each_generation(Ag,G):- format("~d\t",[G]), fitness_list(G,Ag,FitnessList), print_fitness_list(FitnessList), G1 is G+1, print_fitnesses_of_an_agent_for_each_generation(Ag,G1). print_fitness_list([]):-!, format("~n",[]). print_fitness_list([H|T]):- format("~f\t",[H]), print_fitness_list(T). set(Par,Value):- retract(par(Par,_OldValue)), assert(par(Par,Value)). eliminate_not([],R,R):-!. eliminate_not([not _A|T],R,R1):-!, eliminate_not(T,R,R1). eliminate_not([H|T],R,[H|R1]):-!, eliminate_not(T,R,R1). start_ga:- initialize_population, assert_fitness_data, ga_loop(0). ga_loop(X):- statistics(runtime,[_,_]), reproduction(X), return_best_hypothesis(Result1), statistics(runtime,[_,T]), T1 is T /1000, format("Execution time ~f seconds. ~N",[T1]), % eliminate_not(Result1,[],Result), format("Result: ~p ~N",[Result1]), % write('Continue ?'),read(A), % (A=y-> % par(max_gen,Z), % Y is X + Z, % ga_loop(Y) % ; % true % ), par(max_gen,M), assert(last_gen(M)). return_best_hypothesis(Result):- population(Pop,_,_,_), find_max_fitness_in_list(Pop,[_,_,0,_],[Ch,_M,_MF,_]), convert(Ch,Result). convert(Ch,Result):- revisables(L), associate(L,Ch,[],Result). % two valued case associate([],[],R,R):-!. associate([H|T],[1|GT],In,[H|Out]):- associate(T,GT,In,Out). associate([H|T],[0|GT],In,[not H|Out]):- associate(T,GT,In,Out). % three valued case %associate([],[],R,R):-!. % %associate([H|T],[1|GT],In,[H|Out]):- % associate(T,GT,In,Out). % %associate([_H|T],[0|GT],In,Out):- % associate(T,GT,In,Out). % %associate([H|T],[-1|GT],In,[not H|Out]):- % associate(T,GT,In,Out). reproduction(X):- end_condition(X),!. reproduction(X):- population(_,_,G,_), G1 is G+1, format("Generation ~p~n~n",[G1]), generate_new_population, findall([Rev,Ag,F,_],best_global_chromosome_of_an_agent(G1,Ag,Rev,F),List), find_max_fitness_in_list(List,[_,_,0,_],[Rev,Ag,MF,_]), format("Best chromosome in generation ~d:~nGlobal Fitness: ~f~nLiterals: ~p Found in agent: ~p~n~n~n",[G1,MF,Rev,Ag]), assert_fitness_data, reproduction(X). end_condition(X):- population(_,_,G,_), par(max_gen,MG), G>=MG+X. generate_new_population:- agents(AG), length(AG,NAG), generate_new_population_agents(AG,NAG). generate_new_population_agents([],_NAG):-!. generate_new_population_agents([H|T],NAG):- par(r,R), par(p,P), par(m,M), par(l,L), Ind is integer((1-R)*P/NAG), select_individuals(H,Ind,[],Pop1), Cross is integer(R*P/NAG), crossover(H,Cross,Pop1,Pop2), length(Pop2,L2), Mut is integer(M*L2), mutate(H,Mut,Pop2,Pop3), length(Pop3,L3), Lam is integer(L*L3), lamarck_op(H,Lam,Pop3,Pop4), retract(population(_,_MF,G,H)), G1 is G +1, compute_max_global_fitness(Pop4,[_,_,0,_],[ChO,MO,MFO,SO]), find_max_fitness_in_list(Pop4,[_,_,0,_],[Ch,Mask,MF,S]), convert(Ch,Rev), convert(ChO,RevO), eliminate_not(Rev,[],Rev_no_nots), eliminate_not(RevO,[],RevO_no_nots), format("Agent ~p: Best chromosome according to local fitness: Fitness=~p True literals=~p~n\c Correct:~p Accessed:~p~n\c Best chromosome according to global fitness: Fitness=~p True literals=~p~nCorrect:~p Accessed:~p~n~n", [H,MF,Rev_no_nots,S,Mask,MO,RevO_no_nots,SO,MFO]), assert(population(Pop4,MF,G1,H)), % assert the generation number, the maximum fitness, if it is a solution or not and the agent assert(best_local_chromosome_of_an_agent(G1,H,Rev_no_nots,MF)), assert(best_global_chromosome_of_an_agent(G1,H,RevO_no_nots,MFO)), generate_new_population_agents(T,NAG). % compute_max_global_fitness(Pop,[_,_,0,_],NewMax) % returns a chromosome of the form [Ch,M,MF,S] that has the maximum % fitness of the population computed considering the constraints of all % agents (overall fitness). % it computes the overall fitness for each chromosome compute_max_global_fitness([],[Ch,M,MF,S],[Ch,M,MF,S]):-!. compute_max_global_fitness([[Ch,M,_F,_S]|Rest],[ChIn,MIn,MFIn,SIn],[ChOut,MOut,MFOut,SOut]):- fitness(Ch,F,S), (MFIn > F-> Ch1=ChIn, MF1=MFIn, S1=SIn, M1=MIn ; Ch1=Ch, MF1=F, S1=S, M1=M ), compute_max_global_fitness(Rest,[Ch1,M1,MF1,S1],[ChOut,MOut,MFOut,SOut]). % find_max_fitness_in_list(Pop,[_,_,0,_],NewMax) % returns a chromosome of the form [Ch,M,MF,S] that has the maximum % local fitness in the population % it does not have to comput fitness for each chromosome because it is % already stored in the population find_max_fitness_in_list([],[Ch,M,MF,S],[Ch,M,MF,S]):-!. find_max_fitness_in_list([[Ch,M,F,S]|Rest],[ChIn,MIn,MFIn,SIn],[ChOut,MOut,MFOut,SOut]):- (MFIn > F-> Ch1=ChIn, MF1=MFIn, S1=SIn, M1=MIn ; Ch1=Ch, MF1=F, S1=S, M1=M ), find_max_fitness_in_list(Rest,[Ch1,M1,MF1,S1],[ChOut,MOut,MFOut,SOut]). select_individuals(H,Ind,[],Pop1):- par(selection,probabilistic),!, select_individuals_probabilistically(H,Ind,[],Pop1). select_individuals(H,Ind,[],Pop1):- par(selection,bestn),!, population(P,_MF,_G,H), select_individuals_certainly(Ind,P,[],Pop1). select_individuals_probabilistically(_AG,0,Pop,Pop):-!. select_individuals_probabilistically(AG,Ind,PopIn,[[Ch,M,F,S]|PopOut]):- select_single_ch(Ch,M,F,S,AG), Ind1 is Ind -1, select_individuals_probabilistically(AG,Ind1,PopIn,PopOut). select_individuals_certainly(0,_P,Pop,Pop):-!. select_individuals_certainly(Ind,P,PopIn,[[Ch,M,F,S]|PopOut]):- find_max_fitness_in_list(P,[_,_,0,_],[Ch,M,F,S]), delete(P,[Ch,M,F,S],RestP), Ind1 is Ind -1, select_individuals_certainly(Ind1,RestP,PopIn,PopOut). crossover(H,Cross,PopIn,PopOut):- agents([H]),!, %single agent case crossover_single_agent(Cross,PopIn,PopOut). crossover(H,Cross,PopIn,PopOut):- crossover_multi_agent(H,Cross,PopIn,PopOut). crossover_single_agent(Cross,Pop,Pop):-Cross=<0,!. crossover_single_agent(Cross,PopIn,[[NCh1,M1,NF1,NS1],[NCh2,M2,NF2,NS2]|PopOut]):- agents([H]), select_single_ch(Ch1,M1,_F1,_S1,H), select_single_ch(Ch2,M2,_F2,_S2,H), Cross1 is Cross -2, cross_memes(H,Ch1,M1,Ch2,M2,NCh1,NF1,NCh2,NF2,NS1,NS2), crossover_single_agent(Cross1,PopIn,PopOut). %cross(Ch1,Ch2,NCh1,NF1,NCh2,NF2,NS1,NS2):- % generate_mask(Ch1,[],Mask), % crossing(Ch1,Ch2,Mask,[],NCh1,[],NCh2), % fitness(NCh1,NF1,NS1), % fitness(NCh2,NF2,NS2). crossover_multi_agent(_AG,Cross,Pop,Pop):-Cross=<0,!. crossover_multi_agent(AG,Cross,PopIn,[[NCh1,M1,NF1,NS1]|PopOut]):- select_single_ch(Ch1,M1,_F1,_S1,AG), agents(AGL), delete(AGL,AG,RAGL), length(RAGL,NRAG), random(0,NRAG,R), nth0(R,RAGL,AG2), select_single_ch(Ch2,M2,_F2,_S2,AG2), Cross1 is Cross -1, cross_memes(AG,Ch1,M1,Ch2,M2,NCh1,NF1,_NCh2,_NF2,NS1,_NS2), crossover_multi_agent(AG,Cross1,PopIn,PopOut). cross_memes(AG,Ch1,M1,Ch2,M2,NCh1,NF1,NCh2,NF2,NS1,NS2):- generate_mask(Ch1,M1,M2,[],Mask), crossing(Ch1,Ch2,Mask,[],NCh1,[],NCh2), fitness_single_agent(AG,NCh1,NF1,NS1), fitness_single_agent(AG,NCh2,NF2,NS2). generate_mask(Ch1,M1,M2,[],Mask):- par(memes,on),!, generate_mask_memes(Ch1,M1,M2,[],Mask). generate_mask(Ch1,_M1,_M2,[],Mask):- par(memes,off),!, generate_mask_no_memes(Ch1,[],Mask). generate_mask_memes([],_M1,_M2,Mask,Mask):-!. generate_mask_memes([_G|Rest],[_B1|M1],[B2|M2],MaskIn,[R|MaskOut]):- (B2=1-> %random(0,2,R), R=1 ; R=0 ), generate_mask_memes(Rest,M1,M2,MaskIn,MaskOut). generate_mask_no_memes([_G|Rest],MaskIn,[R|MaskOut]):- random(0,2,R), generate_mask_no_memes(Rest,MaskIn,MaskOut). crossing([],[],[],NCh1,NCh1,NCh2,NCh2):-!. crossing([G1|Rest1],[G2|Rest2],[M|RestM],NCh1In,NCh1Out,NCh2In,NCh2Out):- (M=0-> % do not exchange the genes NCh1Out=[G1|NCh11], NCh2Out=[G2|NCh21] ; % exchange the genes NCh1Out=[G2|NCh11], NCh2Out=[G1|NCh21] ), crossing(Rest1,Rest2,RestM,NCh1In,NCh11,NCh2In,NCh21). mutate(_AG,0,Pop,Pop):-!. mutate(AG,N,PopIn,PopOut):- length(PopIn,L), random(0,L,R), nth0(R, PopIn, [Ch,M,_F,_S]), length(Ch,LC), random(0,LC,RG), nth0(RG,Ch,Gene), change(Gene,Gene1), replace(Ch,RG,Gene1,Ch1), replace(M,RG,0,M1), fitness_single_agent(AG,Ch1,F1,S1), replace(PopIn,R,[Ch1,M1,F1,S1],Pop1), N1 is N-1, mutate(AG,N1,Pop1,PopOut). % two valued case change(Gene,Gene1):- random(0,2,NewGene), (Gene=NewGene-> change(Gene,Gene1) ; Gene1=NewGene ). % three valued case %change(Gene,Gene1):- % random(-1,2,NewGene), % (Gene=NewGene-> % change(Gene,Gene1) % ; % Gene1=NewGene % ). replace([_H|T],0,El,[El|T]):-!. replace([H|T],N,El,[H|T1]):- N1 is N-1, replace(T,N1,El,T1). lamarck_op(_AG,0,Pop,Pop):-!. lamarck_op(AG,Lam,PopIn,PopOut):- length(PopIn,L), random(0,L,R), nth0(R, PopIn, [Ch,M,_F,_S]), convert(Ch,Abd), solution(AG,Abd,Abd1,Acc), convert_back(Abd1,Ch1,Acc,M,M1), fitness_single_agent(AG,Ch1,F1,S1), replace(PopIn,R,[Ch1,M1,F1,S1],Pop1), Lam1 is Lam -1, lamarck_op(AG,Lam1,Pop1,PopOut). convert_back(Abd1,Ch1,Acc,M,M1):- revisables(L), length(L,N), length(Ch1,N), length(M1,N), convert_back1(Abd1,Ch1,Acc,M,M1). convert_back1([],_Ch1,_Acc,_M,_M1):-!. convert_back1([not H|T],Ch,Acc,M,M1):-!, revisables(R), nth(N, R, H), nth(N,Ch,0), ((member(H,Acc);member(not H,Acc))-> nth(N,M1,1) ; nth(N,M,B), nth(N,M1,B) ), convert_back1(T,Ch,Acc,M,M1). convert_back1([H|T],Ch,Acc,M,M1):- revisables(R), nth(N, R, H), nth(N,Ch,1), ((member(H,Acc);member(not H,Acc))-> nth(N,M1,1) ; nth(N,M,B), nth(N,M1,B) ), convert_back1(T,Ch,Acc,M,M1). select_single_ch(Ch,M,F,S,AG):- population(P,MF,_G,AG), select_ch(P,MF,Ch,M,F,S). select_ch(Pop,MF,Ch1,M1,F1,S1):- length(Pop,L), random(0,L,N), nth0(N,Pop,[Ch,M,F,S]), Pr is F/MF, random(R), (R Ch1=Ch, F1=F, S1=S, M1=M ; select_ch(Pop,MF,Ch1,M1,F1,S1) ). initialize_population:- assert_revisable_list, revisables(L), length(L,N), par(p,P), agents(AG), length(AG,NAG), PA is P/NAG, generate_populations(AG,PA,N). generate_populations([],_PA,_N):-!. generate_populations([AGH|T],PA,N):- null_chromosome(N,C), fitness(C,F,S), PA1 is PA - 1, generate_population(AGH,N,PA1,F,TF,[[C,C,F,S]],Population), assert(population(Population,TF,0,AGH)), generate_populations(T,PA,N). % population(Population, maximum local fitness, generation, agent) % Population=[[Chromosome,Memes,Fitness,Solution(yes,no)],....] null_chromosome(1,[0]):-!. null_chromosome(N,[0|C]):- N1 is N - 1, null_chromosome(N1,C). generate_population(_AGH,_N,P,TF,TF,Pop,Pop):-P=<0,!. generate_population(AGH,N,P,TFIn,TFOut,PopIn,[[Ch,AC,F,S]|PopOut]):- generate_random_chromosome(N,[],Ch), string(N,[],AC), fitness_single_agent(AGH,Ch,F,S), (TFIn >F-> TF1=TFIn ; TF1=F ), P1 is P-1, generate_population(AGH,N,P1,TF1,TFOut,PopIn,PopOut). % string(N,[],Out) generates a string of N 0 string(0,S,S):-!. string(N,Sin,[0|Sout]):- N1 is N-1, string(N1,Sin,Sout). generate_random_chromosome(0,Ch,Ch):-!. % two valued case: 0 is false, 1 true generate_random_chromosome(N,ChIn,[Gene|Chout]):- random(0,2,Gene), N1 is N-1, generate_random_chromosome(N1,ChIn,Chout). % three valued case %generate_random_chromosome(N,ChIn,[Gene|Chout]):- % random(-1,2,Gene), % N1 is N-1, % generate_random_chromosome(N1,ChIn,Chout). retract_old_pred:- retractall(best_chromosome_for_local_fitness(_,_,_,_)), retractall(best_chromosome_for_global_fitness(_,_,_,_)), retractall(population(_,_,_,_)), retractall(revisables(_)), retractall(last_gen(_)). revisable(L):- revisables(List), member(L,List). assert_fitness_data:- agents(List), assert_fitness_for_each_agent(List). assert_fitness_for_each_agent([]):-!. assert_fitness_for_each_agent([H|T]):- population(Population,_MF,G,H), find_fitness_list(Population,[],FitnessList), assert(fitness_list(G,H,FitnessList)), assert_fitness_for_each_agent(T). find_fitness_list([],L,L):-!. find_fitness_list([[_Ch,_AC,F,_S]|T],Lin,[F|Lout]):-!, find_fitness_list(T,Lin,Lout). % population(Population, maximum fitness, generation, agent) % Population=[[Ch,AC,F,S]] % Population=[[Chromosome,Memes,Fitness,Solution(yes,no)],....] % fitness % accuracy: accuracy only % hybrid: accuracy + percentage of false/2 % weighted_hybrid: means of accuracy + percentage of false % (n_i/n) x (n/(n+h)) + (f_i/|h_i|) x (h/(n+h)) %fitness for all agents (overall fitness) fitness(Chromosome,F,S):- par(fitness,weighted_hybrid),!, convert(Chromosome,Abd), check_ics(Abd,N,Nic), count0(Chromosome,0,N0), length(Chromosome,L), Ratio is N/Nic, F is Ratio*(Nic/(Nic+L)) + (N0/L)*(L/(Nic+L)), (Ratio=1.0-> S=yes ; S=no ). % fitness_single_agent(Chromosome,F,S) computes the fitness of a Chromosome according % to the ic for a single agent (local fitness for agent AG) fitness_single_agent(AG,Chromosome,F,S):- par(fitness,weighted_hybrid),!, convert(Chromosome,Abd), check_ics_single_agent(AG,Abd,N,Nic), count0(Chromosome,0,N0), length(Chromosome,L), Ratio is N/Nic, F is Ratio*(Nic/(Nic+L)) + (N0/L)*(L/(Nic+L)), (Ratio=1.0-> S=yes ; S=no ). %fitness for all agents (overall fitness) fitness(Chromosome,F,S):- par(fitness,accuracy),!, convert(Chromosome,Abd), check_ics(Abd,N,Nic), Ratio is N/Nic, F is Ratio, (Ratio=1.0-> S=yes ; S=no ). % fitness_single_agent(Chromosome,F,S) computes the fitness of a Chromosome according % to the ic for a single agent (local fitness for agent AG) fitness_single_agent(AG,Chromosome,F,S):- par(fitness,accuracy),!, convert(Chromosome,Abd), check_ics_single_agent(AG,Abd,N,Nic), Ratio is N/Nic, F is Ratio, (Ratio=1.0-> S=yes ; S=no ). %fitness for all agents (overall fitness) fitness(Chromosome,F,S):- par(fitness,hybrid),!, convert(Chromosome,Abd), check_ics(Abd,N,Nic), count0(Chromosome,0,N0), length(Chromosome,L), Ratio is N/Nic, F is Ratio + (N0/L)/2, (Ratio=1.0-> S=yes ; S=no ). % fitness_single_agent(Chromosome,F,S) computes the fitness of a Chromosome according % to the ic for a single agent (local fitness for agent AG) fitness_single_agent(AG,Chromosome,F,S):- par(fitness,hybrid),!, convert(Chromosome,Abd), check_ics_single_agent(AG,Abd,N,Nic), count0(Chromosome,0,N0), length(Chromosome,L), Ratio is N/Nic, F is Ratio + (N0/L)/2, (Ratio=1.0-> S=yes ; S=no ).