At the forefront of Artificial Intelligence
  Home Articles Reviews Interviews JDK Glossary Features Discussion Search
Home » Articles » Genetic Algorithms » Applications/Code

Genetic Algorithm with Floating Point in Assembler

By Manabu Ishii

Purpose

The purpose of this article is introduce how to make Genetic Algorithm @asm, and how to make assembly program, and my English skill up. I don't have good English and enough knowledge about GA and FP. By writing this article, I'll teach about GA, FP, and English to me. If you read this, soon you notice that I like to use "don't know". When I use the words, I really don't know (hmm this is first time, you see). If you know about it please teach it to me, and I want to fix it.

When I started writing this article, I was going to make the series of lesson. But during writing, this article became one article by itself. So something strange is appeared in place. If you have enough time and enough perseverance, I want you to read through the whole article at first. And read again, then you can understand...I hope so.

Compiler

I use NASM.

First

First program we make is only quit. Nothing is done. But it's important how to know quit. Following code is ga001.asm:
--- ga001.asm ---
	org 0100h
start:
; quit program.
	ret
--- ga001.asm ---
Line 1 is declaration that this program start at 0100h.
Line 2 is the label, if you want to back to start, you can use this label.
Line 3 is comment. At nasm ';' is comment start and anything after this is ignored.
Line 4 is command which is only this program have. And this statement( command ) is quit the program (exactly it has described another expression... but now I use it for QUIT the program).

Compile

Next, how to compile it ?
--- cut ---
nasm -f bin -o ga001.com ga001.asm
--- cut ---

Run

How to use it? Let's invoke:
--- magic word ---
ga001
--- magic word ---
Screen shot isn't available...but something like this.
--- screen mimic ---
C:\gaasm>nasm -f bin -o ga001.com ga001.asm

C:\gaasm>ga001

C:\gaasm>
--- mimic is dead ---
Umm, it works well, but there's nothing...like Japanese Bank's rates of interest.

Before making GENE pool

We must construct the GENE pool and filled it random numbers. Method of random number generating is alot of type. It's heavy factor of GA, though I currently choose easy one which is work. Of course you can prepare own fantastic random routine. To randomize I use following interupt (DOS only):
--- from Ralf's interupt list ---
AH = 00h

Return:
CX:DX = number of clock ticks since midnight
AL = midnight flag, nonzero if midnight passed since time last read
--- from Ralf's interupt list ---
How to invoke:
--- randomize ---
;randomize   initialize rand seed
	xor ah,ah		; ah = 0
	int 1Ah			; get date and time
--- randomize ---
Umm, Why 'xor ah,ah' makes ah = 0 ? 'XOR' is exclusive OR .
---XOR----
A | B | R
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0
---XOR----
As you see, if A and B is same (A is set and B is set or, both is unset). Result is 0 and if A and B isn't same, Result = 1. If we take ah as A, and ah as B, all bits are the same, so ah = 0.

Feed seed:

--- feed seed ---
; dx is wide range
; cx is small...?
; so we take cx as 1st seed and dx as 2nd seed
	mov [seed1],cx		; save seed1
	mov [seed2],dx		; save seed2
--- feed seed ---
Now Random generating routine have gotten two seeds. I made following routine, I don't know it work pretty well. But as far as I dumped, It seem to work enough well and pretty complex to explain it...So I don't explain it :), plz don't complain for my lazy.
--- random generate ---
; generate random number
;  return
;	ax = number
random:
	db 0b8h	; mov ax,seed1
seed1:	db 0,0

	dec ax	; decrement
	
randloop:
	db 35h	; xor ax,seed2
seed2:	db 0,0
	inc ax	;
	xchg ah,al
	xor [seed2],ax	; 0.092
	sub ax,[seed1]
	rol al,1	; 0.091
	xchg ah,al	; 0.092
	sub [seed1],ax	; change seed1
	ret
--- random generate ---
ver 0.091, I fix 'rol al,1' to 'ror al,1', it works better?
ver 0.092, 'xchg ah,al' before 'sub [seed1],ax'. 'xor [seed2],ax' before 'sub ax,[seed1].

