View difference between Paste ID: hk8yNEi3 and
SHOW:
|
|
- or go back to the newest paste.
1 | - | |
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 32 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). |