daily pastebin goal
1%
SHARE
TWEET

blackbeard

a guest Dec 14th, 2010 39 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -module(genetic).
  2. -export([test/1, start/0]).
  3. -author({jha, abhinav}).
  4.  
  5. % This is for use directly from the command line.
  6. test(Superman)->
  7.     io:format("Trying to Breed Superhuman: ~p ~n", [Superman]),
  8.     start(lists:concat(Superman)).
  9.  
  10. % This can be used from the erlang shell, once exported above.
  11. start()-> start("superman").
  12. start(Superman)->start(Superman, 100).
  13. start(Superman, Base)->start(Superman, Base, 10000000).
  14. start(Superman, Base, Apocalypse)->start(Superman, Base, Apocalypse, 5).
  15.  
  16. % Superman is the ideal being that the population should evolve into.
  17. % Base is the maximum initial population (of monkeys).
  18. % Apocalypse is the number of generations after which
  19. % a big meteor will wipe off all life from the planet and hence is our deadline.
  20. start(Superman, Base, Apocalypse, Mutability)->
  21.     Monkeys = spawn_base(length(Superman), [], Base),
  22.     Gens = evolve(Monkeys, Superman, Apocalypse, Mutability),
  23.     io:format("Total time taken: ~p generations. ~n", [Apocalypse - Gens]).
  24.  
  25.  
  26.  
  27. % We currently have 2 policies for allowing breeding : fascist (top 20) and liberal (everyone allowed to breed:P)
  28. % Line 19 has an atom (liberal/fascist) that can change the policy.
  29. evolve(_,_, 0, _) -> 0;
  30. evolve(Monkeys, Superman, Generations_to_apocalypse, P)->
  31.     DamageList = lists:keysort(2, [{X, inverse_fitness(X, Superman,0)} || X <- Monkeys]),
  32.     {GoodD, BadD} = breedingpolicy(DamageList, fascist, 50),
  33.     Good = [ X || {X, _} <- GoodD],
  34.     case goodenough(Good, Superman) of
  35.         false ->
  36.             Bad = [ Y || {Y, _} <- BadD],
  37.             NewGood = reproduction_cycle(Good, Superman, P),
  38.             evolve(NewGood ++ Bad, Superman, Generations_to_apocalypse -1, P);
  39.         X ->io:format("Success - Bred Superman! ~p ~n", [X]),
  40.             Generations_to_apocalypse
  41.     end.
  42.  
  43. % One reproduction cycle involves cross breeding the eligible mating population as decided by
  44. % the reproduction policy, once.
  45. reproduction_cycle(Generation, Superman, P)->
  46.     reproduction_cycle(Generation, 1, (length(Generation) div 2) + 1,
  47.                        Generation, Superman, P).
  48. reproduction_cycle(_, X, X, NewGen, _, _) -> NewGen;
  49. reproduction_cycle(Generation, X, Y, NewGen, Superman, P)->
  50.     Parent1 = lists:nth(X*2 -1, Generation),
  51.     Parent2 = lists:nth(X*2, Generation),
  52.     {Sibling1, Sibling2} = breed(Parent1, Parent2, P),
  53.     io:format("[Breeding] ~p x ~p => ~p , ~p ~n", [Parent1, Parent2, Sibling1, Sibling2]),
  54.     NextGen = [ Pop || Pop <- NewGen, Pop =/= Sibling1, Pop =/= Sibling2],
  55.     Match = [ Child || Child <- [Sibling1, Sibling2], Sibling1 =:= Superman orelse Sibling2 =:= Superman ],
  56.     case length(Match) of
  57.         0 -> reproduction_cycle(Generation, X+1, Y, [Sibling1, Sibling2|NextGen], Superman, P);
  58.         _ ->io:format("======================================================~n"),
  59.             io:format("~p x ~p => [~p, ~p]  ~n", [Parent1, Parent2, Sibling1, Sibling2]),
  60.             io:format("======================================================~n"),
  61.             [Sibling1,Sibling2|NewGen]
  62.     end.
  63.  
  64.  
  65. % One specific instance of a couple mating.
  66. % Pick a random pivot, and swap the strings around the pivot
  67. % in Parent1 and Parent 2.
  68. % e.g: AAAAAZZZZZ x BBBBBYYYYY  = AAAAAYYYYY, BBBBBZZZZZ
  69. breed(Parent1, Parent2, P)->
  70.     Xspot = random:uniform(length(Parent1)),
  71.     {Parent1_frag1, Parent1_frag2} = lists:split(Xspot, Parent1),
  72.     {Parent2_frag1, Parent2_frag2} = lists:split(Xspot, Parent2),
  73.     random_mutate({Parent1_frag1 ++ Parent2_frag2, Parent2_frag1 ++ Parent1_frag2}, P).
  74.  
  75. % Mutate with a 1/pow(2, P) probability
  76. random_mutate(S, P)->
  77.     {S1, S2} = S,
  78.     X = case probability(P) of
  79.             true ->
  80.                 Mutant1 = mutate(S1),
  81.                 io:format("[Mutation]Result: ~p <==> ~p ~n", [S1, Mutant1]),
  82.                 Mutant1;
  83.             false -> S1
  84.     end,
  85.     Y = case probability(5) of
  86.             true ->
  87.                     Mutant2 = mutate(S2),
  88.                     io:format("[Mutation]Result: ~p <==> ~p ~n", [S1, Mutant2]),
  89.                     Mutant2;
  90.             false -> S2
  91.     end,
  92.     {X, Y}.
  93.  
  94.  
  95. % Actual mutation function.
  96. % Mutagen = Random + or - variation of variable value at a random mutation point within a string.
  97. mutate(S)->
  98.     {A1,A2,A3} = now(),
  99.     random:seed(A1,A2,A3),
  100.     MutationPoint = random:uniform(length(S)-1),
  101.     {Pre, [X|Post]} = lists:split(MutationPoint-1, S),
  102.     Mutagen = case probability(1) of
  103.         true -> -1 * random:uniform(5);
  104.         false -> random:uniform(5)
  105.     end,
  106.     Pre ++ [abs((X-97 + Mutagen) rem 122) + 97] ++ Post.
  107.  
  108. % Initial population
  109. spawn_base(_, Acc, 1)-> Acc;
  110. spawn_base(Num, Acc, N)->spawn_base(Num, [make_string(Num, [])|Acc], N-1).
  111. make_string(X, Acc)->
  112.     case length(Acc) of
  113.         X -> Acc;
  114.         _ -> make_string(X, [96 + random:uniform(26)|Acc])
  115.     end.
  116.  
  117.  
  118. % Inverse fitness count. ( As in survival of the fittest).
  119. % calculates absolute distance of a progeny from the ideal ubermensch.
  120. inverse_fitness([], _, N) -> N;
  121. inverse_fitness([P|Person], [I|Ideal], N)->inverse_fitness(Person, Ideal, N+abs(P-I)).
  122.  
  123. % Whether we have formed the ideal person or not.
  124. goodenough([Superman|_Good], Superman)->Superman;
  125. goodenough(_, _)->false.
  126.  
  127. % A simple probability function that returns true with
  128. % a probability of 1/2^X
  129. probability(X)-> probability(X, X).
  130. probability(_, 0) -> true;
  131. probability(X, A) ->
  132.     N1 = random:uniform(),
  133.     N2 = random:uniform(),
  134.     case N1 > N2 of
  135.         true -> probability(X, A-1);
  136.         false -> false
  137.     end.
  138.  
  139. % Decide the breeding policy - fascist or liberal
  140. breedingpolicy(Population, fascist, X)->lists:split(X, Population);
  141. breedingpolicy(Population, liberal, _)->lists:split(length(Population), Population).
RAW Paste Data
Top