반응형

'Hello World!' 라는 문장을 유전자 알고림즘으로 찾아내는 셈플이다.

#ifndef ga_hpp
#define ga_hpp

#include <stdio.h>

#pragma warning(disable:4786) // disable debug warning

#include <iostream> // for cout etc.
#include <vector> // for vector class
#include <string> // for string class
#include <algorithm> // for sort algorithm
#include <time.h> // for random seed
#include <math.h> // for abs()


extern void go();


#endif /* ga_hpp */




//
//  ga.cpp
//  ga
//
//  Created by netcanis on 9/9/16.
//  Copyright © 2016 Netcanis. All rights reserved.
//

#include "ga.hpp"


// 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384

#define TOTAL_POPULATION    2048            // 총 인구     population size
#define MAXIUM_ITERATIONS   16384           // 최대 반복수  maximum iterations
#define ELITISM_RATE        0.10f           // 엘리티즘율   elitism rate
#define MUTATION_RATE       0.25f           // 변이율      mutation rate
#define MUTATION            RAND_MAX * MUTATION_RATE    // 변이 적용 숫자 (MUTATION_RATE에 대한 rand()값)
#define GA_TARGET           std::string("Hello world!") // 타겟 문장


using namespace std; // polluting global namespace, but hey...

struct Citizen
{
    string dna; // 유전자 정보
    unsigned int fitness; // its fitness
};

typedef vector<Citizen> CitizenArray;// 간결하기 위해 for brevity



// 인구 초기화
void initPopulation(CitizenArray &population, CitizenArray &buffer)
{
    for (int i=0; i<TOTAL_POPULATION; i++) {
        Citizen citizen;
        citizen.fitness = 0;
        citizen.dna.erase();
        
        // 문자열 범위안에서 랜덤하게 기본값을 넣어준다. (타겟 사이즈만큼 넣어준다)
        for (int j=0; j<GA_TARGET.size(); j++) {
            citizen.dna += (rand() % 90) + 32;
        }
        
        population.push_back(citizen);
    }
    
    buffer.resize(TOTAL_POPULATION);
}

// 적합도 계산
void calcFitness(CitizenArray &population)
{
    string target = GA_TARGET;
    int targetSize = (int)target.size();
    
    unsigned int fitness;
    for (int i=0; i<TOTAL_POPULATION; i++) {
        fitness = 0;
        for (int j=0; j<targetSize; j++) {
            fitness += abs(int(population[i].dna[j] - target[j]));
        }
        population[i].fitness = fitness;
    }
}

// 적합도 오름차순 정렬
bool sortFitness(Citizen x, Citizen y) {
    return (x.fitness < y.fitness);
}

inline void sortByFitness(CitizenArray &population) {
    sort(population.begin(), population.end(), sortFitness);
}

// 적합도 상위 엘리트를 버퍼에 저장한다.(재사용)
void elitism(CitizenArray &population, CitizenArray &buffer, int esize)
{
    for (int i=0; i<esize; i++) {
        buffer[i].dna = population[i].dna;
        buffer[i].fitness = population[i].fitness;
    }
}

// 두 dna를 반반 랜덤하게 섞는다.
string mixdna(string dna1, string dna2)
{
    string mdna;
    mdna.resize(GA_TARGET.size());
    for (int i=0; i<GA_TARGET.size(); ++i) {
        mdna[i] = (rand() % 2 == 0) ? dna1[i] : dna2[i];
    }
    return mdna;
}

// 변이
void mutate(Citizen &citizen)
{
    // 주어진 위치의 dna를 랜덤하게 바꾼다.
    int pos = rand() % GA_TARGET.size();
    citizen.dna[pos] = (rand() % 90) + 32;
}

// 교차
void mate(CitizenArray &population, CitizenArray &buffer)
{
    // 전체 인구에서 적합도 상위 주어진 퍼센티지만큼 적용했을때 계산된 인원수
    int eSize = TOTAL_POPULATION * ELITISM_RATE;
    
    // 주어진 적합도 상위 엘리트 시민은 교차를 적용하지 않고 그대로 버퍼에 추가한다.
    elitism(population, buffer, eSize);
    
    // Mate the rest
    // 엘리트들을 제외한 너머지 시민은 교차 실행
    for (int i = eSize; i < TOTAL_POPULATION; ++i) {
        // 전체 인구중 절반 상위 시민중 한명 선택 (상위 그룹)
        int index1 = rand() % (TOTAL_POPULATION / 2);
        // 전체 인구중 절반 하위 시민중 한명 선택 (하위 그룹)
        int index2 = rand() % (TOTAL_POPULATION / 2);
        
        string dna1 = population[index1].dna;
        string dna2 = population[index2].dna;
        
        // 50%확률로 랜덤하게 섞는다.
        buffer[i].dna = mixdna(dna1, dna2);
        
        // 변이 적용 - dna인자 한개를 랜덤하게 바꾸어 준다.
        if (rand() < MUTATION) {
            mutate(buffer[i]);
        }
    }
}

// 적합도가 가장 좋은 시민의 dna를 출력해준다.
inline void print_best(CitizenArray &citizen) {
    cout << "Best: " << citizen[0].dna << "  fitness = (" << citizen[0].fitness << ")" << endl;
}

// 대치
inline void swap(CitizenArray *&population, CitizenArray *&buffer) {
    CitizenArray *temp = population; population = buffer; buffer = temp;
}


void go()
{
    srand(unsigned(time(NULL)));
    
    CitizenArray pop_alpha;
    CitizenArray pop_beta;
    
    CitizenArray *population;
    CitizenArray *buffer;
    
    initPopulation(pop_alpha, pop_beta);
    population = &pop_alpha;
    buffer = &pop_beta;
    
    for (int i=0; i<MAXIUM_ITERATIONS; i++) {
        calcFitness(*population); // calculate fitness
        sortByFitness(*population);     // sort them
        print_best(*population); // print the best one
        
        // 적합도가 100%이면 종료처리한다.
        if ((*population)[0].fitness == 0) {
            break;
        }
        
        // 교차
        mate(*population, *buffer); // mate the population together
        
        // 대치
        swap(population, buffer); // swap buffers
    }
}
 

2020/05/19 - [AI/Algorithm] - neural network

2020/05/19 - [AI/Algorithm] - minimax full search example

2020/05/19 - [AI/Algorithm] - minimax, alpha-beta pruning

2020/05/19 - [iOS/Tips] - Bitbucket Carthage 사용

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/3) - 메모리 덤프

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/3) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/3) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Neural Network (XOR)  (0) 2022.11.18
2D 충돌처리  (0) 2020.12.12
neural network  (0) 2020.05.19
minimax full search example  (0) 2020.05.19
minimax, alpha-beta pruning  (0) 2020.05.19
블로그 이미지

SKY STORY

,