Update:
The genes don't get corrupted anymore, I'm not even sure what was really causing the problem. I fixed my crossover function too, so now it properly has a crossover chance on EVERY gene, and not just two, and it now also uses elitism. I also fixed random little bugs here and there. Now that I have it working moderately well, I need to work on optimizing it to work faster. My first thought for that is changing the 'calculate' function to work on a gene-by-gene basis instead of re-calculating every gene every time, since only two genes change at a time in the crossover function.
Rem ***** Main Source File *****
Rem Project: GA4
Rem Created: 4/8/2010 5:34:36 PM
#constant POP_SIZE 50.0
#constant GENE_LENGTH 11.0
#constant CROSSOVER 0.7
#constant MUTATION 0.1
global total_fitness#
global avg_fitness#
global GOAL as float
global loop_counter
GOAL=rnd(1000)+1000
set text opaque
generate_population(POP_SIZE,GENE_LENGTH)
do
calculate(GENE_LENGTH)
crossover()
mutate()
calculate(GENE_LENGTH)
inc loop_counter
display(loop_counter)
total_fitness#=0
loop
function display(num)
set cursor 0,0
print str$(avg_fitness#)
print GOAL
remstart
if loop_counter mod 250=0 and loop_counter>0
filenum=loop_counter/250
file$=str$(filenum)
open to write filenum,file$
write string filenum,str$(GOAL)
write string filenum,str$(avg_fitness#)
debug=1
endif
remend
for x=1 to POP_SIZE
if pop_fitness(x)>=oldpop#
oldpop#=pop_fitness(x)
highest=x
endif
if pop_fitness(x)=1.0
sol$=population$(x)
sol=x
endif
if debug=1
write string filenum,population$(x)
write string filenum,str$(pop_calculated(x))
write string filenum,str$(pop_fitness(x))
write string filenum," "
endif
next x
if debug=1 then close file filenum
print "Best solution: "+population$(highest)+"="+str$(pop_calculated(highest))+" "
print "Highest fitness: "+str$(pop_fitness(highest))+" "
print "Generation Number: "+str$(num)+" "
if sol$<>"" : print "Solution found: "+population$(sol)+"="+str$(pop_calculated(sol)) : wait mouse : end : endif
endfunction
function crossover()
for total=1 to POP_SIZE
cross=rnd(10)
if cross<=(CROSSOVER*100)
for elitism=1 to POP_SIZE
if highest#<=pop_fitness(elitism)
highest#=pop_fitness(elitism)
num=elitism
endif
next elitism
redo:
for get_two=1 to 2
for x=1 to POP_SIZE
cross_chance#=(pop_fitness(x)/total_fitness#)*100 `1 to 100
cross_limit#=rnd(100)
if cross_limit#<=cross_chance#
selections(get_two)=x
endif
next x
next get_two
if selections(1)=selections(2) then goto redo
if selections(1)=0 or selections(2)=0 then goto redo
if selections(1)=num or selections(2)=num then goto redo
place=rnd(GENE_LENGTH-2)+2
place2=GENE_LENGTH-place
temp1$=population$(selections(1))
temp2$=population$(selections(2))
population$(selections(1))=left$(temp1$,place)+right$(temp2$,place2)
population$(selections(2))=left$(temp2$,place)+right$(temp1$,place2)
calculate(GENE_LENGTH)
endif
next total
endfunction
function mutate()
for elitism=1 to POP_SIZE
if highest#<=pop_fitness(elitism)
highest#=pop_fitness(elitism)
num=elitism
endif
next elitism
for x=1 to POP_SIZE
mutate_limit#=rnd(1000)
if mutate_limit#<=(MUTATION*1000) and x<>num
selected=x
place2=rnd(GENE_LENGTH-1)+1
place1=place2-1
place3=GENE_LENGTH-place2
if val(mid$(population$(selected),place2))>0 or mid$(population$(selected),place2)="0"
replace$=str$(rnd(9))
else
replace=rnd(3)+10
if replace=10 then replace$="+"
if replace=11 then replace$="-"
if replace=12 then replace$="*"
if replace=13 then replace$="/"
endif
temp$=population$(selected)
population$(selected)=left$(temp$,place1)+replace$+right$(temp$,place3)
endif
next x
endfunction
function calculate(length)
total_fitness#=0.0
temp=(length-1)/2
for x=1 to POP_SIZE
first$=mid$(population$(x),1)
for y=1 to length step 2
operator$=mid$(population$(x),y+1)
second$=mid$(population$(x),y+2)
if operator$="+" then first$=str$(val(first$)+val(second$))
if operator$="-" then first$=str$(val(first$)-val(second$))
if operator$="*" then first$=str$(val(first$)*val(second$))
if operator$="/" then first$=str$(val(first$)/val(second$))
next y
pop_calculated(x)=val(first$)
pop_fitness(x)=1.0/(1.0+abs(GOAL-pop_calculated(x)))
total_fitness#=total_fitness#+pop_fitness(x)
first$=""
next x
avg_fitness#=0.0
avg_fitness#=total_fitness#/POP_SIZE
endfunction
function generate_population(pop,length)
dim population$(pop)
dim pop_calculated(pop) as float
dim pop_fitness(pop) as float
dim selections(2)
for amount=1 to pop
for bits=1 to length
`if placement is odd, bit is a number
if bits mod 2 <> 0
bit=rnd(9)
result$=result$+str$(bit)
else
`if placement is even, bit is an operator
bit=rnd(3)+10
if bit=10 then result$=result$+"+"
if bit=11 then result$=result$+"-"
if bit=12 then result$=result$+"*"
if bit=13 then result$=result$+"/"
endif
next bits
population$(amount)=result$
result$=""
next amount
endfunction
Update 2:
I've changed the 'calculate' function to either calculate on a single-gene, or to do every one. I may change it so it uses a loop either way, like 'calculate(first,second)', so it can be either 1 to POP_SIZE, or something like 54 to 54 for a single gene. Anyways, here's the newest version (now MUCH faster at twice the POP_SIZE):
Rem ***** Main Source File *****
Rem Project: GA5
Rem Created: 4/10/2010 8:19:03 PM
#constant POP_SIZE 100.0
#constant GENE_LENGTH 11.0
#constant CROSSOVER 0.7
#constant MUTATION 0.1
global total_fitness#
global avg_fitness#
global GOAL as float
global loop_counter
GOAL=rnd(1000)+1000
set text opaque
generate_population(POP_SIZE,GENE_LENGTH)
calculate(0,1)
do
crossover()
mutate()
calculate(0,1)
fitness()
inc loop_counter
display(loop_counter)
total_fitness#=0
loop
function fitness()
total_fitness#=0.0
avg_fitness#=0.0
for x=1 to POP_SIZE
total_fitness#=total_fitness#+pop_fitness(x)
next x
avg_fitness#=total_fitness#/POP_SIZE
endfunction
function display(num)
set cursor 0,0
print str$(avg_fitness#)
print GOAL
remstart
if loop_counter mod 250=0 and loop_counter>0
filenum=loop_counter/250
file$=str$(filenum)
open to write filenum,file$
write string filenum,str$(GOAL)
write string filenum,str$(avg_fitness#)
debug=1
endif
remend
for x=1 to POP_SIZE
if pop_fitness(x)>=oldpop#
oldpop#=pop_fitness(x)
highest=x
endif
if pop_fitness(x)=1.0
sol$=population$(x)
sol=x
endif
if debug=1
write string filenum,population$(x)
write string filenum,str$(pop_calculated(x))
write string filenum,str$(pop_fitness(x))
write string filenum," "
endif
next x
if debug=1 then close file filenum
print "Best solution: "+population$(highest)+"="+str$(pop_calculated(highest))+" "
print "Highest fitness: "+str$(pop_fitness(highest))+" "
print "Generation Number: "+str$(num)+" "
if sol$<>"" : print "Solution found: "+population$(sol)+"="+str$(pop_calculated(sol)) : wait mouse : end : endif
endfunction
function crossover()
for total=1 to POP_SIZE
cross=rnd(10)
if cross<=(CROSSOVER*100)
for elitism=1 to POP_SIZE
if highest#<=pop_fitness(elitism)
highest#=pop_fitness(elitism)
num=elitism
endif
next elitism
redo:
for get_two=1 to 2
for x=1 to POP_SIZE
cross_chance#=(pop_fitness(x)/total_fitness#)*100 `1 to 100
cross_limit#=rnd(100)
if cross_limit#<=cross_chance#
selections(get_two)=x
endif
next x
next get_two
if selections(1)=selections(2) then goto redo
if selections(1)=0 or selections(2)=0 then goto redo
if selections(1)=num or selections(2)=num then goto redo
place=rnd(GENE_LENGTH-2)+2
place2=GENE_LENGTH-place
temp1$=population$(selections(1))
temp2$=population$(selections(2))
population$(selections(1))=left$(temp1$,place)+right$(temp2$,place2)
population$(selections(2))=left$(temp2$,place)+right$(temp1$,place2)
calculate(selections(1),0)
calculate(selections(2),0)
endif
next total
endfunction
function mutate()
for elitism=1 to POP_SIZE
if highest#<=pop_fitness(elitism)
highest#=pop_fitness(elitism)
num=elitism
endif
next elitism
for x=1 to POP_SIZE
mutate_limit#=rnd(1000)
if mutate_limit#<=(MUTATION*1000) and x<>num
selected=x
place2=rnd(GENE_LENGTH-1)+1
place1=place2-1
place3=GENE_LENGTH-place2
if val(mid$(population$(selected),place2))>0 or mid$(population$(selected),place2)="0"
replace$=str$(rnd(9))
else
replace=rnd(3)+10
if replace=10 then replace$="+"
if replace=11 then replace$="-"
if replace=12 then replace$="*"
if replace=13 then replace$="/"
endif
temp$=population$(selected)
population$(selected)=left$(temp$,place1)+replace$+right$(temp$,place3)
endif
next x
endfunction
function calculate(gene_num,all)
temp=(GENE_LENGTH-1)/2
if all=1
for x=1 to POP_SIZE
first$=mid$(population$(x),1)
for y=1 to GENE_LENGTH
operator$=mid$(population$(x),y+1)
second$=mid$(population$(x),y+2)
if operator$="+" then first$=str$(val(first$)+val(second$))
if operator$="-" then first$=str$(val(first$)-val(second$))
if operator$="*" then first$=str$(val(first$)*val(second$))
if operator$="/" then first$=str$(val(first$)/val(second$))
next y
pop_calculated(x)=val(first$)
pop_fitness(x)=1.0/(1.0+abs(GOAL-pop_calculated(x)))
next x
else
first$=mid$(population$(gene_num),1)
for y=1 to GENE_LENGTH
operator$=mid$(population$(gene_num),y+1)
second$=mid$(population$(gene_num),y+2)
if operator$="+" then first$=str$(val(first$)+val(second$))
if operator$="-" then first$=str$(val(first$)-val(second$))
if operator$="*" then first$=str$(val(first$)*val(second$))
if operator$="/" then first$=str$(val(first$)/val(second$))
next y
pop_calculated(gene_num)=val(first$)
pop_fitness(gene_num)=1.0/(1.0+abs(GOAL-pop_calculated(gene_num)))
endif
endfunction
function generate_population(pop,length)
dim population$(pop)
dim pop_calculated(pop) as float
dim pop_fitness(pop) as float
dim selections(2)
for amount=1 to pop
for bits=1 to length
`if placement is odd, bit is a number
if bits mod 2 <> 0
bit=rnd(9)
result$=result$+str$(bit)
else
`if placement is even, bit is an operator
bit=rnd(3)+10
if bit=10 then result$=result$+"+"
if bit=11 then result$=result$+"-"
if bit=12 then result$=result$+"*"
if bit=13 then result$=result$+"/"
endif
next bits
population$(amount)=result$
result$=""
next amount
endfunction