/* 

GASample - Sample of Genetic Algorithm 
Copyright (C) 2004 youjin lee(justbear@naver.com) 

This library is free software; you can redistribute it and/or 
modify it under the terms of the GNU Lesser General Public 
License as published by the Free Software Foundation; either 
version 2.1 of the License, or (at your option) any later version. 

This library is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
Lesser General Public License for more details. 

You should have received a copy of the GNU Lesser General Public 
License along with this library; if not, write to the Free Software 
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

*/ 

import java.util.Collections; 
import java.util.Comparator; 
import java.util.LinkedList; 

/** 
* <code>Organism</code>(»ý¹°Ã¼) Å¬·¡½º´Â °³°³ÀÇ »ý¹° °³Ã¼¸¦ ³ªÅ¸³À´Ï´Ù. 
* °¢ »ý¹°Ã¼´Â ¿°»öÃ¼(chromosome)¸¦ °¡Áö°í ÀÖÀ¸¸ç À¯ÀüÀ» ÇÒ¶§ ºÎ¸ðÀÇ ¿°»öÃ¼°¡ 
* ¼­·Î ²¿¿©¼­(crossover) »õ·Î¿î À¯ÀüÀÚ Á¤º¸¸¦ °¡Áø ÀÚ½ÄÀ» ¸¸µé¾î ³À´Ï´Ù. 
* @author <a href="mailto:justbear@naver.com">justbear</a> 
*/ 
class Organism { 
/** 
* »ý¹°Ã¼ÀÇ ¿°»öÃ¼(chromosome)¸¦ ³ªÅ¸³»¸ç, À¯ÀüÀÚ ¾Ë°í¸®Áò(Genetic Algorithm)¿¡ »ç¿ëÇÒ 
* ÆÄ¶ó¹ÌÅÍ ¹è¿­·Î »ç¿ëÇÕ´Ï´Ù. 
* int Å¸ÀÔÀ¸·Î °íÁ¤ÇÕ´Ï´Ù. 
*/ 
int[] chromosome; 

/** 
* fitness °ªÀ» ÀúÀåÇÏ´Âµ¥ »ç¿ëÇÕ´Ï´Ù. fitness¶õ ±¸ÇÏ°íÀÚ ÇÏ´Â ÇØ´ä°ú ¾ó¸¶³ª ÀûÁ¤ÇÑ°¡¸¦ 
* ³ªÅ¸³»´Â ÁöÇ¥·Î ¿©±â ¿¹¿¡¼­´Â ¼ýÀÚ°¡ 0¿¡ °¡±î¿ï¼ö·Ï ÇØ´ä°ú °¡±î¿î °ªÀÌ µË´Ï´Ù. 
*/ 
int fitness; 

/** 
* »ý¼ºÀÚ·Î½á GASample.CHROMOSOME_SIZE °³¼ö¸¸Å­ int ¹è¿­À» »ý¼ºÇÕ´Ï´Ù. 
* CHROMOSOME_SIZE¶õ °³°³ÀÇ »ý¹°Ã¼°¡ °¡Áö´Â ¿°»öÃ¼ÀÇ °³¼ö¸¦ ³ªÅ¸³À´Ï´Ù. 
*/ 
public Organism() { 
chromosome = new int[GASample.CHROMOSOME_SIZE]; 
} 
} 

/** 
* <code>OrganismComparator</code> Å¬·¡½º´Â ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ)À» Á¤·ÄÇÒ¶§ 
* »ç¿ëÇÕ´Ï´Ù. ComparatorÀÇ »ç¿ë¹ýÀº JDK API ¹®¼­¸¦ ÂüÁ¶ÇÏ¼¼¿ä. 
* @author <a href="mailto:justbear@naver.com">justbear</a> 
*/ 
class OrganismComparator implements Comparator { 
public int compare(Object o1, Object o2) { 
Organism c1 = (Organism) o1; 
Organism c2 = (Organism) o2; 
return c1.fitness - c2.fitness; 
} 
} 

