Silverback9

#야생으로

Creative Coding 독학 제253일 2024년12월05일(목)

오늘은 교차작업을 하는 함수 crossover()와 돌연변이를 만드는 mutate()함수를 살펴 보겠습니다~~Yeah~~^^*

어머 근데!!

새파란 찬 바람을 불어 주는 동장군이 납신 아침이예요~^^*

겨울의 아침 느낌을 잠시 만끽하고~^^*

크리스마스 20일 남은 것을 설레어 하며~^^*

항가리 무곡으로 아침 스트레칭 하시며~^^* 잠시 쉬고 계셔요~~^^*

공부 정리해서 곧 돌아올게요~^^*

이제 몸이 좀 부드럽게 풀리셨나요~~^^* 그럼 이제 코딩 공부 시작해 볼게요~~^^* Yeah^^*

먼저 교차 작업을 살펴 보겠습니다~^^*

두 DNA 사의의 교차점을 무작위로 선정해 보려고 합니다.

(1) 무작위 수인 n을 교차점을 정하면~^^*

(2) n번째 보다 뒤에 있는 배열 요소에 자신의 DNA의 해당 내용을 넣고

(3) n번째까지 앞부분에 있는 배열 요소에 파트너의 DNA의 해당 내용을 넣어서

(4) child 의 DNA를 완성해 보는 거예요~^^*

그림으로 표현해 보자면요~~^^*

코드로 표현해 보자면요~^^*

  crossover(partner) {
    
    let child = new DNA(this.genes.length);
    //새로운 DNA 클래스를 생성하여 변수 child에 저장합니다~^^*

    let midpoint = floor(random(this.genes.length)); 
    //0과 DNA 길이값 사이의 수를 무작위로 생성하여 정수부분을 변수 midpoint에 저장합니다. 
   //midpoint는 교차점 역할을 하겠네요~^^* 
    
    for (let i = 0; i < this.genes.length; i++) {
      if (i > midpoint) child.genes[i] = this.genes[i];
      else child.genes[i] = partner.genes[i];
    //교차점 midpoint보다 뒷 부분은 this.genes[]의 해당내용을 저장하고
    //교차점 midpoint까지 앞부분은 파트너의 해당 DNA내용을 저장합니다. 
    }
    return child;
    //완성된 child DNA를 return 반환 합니다.  
  }

이번엔 돌연변이 생성 작업을 하는 함수 mutate()를 살펴 볼까요~~^^*

미리 지정된 돌연변이률에 따라 child DNA에 돌연변이를 일으키는 것인데요~^^*

child의 DNA인 this,genes[ ]의 각 요소마다 돌연변이률을 적용해서 변이를 생성하면 어떨까요~^^*

이 작업은 코드를 먼저 살펴 보는 것이 이해하기 쉬울 것 같아요~^^*

let mutationRate;

function sepup() {
     .
     .
     .
   mutationRate = 0.01;
}

메인 파일인 sketch.js에서 글로벌 변수로 지정한 mutationRate를 클래스 DNA의 내장함수 mutate()에서 사용해 보겠습니다~^^*

 mutate(mutationRate) {

    for (let i = 0; i < this.genes.length; i++) {
      if (random(1) < mutationRate) {
        this.genes[i] = newChar();  
     }
    //this.genes의 각 구성요소[i]에 대하여
    //0에서 1 사이 수를 무작위로 생성하고, 그 값이 mutationRate보다 작으면
    //새로운 character 글자를 무작위로 생성하여 저장합니다. 
    }
  }

와우~^^* 어느덧 우리가 Genetic Algorithm의 대부분의 내용을 다 살펴 본 것 같아요~^^*

굵은 글씨체의 내용이 지금까지 우리가 Genetic Algorithm에 대해 살펴본 내용들이구요~^^*

가는 글씨체의 내용은 결과 평가와 보여주기 등의 작업을 하는 내용들이예요~~^^*

function newChar() {
  let c = floor(random(63, 122));
  if (c === 63) c = 32;
  if (c === 64) c = 46;

  return String.fromCharCode(c);
}

class DNA {
  constructor(num) {
    // The genetic sequence
    this.genes = [];
    this.fitness = 0;
    for (let i = 0; i < num; i++) {
      this.genes[i] = newChar(); // Pick from range of chars
    }
  }

  getPhrase() {
    return this.genes.join("");
  }

  calcFitness(target) {
    let score = 0;
    for (let i = 0; i < this.genes.length; i++) {
      if (this.genes[i] == target.charAt(i)) {
        score++;
      }
    }
    this.fitness = score / target.length;
  }

  
  crossover(partner) {
    
    let child = new DNA(this.genes.length);

    let midpoint = floor(random(this.genes.length));

    for (let i = 0; i < this.genes.length; i++) {
      if (i > midpoint) child.genes[i] = this.genes[i];
      else child.genes[i] = partner.genes[i];
    }
    return child;
  }