Hi ppl, now we can generate any random number (I hope so ...) Finally, we stand the START line. Let's make GENE POOL !!

But before make GENE POOL, we have something to decide. Because what kind of gene expression we use is important. And it's depend on PROBLEM which we solve. Umm, making problem is harder than solve it :)...joke. I make 1 problem. It's a find the minimum value of fuction which has some Sin/Cos functions. I want to choose easy one. Everyone can understand where is the minimum, and if the function have LOCAL minimum is better. Exactly I don't have any idea of function's shape. So it's come back later. But I decide the range of search space between to 0 to 1. I make start line, only we need is the whistle ( NOT **'s whistler :-)

To make GENE POOL

First we decide the number of population. ( hmm, there is another problem ) I don't know how range I can use ... So I gather 100 population for our system.
--- something from 004 ---
POPULATION equ 100	; population of pool
--- end of c&p ---
This line is the population. If you want change population, you can take any number. ( I don't know where is limit ...) We decide the number of population. We make the pool with GENEs. Following code is pool maker .
--- this is pool maker ---
	mov cx,POPULATION * 4	; why multiply by 4 ? A gene have 4 byte (32 bit)!
	mov di,randnum
loop1:
	call random		; generate random number
	stosb			; we store the number which we generate to [di]
	loop loop1
--- this is pool maker ---
cx is which time we loop(s). stosb is value of AL into address which is indicated by di. Now we have made the pool full of GENEs.

Evaluate

How do we evaluate it ? hmm I copied this from test functions
--- here's function ---
Rosenbrock's Saddle

F(x) = Sum(i=1,n) { 100*(x_(i+1)-x_i^2)^2 + (1-x_i)^2 } 

-2.048 .le. x_i .le. 2.048 

Minimum = 0.0 at x_i=1.0
This function has a long curved valley which is only slightly decreasing.
--- here's function ---
I decide when i = n, (i+1) = ( i + 1 ) mod i ,(ie. result 1 ). And n = 2.So if I write 'y', 'y' means 'x+1' . So fomula is following
--- extract function ---
F(x) = Sum(i=1,n) { 100*(x_(i+1)-x_i^2)^2 + (1-x_i)^2 } 
     = { 100 * ( y - x ^ 2 ) ^ 2 + ( 1 - x ) ^ 2 } 
     + { 100 * ( x - y ^ 2 ) ^ 2 + ( 1 - y ) ^ 2 }
--- extract function ---
First we have x and y between -2.408 to 2.048 How do we implement this limitation ? Remeber the remainder. If we divide the number by 4 and take the remainder of this, we get the number which range is between 0 to 3. So we have divide the number, which gene express, by 4096( 2048*2 ). following code is :
--- set up x ---
; setup x between -2048 to 2048
	fild dword [ range ]	; store denominator (4096, we need between 0 to 4096 )
	fild dword [ di ]	; get gene for x
	fabs			; absolute 'ST0'
	fprem			; 0 < 'ST0' < 4096
	fild dword [ rangef ]	; st0 = 2048, st1 = 0 < x < 4096
	fsubp st1,st0		; -2048 < 'ST0' < 2048
; setup x between -2.048 to 2.048
	fidiv word [ para2 ]
--- set up x ---
do the same, make y .
--- set up y ( x + 1 ) ---
; setup y between -2048 to 2048
	fild dword [ range ]	; store denominator (4096, we need between 0 to 4096 )
	fild dword [ di + 4 ]	; get gene for y
	fabs			; absolute 'ST0'
	fprem			; 0 < 'ST0' < 4096
	fild dword [ rangef ]	; st0 = 2048, st1 = 0 < y < 4096
	fsubp st1,st0		; -2048 < 'ST0' < 2048
; setup y between -2.048 to 2.048
	fidiv word [ para2 ]
--- set up y ---

Currently we have 4096 in two stacks. and we don't need them. so pop them. Oops I did it again ... We load integer value and divide by integer ,so we get remainder as integer value. So we only have 4096 diffent value... It's too narrow. I solve this problem with division 1000000. Following code is revised:
--- division ---
	fabs			; absolute 'ST0'
	fdiv dword [ million ]	; ver 0.094
	fprem			; 0 < 'ST0' < 4096
--- division ---
Of course, we do this both x and y . I notice that problem is between 'dd 1000000.0' and 'dd 1000000'. for example:
--- datas ---
million:  dd 1000000.0
million2: dd 1000000
--- datas ---


--- code ---
	fld dword [ million ]
	fld dword [ million2 ]
--- code ---


--- result ---
st0=+1.401298E-0039 st1=+1.000000E+0006
--- result ---
hmm, I think these aren't same value... If you make something floating point value, I suggest you ( of course me ) to pay attention to this .
--- pop ---
; pop two 4096(s)
	fxch st0,st3		; st0 ,st1 = 4096
	fcompp			; pop st0,st1
--- pop ---
Next we calculate "x_i^2"
--- calculate perm 1 ---
; we have st0 = x, st1 = y
; load x
	fld st0
; x^2
	fmul st0		; x^2
--- calculate perm 1 ---


--- calculate 2 ---
; load y
	fld st2
; y - x_i^2
	fsubrp st1
--- calculate 2 ---


--- calculate 3 ---
;( y - x ^ 2 ) ^ 2
	fmul st0
;100 * ( y - x ^ 2 ) ^ 2
	fimul word [ para1 ]
--- calculate 3 ---


--- calculate 4 ---
; 1 - x
	fld1
	fsub st2
; ( 1 - x ) ^ 2
	fmul st0
--- calculate 4 ---


--- calculate 5 ---
;{ 100 * ( y - x ^ 2 ) ^ 2 + ( 1 - x ) ^ 2 } 
	faddp st1
--- calculate 5 ---

Do the same manner, when we calculate '{ 100 * ( x - y ^ 2 ) ^ 2 + ( 1 - y ) ^ 2 }'. Code is following, but I don't explain it anymore.
--- calculate 6 ---
; load y
	fld st2
; y^2
	fmul st0		; y_i^2
; load x
	fld st2
; x - y^2
	fsubrp st1
;( y - x ^ 2 ) ^ 2
	fmul st0
;100 * ( y - x ^ 2 ) ^ 2
	fimul word [ para1 ]
; 1 - x
	fld1
	fsub st3
; ( 1 - x ) ^ 2
	fmul st0
;{ 100 * ( y - x ^ 2 ) ^ 2 + ( 1 - x ) ^ 2 } 
	faddp st1
--- calculate 6 ---
So we finish calculating perms. Finally, we add them. And store it to [si].
--- sum up & store ---
; store fitness to [si]
	fstp dword [si]
--- sum up & store ---
When we have stored the fitness value. But we have 2 value in FP stack . So we pop them ,and return .
--- finalize ---
	fcompp
	ret 
--- finalize ---

Selection

Hey, fitness value is finished. We must select the adam and eve with fitness value. ( hmm if they didn't eat apple, they must not select with fitness :) We shoot she and he with roulette .

Roulette Selection Algorithm.

Before start this section.I change little bit ,but it's important. By now, I used the size of gene with 4, it's constant. This isn't good . When we change the genesize, all 4 turn to new size in source code. So I make it CONSTANT .
--- gene size ---
GENESIZE equ 4
--- gene size ---
If you want to change size of gene, only change this line. All line will be affected, WHEN you RECOMPILE it . ( it's often occured for me, source is updated, but execute isn't updated ... ) Let's get back to the feature ! I choose the roulette selection. But there are various selection algo. I don't know why I choose it :). But I choose it . Tactics is following
  1. sum up the all fitness ( total )
  2. make random number between 0 to total.
  3. compare one's fitness and total
  4. if one's fitness is less than total, total = total - fitness and goto 3
  5. copy this indivisual to parent1
  6. do the same 3 - 5 to make parent2
umm But, much of debuggind time brought me some fatal bug... If following routine is made, great value is occupied wide range seat. Luckily, I found solution. To take a reciprocal number . And always before calculatition, we take a reciprocal number . No other change is needed. But this leave us big problem ,if we choose this solution forever, we always must change this routine. In future ( isn't so long ), I'll standardize it to something. This is flow of my routine. Seeing is believing.
--- roulette selection initialize ---
selection:
; Roulette selection
; initialize
	fldz			; total
	mov di,fitness		; start address of fitness value
	mov cx,POPULATION	; number of POPULATION
--- roulette selection initialize ---
Umm, initializing routine is quite quiet. 'fldz' loads 0 to st(0) .
--- roulette selection 1 ---
; calculation total fitness
rouletteloop1:
	fld1			; 0.092
	fld dword [di]		; load fitness
	fdivp st1		; 0.092
	faddp st1		; sum up fitness
	add di,4		; to point next fitness
	loop rouletteloop1
--- roulette selection 1 ---
2 line have its comment with '0.092'. This is fixed version to calculate a reciprocal.
This loop is looped by POPULATION times.And when loop is finished, st0 have total.
So I explain about 'fld1', 'fld dword [di]', 'fdivp st1', and 'faddp st1'.
Before we start this, we initialized FPU STACK with 'fldz'.So st(0) = 0.0 (after 'fldz')
--- stack ---
before 'fld1'           - st(0) = 0
'fld1'                  - st(0) = 1, st(1) = 0
'fld dword [di]'        - st(0) = gene(0)'s fitness value, st(1) = 1 ,st(2) = 0
'fdivp st1'             - st(0) = a reciprocal of gene(0)'s fitness   ,st(1) = 0
'faddp st1'             - st(0) = a reciprocal of gene(0)'s fitness
--- stack ---
st(0) 's value ( this time was 0 ) push to st(1), and st(0) have gene(0)'s fitness value, indicated by [di] .

Next 'faddp st1' is done .
st(1) = st(1) + st(0), and pop st(0), so st(1) have nothing, st(0) have fitness value.

Then di = di + 4, so [di] indicates next genes fitness value.And loop .
When loop ends, st(0) have total fitness .
Next we make random number between 0 to total.

--- roulette selecion 2 ---
; roulette start
	call random		; generate random
	mov [ randtmp ], ax	; save random to temp
	fild dword [ randtmp ]	; load random number from temp
	fild dword [ randmax ]	; load maximum number of random
	fdivp st1		; st1 / st0 ( random / maximum ), this 
                                ; make 0 < random < 1
	fmul st1		; 0 < target < total fitness
--- roulette selecion 2 ---
this formula is all : target = ( random number / maximum random number ) * total
By doing this ,we know where is target .So we can choose adam.
--- FPU STACK is something like ... ---
call random		- st(0) = total fitness
mov [ randtmp ], ax	- st(0) = total fitness
fild dword [ randtmp ]	- st(0) = random number, st(1) = total fitness
fild dword [ randmax ]	- st(0) = RANDOM MAX   , st(1) = random number, 
                          st(2) = total fitness
fdivp st1		- st(0) = 0 < random < 1, st(1) = total fitness
fmul st1		- st(0) = 0 < random < total fitness, st(1) = total fitness
--- FPU STACK is something like ... ---
Next we have some initialization.
--- roulette selection before3 ---
; seek lucky adam
	mov cx,POPULATION	    ; number of POPULATION
	mov si,randnum - GENESIZE   ; start address of gene pool - GENESIZE (1 previous)
	mov di,fitness - 4	    ; start address of fitness value - 4 (1 previous)
--- roulette selection before3 ---
Why [ - GENESIZE ] ? Why [ - 4 ] ? We compare the chanpion ( current minimum ) and target ( canditate ) . At first Following code will do, add GENESIZE or 4. To do this, next indivisual is target canditate. So if we set " randnum " only, the first indivisual isn't investigated .
--- roulette selection 3 - 4 ---
rouletteloop2:
	add si, GENESIZE	; next gene
	add di,4		; next fitness
	fld1			; 0.092
	fld dword [di]		; load fitness
	fdivp st1		; 0.092
	fcom st1		; 
	fnstsw ax		; during st0 < st1 ,ah = ???????1. 
                                ; if st0 > st1 ah = ???????0
	and ah,1		; check condition
	fsubp st1,st0		; substract st1 - st0 and result store 
                                ; in st1 but 1 pop occur st0 have finally result 
	loopnz rouletteloop2	; cx = cx - 1. if cx isn't 0 but zeroflag is clear,
                                ; exit loop
--- roulette selection 3 - 4 ---
Firstly, increment canditate. and calculate a reciprocal of its fitness( fld1 ... fdivp ).
And compare with total (fcom st1 ).
Next line 'fnstsw ax' is tricky. This is load FPU STATUS into 'AX' .
As comment say, we only need 1 flag ( of FPU STATUS ), which is at bit 0 of ah.
After loading FPU STATUS into AX, we check bit 0 of ah .
With "and ah,1"
If bit 0 of ah is clear(0), zero flag is clear .
If bit 0 of ah is set(1), zero flag is set.
Next (fsubp ...) is total = total - fitness. By doing this ,total down to 0 .
And if total is enough small, someone's fitness is grater than total.He is ADAM :)

We met adam, so we want him to meet eve under the apple tree . So we pick up him from pool ( he can't swim well )

--- roulette selection 5 ---
; now [ si ] is adam's gene
	mov di, parent1		; here's seat for him
	mov cx, GENESIZE	; to copy gene, cx have genesize (byte)
	rep movsb		; do copy
	fcomp	st1		; adios adam
--- roulette selection 5 ---
We copy GENESIZE ( bytes). 'rep movsb' do: [ di ] = [ si ]. di = di + 1, si = si + 1. (exactlly di and si is affected flag...but now I don't explain it ) This is a half of way .But another half is same. Only diffrence is before 'ret' isn't 'fcomp st1' . The line before 'ret' is 'fcompp' ( 2 stack is poped ) Making offspring The main stream is 1. select parents 2. crossover choosen parents 3. go to 1 until next generation is full. I don't want cx and di to destroy. So I use push and pop to save them. The code will explain by itself :)
--- maker ---
; making offspring loop
; init
	mov cx, POPULATION	; loop counter for  next generation
	mov di, offspring	; next swimmers warming up room
makeoffspring:
	push cx
	push di
	call selection		; selecti parents by ROULETTe alGo
	pop di
	call crossover		; corssover by uniform crossover
	add di, GENESIZE	; next position
	pop cx
	loop makeoffspring
--- maker ---
Where is 'crossover' ?, Next ! Crossover We have choosen both parents ( sometimes parent... )
--- crossover ---
; uniform crossover
;   parent1, parent2 is gene
;   di = offsprring ( destination address )
; broken:
;	ax,bx,cx,dx
--- crossover ---
Umm, these are comments.
--- crossover 1 ---
crossover:
        xor bx,bx			; indicator ( counter ) reset
--- crossover 1 ---
bx is used for indicator which we are treating and also store the offspring.
--- crossover 1.5 ---
crossover0:
	mov cx,8			;1 byte is 8 bit.
--- crossover 1.5 ---

Why cx is 8 ? caz 1 byte is 8 bits. So we can loop whole a byte.
--- crossover 2 ---
crossover1:
        call random			; generate random number
        shr al,1			; check even or odd
        jc crossover2			; if odd (ie carry flag is set ), take parent2
        mov al, [ parent1 + bx ]	; because even, take parent1
        jmp crossover3			; go to set
crossover2:
        mov al, [ parent2 + bx ]	; take parent2
crossover3:
--- crossover 2 ---
First call random, and check the number is odd or even. The probability is half and half. If odd we take parent2, so jump. If even, we take parent1 .And pass through parent2 routine.
--- crossover 3 ---
	shl al,cl			; shift al left by cl times
	rcr dl,1			; rotate dl including carry flag by 1
--- crossover 3 ---
This is something tricky for non-assembler experience users. First shift al ( which have parent we choose ) left cl times . So al's ( 8 - cx ) bit go to carry flag. Second rotate dl 1 times to right, according to this dl's 7 bit is same carry flag.
--- crossover 4 ---
	loop crossover1			; cx = cx -1
--- crossover 4 ---
This pattern is repeated 8 times ( 1 byte is 8 bit )
--- crossover 5 ---
	mov [di + bx],dl		; save it as gene
        inc bx
        cmp bx, GENESIZE
        jnz crossover0
--- crossover 5 ---
After looping, we have made 1 byte. So we store it as offspring's gene. And counter is increased. If counter( this case 'bx' ) isn't GENESIZE, loop back to crossover0.
--- crossover 6 ---
	ret
--- crossover 6 ---
Bye bye crossover routine!

Mutation

Firstly we decide how often mutation occurs. I take 0.001 for this. I think it's good that rate is between 0 to 1 ( 0 =< rate =< 1 )
--- mutationrate ---
mutationrate:	dd 0.001	; mutation rate
--- mutationrate ---
Secondly, we initialize for mutation routine. Almost of initialization routine is as same as crossover.
--- mutation initialize ---
; mutation
; di = offspring start address
mutation:
        xor bx,bx
mutation0:
        mov cx,8                ;1 byte is 8 bit.
--- mutation initialize ---
Next, we want rancom number between 0 to 1 . Remember we made this routine before.So copy and paste. And modify it for this routine. And to compare, we must load mutationrate .
--- mutation 1 ---
	call random		; generate random
	mov [ randtmp ], ax	; save temp
	fld dword[ mutationrate ]	; load mutationrate
	fild dword [ randtmp ]	; load random number from temp
	fild dword [ randmax ]	; load maximum number of random
	fdivp st1		; st1 / st0, this make 0 < random < 1
--- mutation 1 ---
Next we compare mutationrate and random number. If mutationrate > random number then mutation occur. If mutationrate < random number then mutation does not occur. well if mutationrate = random number ?, hehe homework :)
--- stack ---
fld dword[ mutationrate ] - st(0) = mutation rate
fild dword [ randtmp ]    - st(0) = random number, st(1) = mutation rate
fild dword [ randmax ]	  - st(0) = RAND_MAX, st(1) = random number st(2) = mutation rate
fdivp st1		- st(0) = random number / RNAD_MAX, st(1) = mutaion rate
--- stack ---
--- mutation 2 ---
	fcompp			; compare and pop st0 ,st1
	fnstsw ax		; during st0 < st1 ,ah = ???????1. if st0 > 
                                ; st1 ah = ???????0
	shr ah,1		; bit 0 of ah -> carry flag
	rcr dl,1		; save carry flag
        loop mutation1		; do this 1 byte( ie 8 times )
--- mutation 2 ---
Flag condtion is at ah's bit 0. So we did 'shr ah,1', carry flag have condition. And 'rcr dl', 'dl' have condtion . If there is mutaion, 'dl' have '1' on that bit.
--- mutation 3 ---
        xor [ di + bx ], dl	; Do MUTATION
--- mutation 3 ---
So we know where is mutation when we investigate with 'dl'. 'xor' make the mutation .
--- mutation 4 ---
        inc bx			; next position
        cmp bx,GENESIZE		; it's end?
        jnz mutation0		; if it's not end, we go back to 'mutation0'.
--- mutation 4 ---
Do these routines until whole gene.

MainLoop

Finally, we make all element of GA .So We make main loop . The main loop is most important factor which is when GA is end . But this time, I decide to loop 10000 times, if the best optimal solution is found. Of course, you can implement the main loop is end when the best solution is found.
--- mainloop 1 ---
; mainloop start
        mov cx, 10000   ; main loop counter
mainloop:
        push cx         ; save main loop counter 
--- mainloop 1 ---
Why 'push cx' ?, caz 'cx' might be destroy during loop.So we save it.
--- mainloop 2 ---
; calculate all fitness
        mov cx, POPULATION
        mov di, randnum
        mov si, fitness
loop2:
        call evaluate
        add di, GENESIZE        ; ver 0.06
        add si,4
        loop loop2
--- mainloop 2 ---
Each gene's fitness is calculated and stored.
--- mainloop 3 ---
; making offspring loop
; init
        mov cx, POPULATION      ; loop counter for  next generation
        mov di, offspring       ; next swimmer warming up room
makeoffspring:
        push cx
        push di
        call selection          ; selection by ROULETTe alGo
        pop di
        call crossover          ; corssover by uniform crossover
        call mutation           ; mutation
        add di, GENESIZE        ; next offspring's position
        pop cx
        loop makeoffspring
--- mainloop 3 ---
Make next generation.
--- mainloop 4 ---
; judgement gene reach to goal ?
        pop cx			; load loop counter
        push cx			; save again
        cmp cx,1		; if the loop is end this time
        jnz changepool  	; if the loop is continued, go to next.
        call judgement		; search best fitness
--- mainloop 4 ---
Once we load counter and check it if this time is end . Umm, this is dirty way... But now, I remain it. If loop is continued, we go to next . If loop is end this time, we search best fitness.
--- mainloop 5 ---
; change gene to new.
changepool:
        mov di, randnum			; old gene pool
        mov si, offspring		; new gene are here.
        mov cx, POPULATION * GENESIZE	; size of pool
        rep movsb			; Do change
--- mainloop 5 ---
We have made new gene pool, and change old pool with new one.
--- mainloop 6 ---
        pop cx			; counter is back
        loop mainlooop		; loop
--- mainloop 6 ---
This is the entire mainloop routine. But where is 'judgement' routine ? Follow me !

Judgement

These code is used for judgement. Usually, judgement routine check whether any solution satisfies end condition . But this doesn't check it. Only search minimum solution .
--- judgement initialize ---
; judgement
;  this version is to search minimum value of fitness.
;  return 
;       si = best gene address
;       dx = best fitness value address
judgement:
        mov bx, randnum			; bx = start address of gene
        mov si,bx			; si = bx
        mov di, fitness		; dx = start address of fitness value
        mov dx,di			; di = dx
        mov cx, POPULATION - 1		; cx is loop counter
        fld dword [ di ]		; first fitness is loaded
--- judgement initialize ---
Above section is initialized routine.
--- judgement 1 ---
judgement1:
        add bx, GENESIZE                ; next gene
        add di, 4                       ; next fitness
        fld dword [ di ]                ; load fitness value
        fcom st1                        ; compare st0( current ) and st1 ( minimum )
        fnstsw ax			; st0 < st1 ,ah = ???????1. st0 > 
                                        ; st1 ah = ???????0
        shr ah,1			; check ah
        jnc judgement2
        mov dx,di                       ; save address of fitness value
        mov si,bx                       ; save address of gene
        fxch st0,st1			; exchange minimum value
judgement2:
        fcomp st1			; poped
        loop judgement1
        fcomp st1			; poped
        ret
--- judgement 1 ---

Tactics is following

  1. we have the front gene's fitness value and gene address.
  2. compare it to next gene's fitness and if next is smaller (higher) than it
    we have smaller (higher) one's fitness and gene address.
  3. go to 1.
This is all.

Conclusion?

For the present, we could make GA system.But there are many of possibility. Something, single point mutation, elitism, island model etc... If you have something interesting, I'm glad.

Future Plan

(Now there is a lot of hope for optimization)
  • Make Smaller if only 1 byte and Speed up if can.
  • Some problem in this article revealed will be fixed.
  • I want this code run under pmode or something like that... to have wide range memory
  • And I want to have SCRIPT LANGUAGE.
  • Export to another platform.
Let's enjoy coding!

  • gaasm.zip - Source code and article (14.2Kb).

Submitted: 27/02/2001

Article content copyright © Manabu Ishii, 2001.
 Article Toolbar
Print
BibTeX entry

Search

Latest News
- Generation5 10-year Anniversary (03/09/2008)
- New Generation5 Design! (09/04/2007)
- Happy New Year 2007 (02/01/2007)
- Where has Generation5 Gone?! (04/11/2005)
- NeuroEvolving Robotic Operatives (NERO) (25/06/2005)

What's New?
- Back-propagation using the Generation5 JDK (07/04/2008)
- Hough Transforms (02/01/2008)
- Kohonen-based Image Analysis using the Generation5 JDK (11/12/2007)
- Modelling Bacterium using the JDK (19/03/2007)
- Modelling Bacterium using the JDK (19/03/2007)


All content copyright © 1998-2007, Generation5 unless otherwise noted.
- Privacy Policy - Legal - Terms of Use -