/** 
* ÀÌ ¿¹Á¦´Â À¯ÀüÀÚ ¾Ë°í¸®ÁòÀ¸·Î ¹æÁ¤½ÄÀÇ ÀÎ¼ö °ªÀ» ±¸ÇÏ´Â ¹æ¹ýÀ» º¸¿©ÁÝ´Ï´Ù. 
* ¹æÁ¤½ÄÀº a+2b+3c+4d+5e=100 À¸·Î ÀÌ ½Ä¿¡ Àû´çÇÑ a, b, c, d, e °ªÀ» ±¸ÇÕ´Ï´Ù. 
* ÀÌ ½ÄÀº calculateFitness() ¸Þ¼Òµå¿¡¼­ º¸½Ç ¼ö ÀÖ½À´Ï´Ù. 
* @author <a href="mailto:justbear@naver.com">justbear</a> 
*/ 
public class GASample { 
/** 
* À¯ÀüÀÚ ¾Ë°í¸®Áò¿¡ »ç¿ëÇÒ OrganismÀÇ ÀüÃ¼ °³¼ö 
*/ 
private int POPULATIONS_SIZE = 2048; 

/** 
* À¯ÀüÀÚ ¾Ë°í¸®Áò¿¡¼­´Â »õ·Î¿î ¼¼´ë(Generation)°¡ ³ªÅ¸³¯ ¶§¸¶´Ù ¶Ù¾î³­ ÇüÁúÀ» °¡Áø 
* »ý¹°Ã¼´Â °è¼Ó »ýÁ¸ÇÏ¿© ±× ÇüÁúÀ» ÀÚ¼Õ¿¡¼­ À¯Àü½ÃÅ°°Ô µË´Ï´Ù. ELITISM_SIZE´Â ÀüÃ¼ 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) Áß¿¡¼­ ÀÚ½ÅÀÇ ÇüÁúÀ» °è¼Ó À¯ÀüÇÒ °´Ã¼ÀÇ °³¼ö¸¦ 
* ³ªÅ¸³À´Ï´Ù. Áï, ÀüÃ¼ »ý¹°Ã¼ Áß ELITISM_SIZE °³¼ö¸¸Å­ÀÇ ¶Ù¾î³­ »ý¹°Ã¼´Â ±× À¯ÀüÀÚ 
* Á¤º¸¸¦ º¯È­½ÃÅ°Áö ¾ÊÀº ºÎ¸ð ±×´ë·ÎÀÇ ÀÚ½ÄÀ» »ý¼ºÇÕ´Ï´Ù. 
*/ 
private int ELITISM_SIZE = 100; 

/** 
* ÇÑ ¿°»öÃ¼(chromosome)°¡ °¡Áö´Â ÃÖ´ë°ª 
*/ 
private int MAX_CHROMOSOME_DATA = 100; 

/** 
* »ý¹°Ã¼(Organism)°¡ °¡Áö´Â ¿°»öÃ¼(chromosome)ÀÇ °³¼ö 
*/ 
public static int CHROMOSOME_SIZE = 5; 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ)À» ³ªÅ¸³»´Â º¯¼ö 
*/ 
private LinkedList populations; 

/** 
* À¯ÀüÀÚ ¾Ë°í¸®Áò °è»ê¿¡¼­ »ç¿ëÇÏ´Â ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) º¯¼öÀÇ ¹öÆÛ 
*/ 
private LinkedList buffer; 

/** 
* GASample »ý¼ºÀÚ 
*/ 
public GASample() { 
doGA(); 
} 