  mutate(mutationRate) {
    for (let i = 0; i < this.genes.length; i++) {
      if (random(1) < mutationRate) {
        this.genes[i] = newChar();
      }
    }
  }
}
class Population {
  constructor(p, m, num) {
    this.population; 
    this.matingPool; 
    this.generations = 0; 
    this.finished = false;
    this.target = p; 
    this.mutationRate = m; 
    this.perfectScore = 1;

    this.best = "";

    this.population = [];
    for (let i = 0; i < num; i++) {
      this.population[i] = new DNA(this.target.length);
    }
    this.matingPool = [];
    this.calcFitness();
  }

  
  calcFitness() {
    for (let i = 0; i < this.population.length; i++) {
      this.population[i].calcFitness(target);
    }
  }

  
  naturalSelection() {
    
    this.matingPool = [];

    let maxFitness = 0;
    for (let i = 0; i < this.population.length; i++) {
      if (this.population[i].fitness > maxFitness) {
        maxFitness = this.population[i].fitness;
      }
    }

    for (let i = 0; i < this.population.length; i++) {
      let fitness = map(this.population[i].fitness, 0, maxFitness, 0, 1);
      let n = floor(fitness * 100); 

      for (let j = 0; j < n; j++) {
        // and pick two random numbers
        this.matingPool.push(this.population[i]);
      }
    }
  }

  
  generate() {
    
    for (let i = 0; i < this.population.length; i++) {
      let a = floor(random(this.matingPool.length));
      let b = floor(random(this.matingPool.length));
      let partnerA = this.matingPool[a];
      let partnerB = this.matingPool[b];
      let child = partnerA.crossover(partnerB);
      child.mutate(this.mutationRate);
      this.population[i] = child;
    }
    this.generations++;
  }

  getBest() {
    return this.best;
  }

  
  evaluate() {
    let worldrecord = 0.0;
    let index = 0;
    for (let i = 0; i < this.population.length; i++) {
      if (this.population[i].fitness > worldrecord) {
        index = i;
        worldrecord = this.population[i].fitness;
      }
    }

    this.best = this.population[index].getPhrase();
    if (worldrecord === this.perfectScore) {
      this.finished = true;
    }
  }

  isFinished() {
    return this.finished;
  }

  getGenerations() {
    return this.generations;
  }

 
  getAverageFitness() {
    let total = 0;
    for (let i = 0; i < this.population.length; i++) {
      total += this.population[i].fitness;
    }
    return total / this.population.length;
  }

  allPhrases() {
    let everything = "";

    let displayLimit = min(this.population.length, 50);

    for (let i = 0; i < displayLimit; i++) {
      everything += this.population[i].getPhrase() + "<br>";
    }
    return everything;
  }
}
let target;
let popmax;
let mutationRate;
let population;

let bestPhrase;
let allPhrases;
let stats;

function setup() {
  bestPhrase = createP("Best phrase:");
  
  bestPhrase.class("best");

  allPhrases = createP("All phrases:");
  allPhrases.position(600, 10);
  allPhrases.class("all");

  stats = createP("Stats");
  
  stats.class("stats");

  
  target = "To be or not to be.";
  popmax = 200;
  mutationRate = 0.01;

  population = new Population(target, mutationRate, popmax);
}

function draw() {
  
  population.naturalSelection();
  
  population.generate();
  
  population.calcFitness();

  population.evaluate();

  
  if (population.isFinished()) {
    
    noLoop();
  }

  displayInfo();
}

function displayInfo() {
  
  let answer = population.getBest();

  bestPhrase.html("Best phrase:<br>" + answer);

  let statstext =
    "total generations:     " + population.getGenerations() + "<br>";
  statstext +=
    "average fitness:       " + nf(population.getAverageFitness()) + "<br>";
  statstext += "total population:      " + popmax + "<br>";
  statstext += "mutation rate:         " + floor(mutationRate * 100) + "%";

  stats.html(statstext);

  allPhrases.html("All phrases:<br>" + population.allPhrases());
}

전체 코드를 다시 파일별로 살펴 보며 프로그램 실행을 한 번 더 해볼까요, 우리~^^*

오늘 저와 함께 DNA 교차 작업과 돌연변이 생성작업을 하는 함수 crossover()와 mutate()를 살펴봐 주셔서 감사합니다~^^*

서로 다른 문화의 개성들이 잘 교차되어 다음 세대의 아름다운 문화를 만들어 내어요~~^^*

내일은 이 모든 내용을 간단하게 복습 정리해 보고 새로운 코드 공부도 시작해 볼까요~^^*

오늘도 점심 맛있게 드시고요!

춥지만 마음은 따순한 낮과 저녁을 보내시고요!

편안하게 코~^^*하는 밤 되시길 바래요~~^^*

우리 내일 또 다시 만나요~~^^*

네~~^^* 꿈은 이루어 집니다~~^^*

댓글 남기기