Another update from ingydotnet^djgoku

This commit is contained in:
Ingy döt Net 2015-11-18 06:14:39 +00:00
parent 91df62d461
commit 948b86eafa
7604 changed files with 108452 additions and 22726 deletions

View file

@ -11,3 +11,25 @@ Starting with:
Cf: [[wp:Weasel_program#Weasel_algorithm|Weasel algorithm]] and [[wp:Evolutionary algorithm|Evolutionary algorithm]]
<small>Note: to aid comparison, try and ensure the variables and functions mentioned in the task description appear in solutions</small>
===========
A cursory examination of a few of the solutions reveals that the instructions have not been followed rigorously in some solutions. Specifically,
* While the <code>parent</code> is not yet the <code>target</code>:
:* copy the <code>parent</code> C times, each time allowing some random probability that another character might be substituted using <code>mutate</code>.
Note that some of the the solutions given retain characters in the mutated string that are ''correct'' in the target string. However, the instruction above does not state to retain any of the characters while performing the mutation. Although some may believe to do so is implied from the use of "converges"
(:* repeat until the parent converges, (hopefully), to the target.
Strictly speaking, the new parent should be selected from the new pool of mutations, and then the new parent used to generate the next set of mutations with parent characters getting retained only by ''not'' being mutated. It then becomes possible that the new set of mutations has no member that is fitter than the parent!
As illustration of this error, the code for 8th has the following remark.
Create a new string based on the TOS, '''changing randomly any characters which
don't already match the target''':
''NOTE:'' this has been changed, the 8th version is completely random now
Clearly, this algo will be applying the mutation function only to the parent characters that don't match to the target characters!
To ensure that the new parent is never less fit than the prior parent, both the parent and all of the latest mutations are subjected to the fitness test to select the next parent.

View file

@ -0,0 +1,62 @@
#!/bin/awk -f
function randchar(){
return substr(charset,randint(length(charset)+1),1)
}
function mutate(gene,rate ,l,newgene){
newgene = ""
for (l=1; l < 1+length(gene); l++){
if (rand() < rate)
newgene = newgene randchar()
else
newgene = newgene substr(gene,l,1)
}
return newgene
}
function fitness(gene,target ,k,fit){
fit = 0
for (k=1;k<1+length(gene);k++){
if (substr(gene,k,1) == substr(target,k,1)) fit = fit + 1
}
return fit
}
function randint(n){
return int(n * rand())
}
function evolve(){
maxfit = fitness(parent,target)
oldfit = maxfit
maxj = 0
for (j=1; j < D; j++){
child[j] = mutate(parent,mutrate)
fit[j] = fitness(child[j],target)
if (fit[j] > maxfit) {
maxfit = fit[j]
maxj = j
}
}
if (maxfit > oldfit) parent = child[maxj]
}
BEGIN{
target = "METHINKS IT IS LIKE A WEASEL"
charset = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
mutrate = 0.10
if (ARGC > 1) mutrate = ARGV[1]
lenset = length(charset)
C = 100
D = C + 1
parent = ""
for (j=1; j < length(target)+1; j++) {
parent = parent randchar()
}
print "target: " target
print "fitness of target: " fitness(target,target)
print "initial parent: " parent
gens = 0
while (parent != target){
evolve()
gens = gens + 1
if (gens % 10 == 0) print "after " gens " generations,","new parent: " parent," with fitness: " fitness(parent,target)
}
print "after " gens " generations,"," evolved parent: " parent
}

View file

@ -4,6 +4,7 @@
#include <cassert>
#include <algorithm>
#include <vector>
#include <ctime>
std::string allowed_chars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";

View file

@ -8,7 +8,7 @@ dchar rnd() { return (uppercase ~ " ")[uniform(0, $)]; }
enum mut = (dchar[] s) => s.map!(a => uniform01 < P ? rnd : a).array;
void main() {
auto parent = target.length.iota.map!(_ => rnd).array;
auto parent = generate!rnd.take(target.length).array;
for (auto gen = 1; parent != target; gen++) {
// parent = parent.repeat(C).map!mut.array.max!fitness;
parent = parent.repeat(C).map!mut.array

View file

@ -0,0 +1,15 @@
defmodule Rand do
def init do # Initialize the random values.
<< a :: 32, b :: 32, c :: 32 >> = :crypto.strong_rand_bytes(12)
:random.seed(a,b,c)
end
def num do # Returns a value between 0.0 and 1.0.
init
:random.uniform
end
def char(list) do # Returns a random letter or a space.
Enum.at(list, :random.uniform(length(list)) - 1)
end
end

View file

@ -0,0 +1,9 @@
defmodule Log do
def show(offspring,i) do
IO.puts "Generation: #{i}, Offspring: #{offspring}"
end
def found([target|i]) do
IO.puts "#{target} found in #{i} iterations"
end
end

View file

@ -0,0 +1,57 @@
defmodule Evolution do
def select(target) do
# Generate char list from A to Z; 32 is the ord value for space.
chars = (?A..?Z) |> Enum.to_list() |> List.insert_at(0, 32)
(1..String.length(target)) # Creates parent for generation 0.
|> Enum.map(fn _-> Rand.char(chars) end)
|> mutate(String.to_char_list(target),0,[],chars)
|> Log.found()
end
# w is used to denote fitness in population genetics.
def mutate(parent,target,i,_,_) when target == parent, do: [parent|i]
def mutate(parent,target,i,_,chars) when target != parent do
w = fitness(parent,target)
prev = reproduce(target,parent,w,0,mu_rate(w),chars)
# Check if the most fit member of the new gen has a greater fitness than the parent.
if w < fitness(prev,target) do
parent = prev
Log.show(parent,i)
end
mutate(parent,target,i+1,prev,chars)
end
# Generate 100 offspring and select the one with the greatest fitness.
def reproduce(target,parent,_,_,rate,chars) do
(1..100)
|> Enum.to_list()
|> Stream.map(fn _-> mutation(parent,rate,chars) end)
|> List.insert_at(0, parent)
|> Enum.max_by(fn n -> fitness(n,target) end)
end
# Calculate fitness by checking difference between parent and offspring chars.
def fitness(t,r) do
(0..length(t)-1)
|> Stream.map(fn n -> abs(Enum.at(t,n) - Enum.at(r,n)) end)
|> Enum.reduce(fn a,b -> a + b end)
|> calc()
end
# Generate offspring based on parent.
def mutation(p,r,chars) do
# Copy the parent chars, then check each val against the random mutation rate
(0..length(p)-1)
|> Stream.map(fn n -> Enum.at(p,n) end)
|> Enum.map(fn n -> if Rand.num <= r, do: Rand.char(chars), else: n end)
end
def calc(sum), do: 100 * :math.exp(sum/-10)
def mu_rate(n), do: 1 - :math.exp(-(100-n)/400)
end

View file

@ -0,0 +1 @@
Evolution.select("METHINKS IT IS LIKE A WEASEL")

View file

@ -0,0 +1,27 @@
function evolve(parent,target,mutation_rate,num_children)
println("Initial parent is $parent, its fitness is $(fitness(parent,target))")
gens=0
while parent!=target
children=[mutate(parent,mutation_rate) for i=1:num_children]
bestfit,best=findmax(map(child->fitness(child,target),children))
parent=children[best]
gens+=1
if gens%10==0
println("After $gens generations, the new parent is $parent and its fitness is $(fitness(parent,target))")
end
end
println("After $gens generations, the parent evolved into the target $target")
end
fitness(s1,s2)=count(x->x,convert(Array{Char,1},s1).==convert(Array{Char,1},s2))
function mutate(s,rate)
new_s=""
for c in s
new_s*=string(rand()<rate?
" ABCDEFGHIJKLMNOPQRSTUVWXYZ"[rand(1:27)]:c)
end
return new_s
end
evolve("IU RFSGJABGOLYWF XSMFXNIABKT","METHINKS IT IS LIKE A WEASEL",0.08998,100)

View file

@ -0,0 +1,6 @@
Initial parent is IU RFSGJABGOLYWF XSMFXNIABKT, its fitness is 1
After 10 generations, the new parent is M TBINGJ IGOYSYV KIAM WIAXEL and its fitness is 13
After 20 generations, the new parent is MRTBINKJ IT SYO KT Z WEAIEL and its fitness is 18
After 30 generations, the new parent is MGTHINKJ IT ISYLMKJ A WEASEL and its fitness is 23
After 40 generations, the new parent is MBTHINKS IT ISYLIKE A WEASEL and its fitness is 26
After 49 generations, the parent evolved into the target METHINKS IT IS LIKE A WEASEL

View file

@ -0,0 +1,110 @@
%% Genetic Algorithm -- Solves For A User Input String
% #### PLEASE NOTE: you can change the selection and crossover type in the
% parameters and see how the algorithm changes. ####
clear;close all;clc; %Clears variables, closes windows, and clears the command window
tic % Begins the timer
%% Select Target String
target = 'METHINKS IT IS LIKE A WEASEL';
% *Can Be Any String With Any Values and Any Length!*
% but for this example we use 'METHINKS IT IS LIKE A WEASEL'
%% Parameters
popSize = 1000; % Population Size (100-10000 generally produce good results)
genome = length(target); % Genome Size
mutRate = .01; % Mutation Rate (5%-25% produce good results)
S = 4; % Tournament Size (2-6 produce good results)
best = Inf; % Initialize Best (arbitrarily large)
MaxVal = max(double(target)); % Max Integer Value Needed
ideal = double(target); % Convert Target to Integers
selection = 0; % 0: Tournament
% 1: 50% Truncation
crossover = 1; % 0: Uniform crossover
% 1: 1 point crossover
% 2: 2 point crossover
%% Initialize Population
Pop = round(rand(popSize,genome)*(MaxVal-1)+1); % Creates Population With Corrected Genome Length
for Gen = 1:1e6 % A Very Large Number Was Chosen, But Shouldn't Be Needed
%% Fitness
% The fitness function starts by converting the characters into integers and then
% subtracting each element of each member of the population from each element of
% the target string. The function then takes the absolute value of
% the differences and sums each row and stores the function as a mx1 matrix.
F = sum(abs(bsxfun(@minus,Pop,ideal)),2);
% Finding Best Members for Score Keeping and Printing Reasons
[current,currentGenome] = min(F); % current is the minimum value of the fitness array F
% currentGenome is the index of that value in the F array
% Stores New Best Values and Prints New Best Scores
if current < best
best = current;
bestGenome = Pop(currentGenome,:); % Uses that index to find best value
fprintf('Gen: %d | Fitness: %d | ',Gen, best); % Formatted printing of generation and fitness
disp(char(bestGenome)); % Best genome so far
elseif best == 0
break % Stops program when we are done
end
%% Selection
% TOURNAMENT
if selection == 0
T = round(rand(2*popSize,S)*(popSize-1)+1); % Tournaments
[~,idx] = min(F(T),[],2); % Index to Determine Winners
W = T(sub2ind(size(T),(1:2*popSize)',idx)); % Winners
% 50% TRUNCATION
elseif selection == 1
[~,V] = sort(F,'descend'); % Sort Fitness in Ascending Order
V = V(popSize/2+1:end); % Winner Pool
W = V(round(rand(2*popSize,1)*(popSize/2-1)+1))'; % Winners
end
%% Crossover
% UNIFORM CROSSOVER
if crossover == 0
idx = logical(round(rand(size(Pop)))); % Index of Genome from Winner 2
Pop2 = Pop(W(1:2:end),:); % Set Pop2 = Pop Winners 1
P2A = Pop(W(2:2:end),:); % Assemble Pop2 Winners 2
Pop2(idx) = P2A(idx); % Combine Winners 1 and 2
% 1-POINT CROSSOVER
elseif crossover == 1
Pop2 = Pop(W(1:2:end),:); % New Population From Pop 1 Winners
P2A = Pop(W(2:2:end),:); % Assemble the New Population
Ref = ones(popSize,1)*(1:genome); % The Reference Matrix
idx = (round(rand(popSize,1)*(genome-1)+1)*ones(1,genome))>Ref; % Logical Indexing
Pop2(idx) = P2A(idx); % Recombine Both Parts of Winners
% 2-POINT CROSSOVER
elseif crossover == 2
Pop2 = Pop(W(1:2:end),:); % New Pop is Winners of old Pop
P2A = Pop(W(2:2:end),:); % Assemble Pop2 Winners 2
Ref = ones(popSize,1)*(1:genome); % Ones Matrix
CP = sort(round(rand(popSize,2)*(genome-1)+1),2); % Crossover Points
idx = CP(:,1)*ones(1,genome)<Ref&CP(:,2)*ones(1,genome)>Ref; % Index
Pop2(idx)=P2A(idx); % Recombine Winners
end
%% Mutation
idx = rand(size(Pop2))<mutRate; % Index of Mutations
Pop2(idx) = round(rand([1,sum(sum(idx))])*(MaxVal-1)+1); % Mutated Value
%% Reset Poplulations
Pop = Pop2;
end
toc % Ends timer and prints elapsed time

View file

@ -0,0 +1,42 @@
Gen: 1 | Fitness: 465 | C<EFBFBD>I1%G+<%?R<EFBFBD>8>9<EFBFBD>JU#(E<EFBFBD>UO<EFBFBD>PHI
Gen: 2 | Fitness: 429 | W=P6>D<EFBFBD>I)VU6$T 99,<EFBFBD> B<EFBFBD>BMP0JH
Gen: 3 | Fitness: 366 | P<EFBFBD>;R08AS<EFBFBD>GJ<EFBFBD>IS&T38IE<EFBFBD>)SJERLJ
Gen: 4 | Fitness: 322 | KI8M5LAS<EFBFBD>GJ<EFBFBD>IS<EFBFBD>SP<EFBFBD>@)D<EFBFBD>V@
JCP
Gen: 5 | Fitness: 295 | UAUR08AS<EFBFBD>GJ<EFBFBD>IS<EFBFBD>8HG*<EFBFBD>+<EFBFBD>=C?UB(
Gen: 6 | Fitness: 259 | VCUQH35S<EFBFBD>HR4.L<EFBFBD>ISJQ%J<EFBFBD>OC*T=E
Gen: 7 | Fitness: 226 | LFB8GPET(LODKQ<EFBFBD>KQ<K E*PEMA6I
Gen: 8 | Fitness: 192 | EPKOLCIR<EFBFBD>QQ<EFBFBD>NF<EFBFBD>QG:B(D/U>BQGF
Gen: 9 | Fitness: 159 | N8R7?SOU<EFBFBD>NO$OK O?K?!;<EFBFBD>MB?QHG
Gen: 10 | Fitness: 146 | TGN@EQR4)PS%IS#TFJQ%A!U>BVLI
Gen: 11 | Fitness: 120 | L?VMALJS%?R EK IILE<EFBFBD>6'RRERLJ
Gen: 12 | Fitness: 102 | R@T9COMR<EFBFBD>NU CS*R?K?!; VD>LCL
Gen: 13 | Fitness: 96 | NENMVOMR<EFBFBD>NU CS*R?K?!; VD>LCL
Gen: 14 | Fitness: 82 | REJGNPMU<EFBFBD>KR CS JKI@+D<EFBFBD>UD?QHG
Gen: 15 | Fitness: 75 | NETI=HPQ<EFBFBD>FT ID EFKE D"WD>QDQ
Gen: 16 | Fitness: 70 | R@TKCOOT)@R$IS KKLE<EFBFBD>D"WC?UBJ
Gen: 17 | Fitness: 61 | NESIKQRP<EFBFBD>NU CS<EFBFBD>MFKE ; SEETCP
Gen: 18 | Fitness: 57 | LFSGLPTN<EFBFBD>NU GQ IIKE D"VD>LCL
Gen: 19 | Fitness: 40 | NENKJLMS<EFBFBD>GS%IS#MFKE B UFATCL
Gen: 21 | Fitness: 39 | NETIGPEU<EFBFBD>KR IS IIKD"? UFDQEK
Gen: 22 | Fitness: 33 | NETGCOMT<EFBFBD>LU IS#MFKE B UFATCL
Gen: 23 | Fitness: 32 | NETIKNPQ<EFBFBD>NU IS#IIKE B UFATCL
Gen: 24 | Fitness: 27 | NETKJLMS<EFBFBD>LU IS MFKE B UFATCL
Gen: 25 | Fitness: 23 | LETIKOMS LU IS IIKE D WEDQEK
Gen: 26 | Fitness: 22 | NETIKMJS LU IS IIKE D WEDQEK
Gen: 27 | Fitness: 20 | LETIKOMS LU IS KILE B"WFATCL
Gen: 28 | Fitness: 19 | NESGJQJS<EFBFBD>GU IS KIKE B WFATEK
Gen: 29 | Fitness: 16 | NETIHPMS KR IS KIKE B WFATEK
Gen: 30 | Fitness: 15 | NESHLPKS KU IS KIKE B WFATEK
Gen: 31 | Fitness: 13 | NETGGNKS KU IS KIKE C WFATEK
Gen: 32 | Fitness: 12 | NETHGNJS IU IS JIKE B WFATCL
Gen: 33 | Fitness: 11 | NETIJPKS IU IS KIKE B WFATEK
Gen: 35 | Fitness: 8 | LEUIHNJS IT IS JIKE A WEATEL
Gen: 37 | Fitness: 7 | NETIHNJS IS IS LIKE B WFASEL
Gen: 38 | Fitness: 6 | NETHGNJS IT IS LIKE A WFASEK
Gen: 39 | Fitness: 4 | METGHNKS IT IS LIKE B WEATEL
Gen: 42 | Fitness: 3 | NETHINKS IT IS KIKE B WEASEL
Gen: 43 | Fitness: 2 | NETHINKS IT IS LIKE A WFASEL
Gen: 44 | Fitness: 1 | METHHNKS IT IS LIKE A WEASEL
Gen: 46 | Fitness: 0 | METHINKS IT IS LIKE A WEASEL
Elapsed time is 0.099618 seconds.

View file

@ -0,0 +1,108 @@
PROGRAM EVOLUTION (OUTPUT);
CONST
TARGET = 'METHINKS IT IS LIKE A WEASEL';
COPIES = 100; (* 100 children in each generation. *)
RATE = 1000; (* About one character in 1000 will be a mutation. *)
TYPE
STRLIST = ARRAY [1..COPIES] OF STRING;
FUNCTION RANDCHAR : CHAR;
(* Generate a random letter or space. *)
VAR RANDNUM : INTEGER;
BEGIN
RANDNUM := RANDOM(27);
IF RANDNUM = 26 THEN
RANDCHAR := ' '
ELSE
RANDCHAR := CHR(RANDNUM + ORD('A'))
END;
FUNCTION RANDSTR (SIZE : INTEGER) : STRING;
(* Generate a random string. *)
VAR
N : INTEGER;
S : STRING;
BEGIN
S := '';
FOR N := 1 TO SIZE DO
INSERT(RANDCHAR, S, 1);
RANDSTR := S
END;
FUNCTION FITNESS (CANDIDATE, GOAL : STRING) : INTEGER;
(* Count the number of correct letters in the correct places *)
VAR N, MATCHES : INTEGER;
BEGIN
MATCHES := 0;
FOR N := 1 TO LENGTH(GOAL) DO
IF CANDIDATE[N] = GOAL[N] THEN
MATCHES := MATCHES + 1;
FITNESS := MATCHES
END;
FUNCTION MUTATE (RATE : INTEGER; S : STRING) : STRING;
(* Randomly alter a string. Characters change with probability 1/RATE. *)
VAR
N : INTEGER;
CHANGE : BOOLEAN;
BEGIN
FOR N := 1 TO LENGTH(TARGET) DO
BEGIN
CHANGE := RANDOM(RATE) = 0;
IF CHANGE THEN
S[N] := RANDCHAR
END;
MUTATE := S
END;
PROCEDURE REPRODUCE (RATE : INTEGER; PARENT : STRING; VAR CHILDREN : STRLIST);
(* Generate children with random mutations. *)
VAR N : INTEGER;
BEGIN
FOR N := 1 TO COPIES DO
CHILDREN[N] := MUTATE(RATE, PARENT)
END;
FUNCTION FITTEST(CHILDREN : STRLIST; GOAL : STRING) : STRING;
(* Measure the fitness of each child and return the fittest. *)
(* If multiple children equally match the target, then return the first. *)
VAR
MATCHES, MOST_MATCHES, BEST_INDEX, N : INTEGER;
BEGIN
MOST_MATCHES := 0;
BEST_INDEX := 1;
FOR N := 1 TO COPIES DO
BEGIN
MATCHES := FITNESS(CHILDREN[N], GOAL);
IF MATCHES > MOST_MATCHES THEN
BEGIN
MOST_MATCHES := MATCHES;
BEST_INDEX := N
END
END;
FITTEST := CHILDREN[BEST_INDEX]
END;
VAR
PARENT, BEST_CHILD : STRING;
CHILDREN : STRLIST;
GENERATIONS : INTEGER;
BEGIN
RANDOMIZE;
GENERATIONS := 0;
PARENT := RANDSTR(LENGTH(TARGET));
WHILE NOT (PARENT = TARGET) DO
BEGIN
IF (GENERATIONS MOD 100) = 0 THEN WRITELN(PARENT);
GENERATIONS := GENERATIONS + 1;
REPRODUCE(RATE, PARENT, CHILDREN);
BEST_CHILD := FITTEST(CHILDREN, TARGET);
IF FITNESS(PARENT, TARGET) < FITNESS(BEST_CHILD, TARGET) THEN
PARENT := BEST_CHILD
END;
WRITE('The string was matched in ');
WRITELN(GENERATIONS, ' generations.')
END.

View file

@ -1,13 +1,13 @@
constant target = "METHINKS IT IS LIKE A WEASEL";
constant mutate_chance = .08;
constant alphabet = 'A'..'Z',' ';
constant @alphabet = flat 'A'..'Z',' ';
constant C = 100;
sub mutate { $^string.comb.map({ rand < mutate_chance ?? alphabet.pick !! $_ }).join }
sub mutate { $^string.subst(/./, { rand < mutate_chance ?? @alphabet.pick !! $/ }, :g) }
sub fitness { [+] $^string.comb Zeq state @ = target.comb }
loop (
my $parent = alphabet.roll(target.chars).join;
my $parent = @alphabet.roll(target.chars).join;
$parent ne target;
$parent = max :by(&fitness), mutate($parent) xx C
) { printf "%6d: '%s'\n", $++, $parent }

View file

@ -1,13 +1,14 @@
from string import ascii_uppercase
from string import letters
from random import choice, random
target = list("METHINKS IT IS LIKE A WEASEL")
charset = ascii_uppercase + ' '
charset = letters + ' '
parent = [choice(charset) for _ in range(len(target))]
minmutaterate = .09
C = range(100)
perfectfitness = float(len(target))
def fitness(trial):
'Sum of matching chars by position'
return sum(t==h for t,h in zip(trial, target))
@ -24,12 +25,23 @@ def que():
print ("#%-4i, fitness: %4.1f%%, '%s'" %
(iterations, fitness(parent)*100./perfectfitness, ''.join(parent)))
def mate(a, b):
place = 0
if choice(xrange(10)) < 7:
place = choice(xrange(len(target)))
else:
return a, b
return a, b, a[:place] + b[place:], b[:place] + a[place:]
iterations = 0
center = len(C)/2
while parent != target:
rate = mutaterate()
rate = mutaterate()
iterations += 1
if iterations % 100 == 0: que()
copies = [ mutate(parent, rate) for _ in C ] + [parent]
parent = max(copies, key=fitness)
print ()
parent1 = max(copies[:center], key=fitness)
parent2 = max(copies[center:], key=fitness)
parent = max(mate(parent1, parent2), key=fitness)
que()

View file

@ -1,35 +1,34 @@
/*REXX program demonstrates an evolutionary algorithm (using mutation).*/
parse arg children MR seed . /*get options (maybe) from C.L. */
if children=='' then children = 10 /*# of children produced each gen*/
if MR =='' then MR = '4%' /*the char Mutation Rate each gen*/
if right(MR,1)=='%' then MR=strip(MR,,'%')/100 /*expressed as %? Adjust*/
if seed\=='' then call random ,,seed /*allow the runs to be repeatable*/
abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ' ; Labc=length(abc)
target= 'METHINKS IT IS LIKE A WEASEL' ; Ltar=length(target)
parent= mutate( left('',Ltar), 1) /*gen rand str,same length as tar*/
say center('target string',Ltar,'') "children" 'mutationRate'
say target center(children,8) center((MR*100/1)'%',12) ; say
say center('new string',Ltar,'') "closeness" 'generation'
/*REXX program demonstrates an evolutionary algorithm (by using mutation). */
parse arg children MR seed . /*get optional arguments from the C.L. */
if children=='' then children = 10 /*# children produced each generation. */
if MR =='' then MR = '4%' /*the character Mutation Rate each gen.*/
if right(MR,1)=='%' then MR=strip(MR,,'%')/100 /*expressed as %? Then adjust*/
if seed\=='' then call random ,,seed /*SEED allow the runs to be repeatable.*/
abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ' ; Labc=length(abc)
target= 'METHINKS IT IS LIKE A WEASEL' ; Ltar=length(target)
parent= mutate( left('',Ltar), 1) /*gen rand string,same length as target*/
say center('target string',Ltar,'') "children" 'mutationRate'
say target center(children,8) center((MR*100/1)'%',12); say
say center('new string',Ltar,'') "closeness" 'generation'
do gen=0 until parent==target; close=fitness(parent)
do gen=0 until parent==target; close=fitness(parent)
almost=parent
do children; child=mutate(parent,MR)
_=fitness(child); if _<=close then iterate
close=_; almost=child
say almost right(close,9) right(gen,10)
do children; child=mutate(parent,MR)
_=fitness(child); if _<=close then iterate
close=_; almost=child
say almost right(close,9) right(gen,10)
end /*children*/
parent=almost
end /*gen*/
exit /*stick a fork in it, we're done.*/
/*───────────────────────────────────FITNESS subroutine─────────────────*/
fitness: parse arg x; hit=0; do k=1 for Ltar
hit=hit+(substr(x,k,1)==substr(target,k,1))
end /*k*/
return hit
/*───────────────────────────────────MUTATE subroutine──────────────────*/
mutate: parse arg x,rate,? /*set ? to a null, x=string. */
do j=1 for Ltar; r=random(1,100000)
if .00001*r<=rate then ?=? || substr(abc,r//Labc+1,1)
else ?=? || substr(x,j,1)
end /*j*/
return ?
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
fitness: parse arg x; $=0
do k=1 for Ltar; $=$+(substr(x,k,1)==substr(target,k,1)); end /*k*/
return $
/*────────────────────────────────────────────────────────────────────────────*/
mutate: parse arg x,rate $ /*set X to 1st argument, RATE to 2nd.*/
$=; do j=1 for Ltar; r=random(1,100000) /*REXX's max.*/
if .00001*r<=rate then $=$ || substr(abc,r//Labc+1,1)
else $=$ || substr(x,j,1)
end /*j*/
return $

View file

@ -1,45 +1,43 @@
/*REXX program demonstrates an evolutionary algorithm (using mutation).*/
parse arg children MR seed . /*get options (maybe) from C.L. */
if children=='' then children = 10 /*# of children produced each gen*/
if MR =='' then MR = "4%" /*the char Mutation Rate each gen*/
if right(MR,1)=='%' then MR=strip(MR,,"%")/100 /*expressed as %? Adjust*/
if seed\=='' then call random ,,seed /*allow the runs to be repeatable*/
abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ' ; Labc=length(abc)
/*REXX program demonstrates an evolutionary algorithm (by using mutation). */
parse arg children MR seed . /*get optional arguments from the C.L. */
if children=='' then children = 10 /*# children produced each generation. */
if MR =='' then MR = '4%' /*the character Mutation Rate each gen.*/
if right(MR,1)=='%' then MR=strip(MR,,'%')/100 /*expressed as %? Then adjust*/
if seed\=='' then call random ,,seed /*SEED allow the runs to be repeatable.*/
abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ '; Labc=length(abc)
do i=0 for Labc /*define array (faster compare), */
A.i=substr(abc, i+1, 1) /* it's better than picking out a*/
end /*i*/ /* byte from a character string. */
do i=0 for Labc /*define array (for faster compare), */
@.i=substr(abc,i+1,1) /* it's better than picking out a */
end /*i*/ /* byte from a character string. */
target= 'METHINKS IT IS LIKE A WEASEL' ; Ltar=length(target)
do i=1 for Ltar /*define array (faster compare), */
T.i=substr(target, i, 1) /*it's better than a byte-by-byte*/
end /*i*/ /*compare using character strings*/
do i=1 for Ltar /*define an array (for faster compare),*/
T.i=substr(target,i,1) /* it's better than a byte-by-byte */
end /*i*/ /* compare using character strings.*/
parent= mutate( left('', Ltar), 1) /*gen rand str,same length as tar*/
say center('target string', Ltar, '') "children" 'mutationRate'
say target center(children, 8) center((MR*100/1)'%', 12) ; say
say center('new string', Ltar, '') "closeness" 'generation'
parent= mutate( left('',Ltar), 1) /*gen rand string, same length as tar. */
say center('target string',Ltar,'') "children" 'mutationRate'
say target center(children,8) center((MR*100/1)'%',12); say
say center('new string',Ltar,'') "closeness" 'generation'
do gen=0 until parent==target; close=fitness(parent)
do gen=0 until parent==target; close=fitness(parent)
almost=parent
do children; child=mutate(parent, MR)
_=fitness(child); if _<=close then iterate
close=_; almost=child
say almost right(close, 9) right(gen, 10)
do children; child=mutate(parent,MR)
_=fitness(child); if _<=close then iterate
close=_; almost=child
say almost right(close,9) right(gen,10)
end /*children*/
parent=almost
end /*gen*/
exit /*stick a fork in it, we're done.*/
/*───────────────────────────────────FITNESS subroutine─────────────────*/
fitness: parse arg x; hit=0; do k=1 for Ltar
hit=hit + (substr(x,k,1) == T.k)
end /*k*/
return hit
/*───────────────────────────────────MUTATE subroutine──────────────────*/
mutate: parse arg x,rate,? /*set ? to a null, x=string. */
do j=1 for Ltar; r=random(1, 100000)
if .00001*r<=rate then do; _=r//Labc; ?=? || A._; end
else ?=? || substr(x,j,1)
end /*j*/
return ?
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
fitness: parse arg x; $=0; do k=1 for Ltar; $=$+(substr(x,k,1)==T.k); end
return $
/*────────────────────────────────────────────────────────────────────────────*/
mutate: parse arg x,rate /*set X to 1st argument, RATE to 2nd.*/
$=; do j=1 for Ltar; r=random(1,100000) /*REXX's max.*/
if .00001*r<=rate then do; _=r//Labc; $=$ || @._; end
else $=$ || substr(x,j,1)
end /*j*/
return $