/** 
* À¯ÀüÀÚ ¾Ë°í¸®ÁòÀ» ½ÇÇà 
*/ 
public void doGA() { 
initPopulations(); 

// ³¡³ª´Â Á¶°ÇÀÌ ¸ÂÀ» ¶§±îÁö ¹Ýº¹ÇÕ´Ï´Ù. 
while (true) { 
evaluate(); 
sortPopulations(); 
printOrganism(0); 
checkFinish(); 
elitism(); 
crossover(); 
mutate(); 
swap(); 
} 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ)À» ÃÊ±âÈ­ÇÔ 
*/ 
public void initPopulations() { 
populations = new LinkedList(); 
buffer = new LinkedList(); 

for (int i = 0; i < POPULATIONS_SIZE; i++) { 
populations.add(initOrganism()); 
} 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ)ÀÇ °¢ »ý¹°Ã¼ÀÇ fitness °ªÀ» ¼³Á¤ÇÕ´Ï´Ù. 
*/ 
public void evaluate() { 
for (int i = 0; i < POPULATIONS_SIZE; i++) { 
Organism c = (Organism) populations.get(i); 
c.fitness = calculateFitness(c.chromosome); 
} 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ)ÀÇ °¢ »ý¹°Ã¼(Organism)¸¦ fitness°¡ ³·Àº ¼øÀ¸·Î 
* Á¤·ÄÇÕ´Ï´Ù. fitness °ªÀÌ ³·À» ¼ö·Ï ´õ ¶Ù¾î³­, Áï Ã£°íÀÚ ÇÏ´Â ÇØ´ä°ú À¯»çÇÑ 
* »ý¹°Ã¼(Organism) ÀÔ´Ï´Ù. 
*/ 
public void sortPopulations() { 
// ¸Å¹ø Á¤·ÄÀ» ÇÒ¶§¸¶´Ù OrganismComparator °´Ã¼¸¦ »ý¼ºÇÏ´Â °ÍÀº ÁÁÁö ¾Ê½À´Ï´Ù. 
// Ã³À½¿¡ ÇÏ³ª »ý¼ºÇØ¼­ °è¼Ó »ç¿ëÇÏ´Â °ÍÀÌ ÁÁ½À´Ï´Ù. ¼³¸íÀ» À§ÇÏ¿© °£´ÜÈ÷ ÇÕ´Ï´Ù. 
Collections.sort(populations, new OrganismComparator()); 
} 

