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