/** 
* ¹Ýº¹À» Áß´ÜÇÏ´ÂÁö¸¦ È®ÀÎÇÕ´Ï´Ù. ¹Ýº¹À» Áß´ÜÇÏ´Â °ÍÀº À¯ÀüÀÚ ¾Ë°í¸®Áò¿¡¼­ ´õÀÌ»ó »õ·Î¿î 
* ¼¼´ë(Generation)¸¦ »ý¼ºÇÏÁö ¾Ê´Â °ÍÀ» ÀÇ¹ÌÇÕ´Ï´Ù. Ã¹¹øÂ° »ý¹°Ã¼(Organism)ÀÇ fitness °ªÀÌ 
* 0ÀÎ °æ¿ì ÇÁ·Î±×·¥À» Áß´ÜÇÕ´Ï´Ù. 
*/ 
public void checkFinish() { 
Organism c = (Organism) populations.get(0); 
if (c.fitness == 0) 
System.exit(0); 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) Áß¿¡¼­ ¶Ù¾î³­ À¯ÀüÀÚ¸¦ Áö´Ñ »ý¹°Ã¼(Organism)¸¦ 
* ELITISM_SIZE °³¼ö¸¸Å­ ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) ¹öÆÛ¿¡ ÀúÀåÇÕ´Ï´Ù. 
*/ 
public void elitism() { 
for (int i = 0; i < ELITISM_SIZE; i++) { 
Organism c = new Organism(); 
c.chromosome = ((Organism) populations.get(i)).chromosome; 
c.fitness = ((Organism) populations.get(i)).fitness; 
buffer.add(c); 
} 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) Áß¿¡¼­ ÀÓÀÇÀÇ µÎ »ý¹°Ã¼(Organism)¸¦ ±³¹è(crossover)½ÃÄÑ 
* »õ·Î¿î ÀÚ½Ä »ý¹°Ã¼(Organism)¸¦ ¸¸µé°í ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) ¹öÆÛ¿¡ ÀúÀåÇÕ´Ï´Ù. 
*/ 
public void crossover() { 
for (int i = 0; i < POPULATIONS_SIZE - ELITISM_SIZE; i++) { 
// getRandomPopulation()ÀÇ °ªÀÌ ¶È°°ÀºÁö È®ÀÎÇÏ´Â ÀÛ¾÷ÀÌ ÇÊ¿äÇÕ´Ï´Ù. 
// °£´ÜÈ÷ ÇÏ±â À§ÇÏ¿© ±× °úÁ¤À» »ý·«ÇÕ´Ï´Ù. 
Organism c1 = (Organism) populations.get(getRandomPopulation()); 
Organism c2 = (Organism) populations.get(getRandomPopulation()); 

// getRandomPositionOfPopulation()ÀÇ °ªÀÌ 0ÀÎÁö È®ÀÎÇÒ ÇÊ¿ä°¡ ÀÖ½À´Ï´Ù. 
// °£´ÜÈ÷ ÇÏ±â À§ÇÏ¿© ±× °úÁ¤À» »ý·«ÇÕ´Ï´Ù. 
int position = getRandomChromosomePosition(); 

Organism c = new Organism(); 
System.arraycopy(c1.chromosome, 0, c.chromosome, 0, position); 
System.arraycopy(c2.chromosome, 0, c.chromosome, position, CHROMOSOME_SIZE 
- position); 
buffer.add(c); 
} 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) Áß¿¡¼­ ÀÓÀÇÀÇ ÇÑ »ý¹°Ã¼¸¦ µ¹¿¬º¯ÀÌ(mutate) ½ÃÅµ´Ï´Ù. 
* µ¹¿¬º¯ÀÌ(mutate)¸¦ ½ÃÅ°´Â ÀÌÀ¯´Â ±³¹è(crossover)¸¸ ½ÃÅ°´Â °æ¿ìº¸´Ù ´õ randomÇÑ °ªÀ» 
* »ý¼ºÇÏ¿© ¾Ë°í¸®ÁòÀÇ È¿À²À» ³ôÀÌ±â À§ÇØ¼­ÀÔ´Ï´Ù. 
*/ 
public void mutate() { 
Organism c = (Organism) buffer.get(getRandomPopulation()); 
int position = getRandomChromosomePosition(); 
c.chromosome[position] = (int) (Math.random() + MAX_CHROMOSOME_DATA); 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) ¹öÆÛÀÇ °ªÀ» ¿ø·¡ ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) º¯¼ö¿¡ 
* º¹»çÇÕ´Ï´Ù. Áï »õ·Î¿î ¼¼´ë(New Generation)¸¦ ¸¸µì´Ï´Ù. 
*/ 
public void swap() { 
for (int i = 0; i < POPULATIONS_SIZE; i++) { 
populations.remove(0); 
} 
for (int i = 0; i < POPULATIONS_SIZE; i++) { 
populations.add(buffer.remove(0)); 
} 
} 

/** 
* ÃÊ±âÈ­µÈ Organism °´Ã¼¸¦ ¹ÝÈ¯ÇÕ´Ï´Ù. OrganismÀÇ chromosome º¯¼ö ¹è¿­µéÀÇ ÃÊ±â°ªÀº 
* MAX_CHROMOSOME_DATA °ªÀ» ÃÊ°úÇÏÁö ¾Ê½À´Ï´Ù. 
* 
* @return ÃÊ±âÈ­µÈ Organism °´Ã¼ 
*/ 
public Organism initOrganism() { 
Organism c = new Organism(); 
for (int i = 0; i < CHROMOSOME_SIZE; i++) 
c.chromosome[i] = (int) (Math.random() * MAX_CHROMOSOME_DATA); 
return c; 
} 

/** 
* ÇÑ »ý¹°Ã¼(Organism)ÀÇ ¿°»öÃ¼(Chromosome) Áß¿¡¼­ ÀÓÀÇÀÇ À§Ä¡¸¦ ¹ÝÈ¯ÇÕ´Ï´Ù. 
* @return ¿°»öÃ¼(Chromosome) Áß ÀÓÀÇÀÇ À§Ä¡ 
*/ 
public int getRandomChromosomePosition() { 
return (int) (Math.random() * CHROMOSOME_SIZE); 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) Áß¿¡¼­ ÀÓÀÇÀÇ »ý¹°Ã¼(Organism)ÀÇ À§Ä¡¸¦ ¹ÝÈ¯ÇÕ´Ï´Ù. 
* @return ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) Áß¿¡¼­ ÀÓÀÇÀÇ »ý¹°Ã¼(Organism)ÀÇ À§Ä¡ 
*/ 
public int getRandomPopulation() { 
return (int) (Math.random() * POPULATIONS_SIZE); 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) ÁßÀÇ °¢°¢ÀÇ »ý¹°Ã¼(Organism)¿¡ ´ëÇÏ¿© fitness °ªÀ» 
* °è»êÇÕ´Ï´Ù. fitness °ªÀº Àý´ë°ªÀ¸·Î ³ªÅ¸³À´Ï´Ù. 
* @return fitness °ª 
*/ 
public int calculateFitness(int[] values) { 
return Math.abs(values[0] + 2 * values[1] + 3 * values[2] + 4 
* values[3] + 5 * values[4] - 100); 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) Áß¿¡¼­ ÀÔ·Â¹ÞÀº À§Ä¡ÀÇ »ý¹°Ã¼(Organism)ÀÇ °ªÀ» 
* Ãâ·ÂÇÕ´Ï´Ù. »ý¹°Ã¼(Organism)ÀÇ ¿°»öÃ¼(chromosome) ¹è¿­À» Áß°£¿¡ ½ºÆäÀÌ½º¸¦ µÎ¾î 
* Ãâ·ÂÇÏ°í, '['¿Í ']' »çÀÌ¿¡ fitness °ªÀ» Ãâ·ÂÇÕ´Ï´Ù. 
* @param ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ) Áß¿¡¼­ Ãâ·ÂÇÒ »ý¹°Ã¼(Organism)ÀÇ À§Ä¡ 
*/ 
public void printOrganism(int row) { 
Organism c = (Organism) populations.get(row); 
for (int i = 0; i < CHROMOSOME_SIZE; i++) 
System.out.print(c.chromosome[i] + " "); 
System.out.println("[" + c.fitness + "]"); 
} 

/** 
* ÀÎ±¸(Population, »ý¹°Ã¼ÀÇ ¸ðÀÓ)ÀÇ ÀüÃ¼ »ý¹°Ã¼(Organism)ÀÇ °ªÀ» Ãâ·ÂÇÕ´Ï´Ù. 
* »ý¹°Ã¼(Organism)ÀÇ ¿°»öÃ¼(chromosome) ¹è¿­À» Áß°£¿¡ ½ºÆäÀÌ½º¸¦ µÎ¾î Ãâ·ÂÇÏ°í, 
* '['¿Í ']' »çÀÌ¿¡ fitness °ªÀ» Ãâ·ÂÇÕ´Ï´Ù. 
*/ 
public void printOrganisms() { 
for (int i = 0; i < POPULATIONS_SIZE; i++) 
printOrganism(i); 
} 

/** 
* ½ÇÇàÇÏ±â À§ÇÑ main ¸Þ¼Òµå 
*/ 
public static void main(String[] args) { 
new GASample(); 
} 
}
