├── .gitignore ├── .gitmodules ├── LICENSE ├── MANIFEST.in ├── OpenCLGA ├── __init__.py ├── __main__.py ├── evaluation │ ├── ant │ │ ├── ant_tsp.cl │ │ ├── ant_tsp.py │ │ └── python_ant_tsp.py │ ├── memory_usage │ │ ├── main.py │ │ ├── test_local.c │ │ └── test_private.c │ ├── simulated_annealing │ │ ├── __init__.py │ │ ├── ocl_sa.cl │ │ ├── ocl_sa.py │ │ └── sa.py │ └── type_casting │ │ ├── casting.c │ │ ├── casting.py │ │ └── casting_vector.c ├── kernel │ ├── Noise.cl │ ├── ga_utils.cl │ ├── ocl_ga.cl │ ├── shuffler_chromosome.cl │ ├── simple_chromosome.cl │ └── simple_gene.cl ├── ocl_ga.py ├── ocl_ga_client.py ├── ocl_ga_server.py ├── ocl_ga_wsserver.py ├── shuffler_chromosome.py ├── simple_chromosome.py ├── simple_gene.py ├── ui │ ├── android-icon-144x144.png │ ├── android-icon-192x192.png │ ├── android-icon-36x36.png │ ├── android-icon-48x48.png │ ├── android-icon-72x72.png │ ├── android-icon-96x96.png │ ├── apple-icon-114x114.png │ ├── apple-icon-120x120.png │ ├── apple-icon-144x144.png │ ├── apple-icon-152x152.png │ ├── apple-icon-180x180.png │ ├── apple-icon-57x57.png │ ├── apple-icon-60x60.png │ ├── apple-icon-72x72.png │ ├── apple-icon-76x76.png │ ├── apple-icon-precomposed.png │ ├── apple-icon.png │ ├── asset-manifest.json │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── favicon.ico │ ├── index.html │ ├── manifest.json │ ├── ms-icon-144x144.png │ ├── ms-icon-150x150.png │ ├── ms-icon-310x310.png │ ├── ms-icon-70x70.png │ └── static │ │ ├── css │ │ ├── main.5da4bf40.css │ │ └── main.5da4bf40.css.map │ │ └── js │ │ ├── main.7371ebc2.js │ │ └── main.7371ebc2.js.map ├── utilities │ ├── __init__.py │ ├── generaltaskthread │ │ ├── __init__.py │ │ ├── generaltaskthread.py │ │ └── logger.py │ ├── httpwebsocketserver │ │ ├── ExampleWSServer.py │ │ ├── HTTPWebSocketsHandler.py │ │ ├── README.md │ │ ├── __init__.py │ │ ├── index.html │ │ └── websocket.html │ └── socketserverclient │ │ ├── __init__.py │ │ └── server_client.py └── utils.py ├── README.rst ├── examples ├── algebra_expansion │ ├── expansion.py │ └── kernel │ │ └── expansion.cl ├── grouping │ ├── grouping.cl │ └── grouping.py ├── scheduling - power station │ ├── power.cl │ └── power.py ├── taiwan_travel │ ├── TW319_368Addresses-no-far-islands.json │ ├── TW319_368Addresses.json │ ├── TW319_368Addresses.xlsx │ ├── kernel │ │ └── taiwan_fitness.cl │ ├── taiwan_travel_client.py │ ├── taiwan_travel_server.py │ └── ui │ │ ├── android-icon-144x144.png │ │ ├── android-icon-192x192.png │ │ ├── android-icon-36x36.png │ │ ├── android-icon-48x48.png │ │ ├── android-icon-72x72.png │ │ ├── android-icon-96x96.png │ │ ├── apple-icon-114x114.png │ │ ├── apple-icon-120x120.png │ │ ├── apple-icon-144x144.png │ │ ├── apple-icon-152x152.png │ │ ├── apple-icon-180x180.png │ │ ├── apple-icon-57x57.png │ │ ├── apple-icon-60x60.png │ │ ├── apple-icon-72x72.png │ │ ├── apple-icon-76x76.png │ │ ├── apple-icon-precomposed.png │ │ ├── apple-icon.png │ │ ├── asset-manifest.json │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── manifest.json │ │ ├── ms-icon-144x144.png │ │ ├── ms-icon-150x150.png │ │ ├── ms-icon-310x310.png │ │ ├── ms-icon-70x70.png │ │ └── static │ │ ├── css │ │ ├── main.10448cc5.css │ │ └── main.10448cc5.css.map │ │ └── js │ │ ├── main.0b7ca193.js │ │ └── main.0b7ca193.js.map └── tsp │ ├── kernel │ └── simple_tsp.cl │ └── simple_tsp.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.pyc 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # IPython Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # dotenv 80 | .env 81 | 82 | # virtualenv 83 | .venv/ 84 | venv/ 85 | ENV/ 86 | 87 | # Spyder project settings 88 | .spyderproject 89 | 90 | # Rope project settings 91 | .ropeproject 92 | 93 | # OpenCLGA tmp files 94 | final.cl 95 | 96 | # mac ds store 97 | .DS_Store 98 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "utilities/generaltaskthread"] 2 | path = utilities/generaltaskthread 3 | url = https://github.com/kilikkuo/py_generaltaskthread.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Python OpenCL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE README.rst 2 | recursive-include OpenCLGA/kernel * 3 | recursive-include OpenCLGA/ui * 4 | recursive-exclude * __pycache__ 5 | recursive-exclude * .gitignore 6 | -------------------------------------------------------------------------------- /OpenCLGA/__init__.py: -------------------------------------------------------------------------------- 1 | from .simple_gene import SimpleGene 2 | from .shuffler_chromosome import ShufflerChromosome 3 | from .simple_chromosome import SimpleChromosome 4 | from .ocl_ga import OpenCLGA 5 | from .ocl_ga_server import start_ocl_ga_server 6 | from .ocl_ga_client import start_ocl_ga_client 7 | from . import utils 8 | -------------------------------------------------------------------------------- /OpenCLGA/__main__.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | import argparse 3 | from .ocl_ga_client import start_ocl_ga_client 4 | parser = argparse.ArgumentParser(description='OpenCLGA client help') 5 | parser.add_argument('server', metavar='ip', type=str, 6 | help='the server ip, default : 127.0.0.1', default='127.0.0.1') 7 | parser.add_argument('port', metavar='port', type=int, 8 | help='the server port, default : 12345', default=12345) 9 | args = parser.parse_args() 10 | start_ocl_ga_client(args.server, args.port) 11 | 12 | main() 13 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/ant/ant_tsp.cl: -------------------------------------------------------------------------------- 1 | #include "ga_utils.cl" 2 | 3 | /* ======================== codes for preparing execution =========================== */ 4 | 5 | __kernel void ant_tsp_calculate_distances(global float* x, global float* y, global float* distances) 6 | { 7 | int global_p = get_global_id(0); 8 | int global_q = get_global_id(1); 9 | 10 | float2 p = (float2)(x[global_p], y[global_p]); 11 | float2 q = (float2)(x[global_q], y[global_q]); 12 | distances[global_p * NODE_COUNT + global_q] = distance(p, q); 13 | } 14 | 15 | 16 | /* ======================== codes for ant going out =========================== */ 17 | 18 | bool ant_tsp_in_visited_nodes(global int* ant_visited_nodes, int last_index, int node_id) { 19 | int i = 0; 20 | for (; i <= last_index; i++) { 21 | if (ant_visited_nodes[i] == node_id) { 22 | return true; 23 | } 24 | } 25 | return false; 26 | } 27 | 28 | void ant_tsp_calculate_path_probabilities(global int* ant_visited_nodes, 29 | global float* tmp_path_probabilities, 30 | global float* tmp_pheromones, 31 | global float* path_pheromones, 32 | global float* path_distances, 33 | int last_index) 34 | { 35 | float total = 0.0; 36 | int current_node = ant_visited_nodes[last_index]; 37 | int i; 38 | 39 | for (i = 0; i < NODE_COUNT; i++) { 40 | if (current_node == i) { 41 | tmp_path_probabilities[i] = 0; 42 | tmp_pheromones[i] = 0; 43 | } else if (ant_tsp_in_visited_nodes(ant_visited_nodes, last_index, i)) { 44 | tmp_path_probabilities[i] = 0; 45 | tmp_pheromones[i] = 0; 46 | } else { 47 | tmp_pheromones[i] = pow(path_pheromones[current_node * NODE_COUNT + i], (float) ALPHA) * 48 | pow(100 / path_distances[current_node * NODE_COUNT + i], (float) BETA); 49 | total += tmp_pheromones[i]; 50 | } 51 | } 52 | 53 | for (i = 0; i < NODE_COUNT; i++) { 54 | if (tmp_pheromones[i] > 0.00001) { 55 | tmp_path_probabilities[i] = tmp_pheromones[i] / total; 56 | } 57 | } 58 | } 59 | 60 | int ant_tsp_random_choose(global float* tmp_path_probabilities, uint* rand_holder) 61 | { 62 | return random_choose_by_ratio(tmp_path_probabilities, rand_holder, NODE_COUNT); 63 | } 64 | 65 | float ant_tsp_calculate_fitness(global int* ant_visited_nodes, global float* path_distances) { 66 | float fitness = 0.0; 67 | int i = 0; 68 | int start, end; 69 | for (; i < NODE_COUNT; i++) { 70 | start = ant_visited_nodes[i]; 71 | if (i < NODE_COUNT - 1) { 72 | end = ant_visited_nodes[i + 1]; 73 | } else { 74 | end = ant_visited_nodes[0]; 75 | } 76 | fitness += path_distances[start * NODE_COUNT + end]; 77 | } 78 | return fitness; 79 | } 80 | 81 | // A kernel work item is an ant 82 | __kernel void ant_tsp_run_ant(global int* ant_visited_nodes, 83 | global float* tmp_path_probabilities, 84 | global float* tmp_pheromones, 85 | global float* path_pheromones, 86 | global float* path_distances, 87 | global float* ant_fitnesses, 88 | global uint* rand_input) 89 | { 90 | int idx = get_global_id(0); 91 | // out of bound kernel task for padding 92 | if (idx >= ANT_COUNT) { 93 | return; 94 | } 95 | // init random numbers. 96 | uint ra[1]; 97 | init_rand(rand_input[idx], ra); 98 | 99 | int next_index = 1; 100 | 101 | // The first position of visited_node is not 0. We should move it. 102 | global int* my_tmp_visited_nodes = ant_visited_nodes + idx * NODE_COUNT; 103 | global float* my_tmp_path_probabilities = tmp_path_probabilities + idx * NODE_COUNT; 104 | global float* my_tmp_pheromones = tmp_pheromones + idx * NODE_COUNT; 105 | // choose the first node randomly 106 | my_tmp_visited_nodes[0] = rand_range(ra, NODE_COUNT); 107 | // go all nodes 108 | for (; next_index < NODE_COUNT; next_index++) { 109 | ant_tsp_calculate_path_probabilities(my_tmp_visited_nodes, 110 | my_tmp_path_probabilities, 111 | my_tmp_pheromones, 112 | path_pheromones, 113 | path_distances, 114 | next_index - 1); 115 | my_tmp_visited_nodes[next_index] = ant_tsp_random_choose(my_tmp_path_probabilities, ra); 116 | } 117 | // calculate fitness 118 | ant_fitnesses[idx] = ant_tsp_calculate_fitness(my_tmp_visited_nodes, path_distances); 119 | } 120 | 121 | /* ======================== codes for updating pheromone =========================== */ 122 | 123 | /** 124 | * kernel design: each path has its owned kernel 125 | **/ 126 | __kernel void ant_tsp_evaporate_pheromones(global float* path_pheromones) 127 | { 128 | int idx = get_global_id(0); 129 | path_pheromones[idx] = (1 - EVAPORATION) * path_pheromones[idx] + 1; 130 | } 131 | 132 | /* 133 | * Pheromones is a two dimensional array: 134 | * from 135 | * 1 2 3 4 5 6 136 | * ----------------------- 137 | * t 1| 138 | * o 2| 139 | * 3| 140 | * 141 | * Since from and to can be swapped in TSP case, we have to update both side, (1, 2) and (2, 1), if 142 | * an ant goes through (1, 2). 143 | * 144 | * kernel design: each path has its owned kernel 145 | */ 146 | __kernel void ant_tsp_update_pheromones(global int* ant_visited_nodes, 147 | global float* ant_fitnesses, 148 | global float* path_pheromones) 149 | { 150 | int start = get_global_id(0); 151 | int end = get_global_id(1); 152 | // out of bound kernel task for padding 153 | if (start * end >= NODE_COUNT * NODE_COUNT) { 154 | return; 155 | } 156 | 157 | int ant_index, node_index, ant_start, ant_end; 158 | float bonus; 159 | int idx = start * NODE_COUNT + end; 160 | 161 | for (ant_index = 0; ant_index < ANT_COUNT; ant_index++) { 162 | bonus = Q / ant_fitnesses[ant_index]; 163 | for (node_index = 0; node_index < NODE_COUNT; node_index++) { 164 | if (node_index < NODE_COUNT - 1) { 165 | ant_start = ant_visited_nodes[ant_index * NODE_COUNT + node_index]; 166 | ant_end = ant_visited_nodes[ant_index * NODE_COUNT + node_index + 1]; 167 | } else { 168 | ant_start = ant_visited_nodes[ant_index * NODE_COUNT + node_index]; 169 | ant_end = ant_visited_nodes[ant_index * NODE_COUNT]; 170 | } 171 | if ((ant_start == start && ant_end == end) || (ant_start == end && ant_end == start)) { 172 | path_pheromones[idx] += bonus; 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/ant/ant_tsp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import math 3 | import numpy 4 | import os 5 | import pyopencl as cl 6 | import random 7 | import sys 8 | from OpenCLGA import utils 9 | 10 | class AntTSP(): 11 | 12 | def __init__(self, options): 13 | self.__iterations = options['iterations'] 14 | self.__ants = options['ants'] 15 | # the option for pheromone affecting probability 16 | self.__alpha = options['alpha'] 17 | # the option for length affecting probability 18 | self.__beta = options['beta'] 19 | # node should be an array of object. The structure of object should be 20 | # 1. x: the position of x a float 21 | # 2. y: the position of y a float 22 | self.__nodes = options['nodes'] 23 | self.__node_count = len(self.__nodes) 24 | self.__matrix_size = self.__node_count * self.__node_count 25 | # the option for pheromone evaporating 26 | self.__evaporation = options['evaporation'] 27 | # the option for leaking pheromone 28 | self.__q = options['q'] 29 | self.__best_result = None 30 | self.__best_fitness = sys.float_info.max 31 | 32 | self.__init_cl() 33 | self.__create_program() 34 | 35 | def __init_cl(self, cl_context=None): 36 | self.__ctx = cl_context if cl_context is not None else cl.create_some_context() 37 | self.__queue = cl.CommandQueue(self.__ctx) 38 | 39 | def __create_program(self): 40 | f = open('ant_tsp.cl', 'r'); 41 | fstr = ''.join(f.readlines()) 42 | f.close() 43 | ocl_kernel_path = os.path.join(os.path.dirname(os.path.abspath('../../' + __file__)), 'kernel').replace(' ', '\\ ') 44 | options = [ 45 | '-D', 'ANT_COUNT={}'.format(self.__ants), 46 | '-D', 'NODE_COUNT={}'.format(self.__node_count), 47 | '-D', 'ALPHA={}'.format(self.__alpha), 48 | '-D', 'BETA={}'.format(self.__beta), 49 | '-D', 'EVAPORATION={}'.format(self.__evaporation), 50 | '-D', 'Q={}'.format(self.__q), 51 | '-I', ocl_kernel_path 52 | ] 53 | self.__prg = cl.Program(self.__ctx, fstr).build(options); 54 | 55 | def __prepare_cl_buffers(self): 56 | mf = cl.mem_flags 57 | # prepare distances buffers 58 | self.__path_distances = numpy.zeros(shape=[self.__node_count, self.__node_count], 59 | dtype=numpy.float32) 60 | 61 | self.__dev_path_distances = cl.Buffer(self.__ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 62 | hostbuf=self.__path_distances) 63 | 64 | # initialize all pheromones of paths with 1 65 | self.__path_pheromones = numpy.empty(shape=[self.__node_count, self.__node_count], 66 | dtype=numpy.float32) 67 | self.__path_pheromones.fill(1) 68 | self.__dev_path_pheromones = cl.Buffer(self.__ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 69 | hostbuf=self.__path_pheromones) 70 | 71 | # prepare buffers for node position: x, y 72 | x = numpy.empty(self.__node_count, dtype=numpy.float32) 73 | y = numpy.empty(self.__node_count, dtype=numpy.float32) 74 | for i in range(self.__node_count): 75 | x[i] = self.__nodes[i][0] 76 | y[i] = self.__nodes[i][1] 77 | 78 | self.__dev_x = cl.Buffer(self.__ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, 79 | hostbuf=x) 80 | self.__dev_y = cl.Buffer(self.__ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, 81 | hostbuf=y) 82 | 83 | # Random number should be given by Host program because OpenCL doesn't have a random number 84 | # generator. We just include one, Noise.cl. 85 | rnum = [random.randint(0, 4294967295) for i in range(self.__ants)] 86 | ## note: numpy.random.rand() gives us a list float32 and we cast it to uint32 at the calling 87 | ## of kernel function. It just views the original byte order as uint32. 88 | self.__dev_rnum = cl.Buffer(self.__ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 89 | hostbuf=numpy.array(rnum, dtype=numpy.uint32)) 90 | 91 | # we should prepare buffer memory for each ant on each node. 92 | buffer_size = 4 * self.__node_count * self.__ants 93 | # the visited_nodes is used for storing the path of an ant. 94 | self.__dev_visited_nodes = cl.Buffer(self.__ctx, mf.READ_WRITE, buffer_size) 95 | # the path_probabilities is used for choosing next node 96 | self.__dev_path_probabilities = cl.Buffer(self.__ctx, mf.READ_WRITE, buffer_size) 97 | # the tmp pheromones is used for calcuating probabilities for next node 98 | self.__dev_tmp_pheromones = cl.Buffer(self.__ctx, mf.READ_WRITE, buffer_size) 99 | # this is for keepting fitness value of each ant at a single round. 100 | self.__dev_ant_fitnesses = cl.Buffer(self.__ctx, mf.READ_WRITE, 4 * self.__ants) 101 | 102 | def __calculate_distances(self): 103 | # calculate the distances betwen two points. 104 | self.__prg.ant_tsp_calculate_distances(self.__queue, 105 | (self.__node_count, self.__node_count), 106 | (1, 1), 107 | self.__dev_x, 108 | self.__dev_y, 109 | self.__dev_path_distances) 110 | 111 | def __execute_single_generation(self, generation): 112 | self.__prg.ant_tsp_run_ant(self.__queue, 113 | (self.__ants, ), 114 | (1, ), 115 | self.__dev_visited_nodes, 116 | self.__dev_path_probabilities, 117 | self.__dev_tmp_pheromones, 118 | self.__dev_path_pheromones, 119 | self.__dev_path_distances, 120 | self.__dev_ant_fitnesses, 121 | self.__dev_rnum).wait() 122 | 123 | visited_nodes = numpy.empty(self.__ants * self.__node_count, dtype=numpy.int32) 124 | fitnesses = numpy.empty(self.__ants, dtype=numpy.float32) 125 | cl.enqueue_copy(self.__queue, visited_nodes, self.__dev_visited_nodes) 126 | cl.enqueue_copy(self.__queue, fitnesses, self.__dev_ant_fitnesses).wait(); 127 | 128 | best_index = -1; 129 | best_fitness = sys.float_info.max 130 | for index, fitness in enumerate(fitnesses): 131 | if fitness < best_fitness: 132 | best_index = index 133 | best_fitness = fitness 134 | 135 | start_index = best_index * self.__node_count 136 | end_index = (best_index + 1) * self.__node_count 137 | best_result = visited_nodes[start_index:end_index] 138 | 139 | 140 | # update path_pheromones 141 | self.__prg.ant_tsp_evaporate_pheromones(self.__queue, 142 | (self.__node_count, self.__node_count), 143 | (1, 1), 144 | self.__dev_path_pheromones) 145 | 146 | self.__prg.ant_tsp_update_pheromones(self.__queue, 147 | (self.__node_count, self.__node_count), 148 | (1, 1), 149 | self.__dev_visited_nodes, 150 | self.__dev_ant_fitnesses, 151 | self.__dev_path_pheromones).wait() 152 | return (best_result, best_fitness) 153 | 154 | def run(self): 155 | self.__prepare_cl_buffers() 156 | self.__calculate_distances() 157 | for generation in range(self.__iterations): 158 | result = self.__execute_single_generation(generation) 159 | print('best fitness #{}: {}'.format(generation, result[1])) 160 | if result[1] < self.__best_fitness: 161 | self.__best_fitness = result[1] 162 | self.__best_result = result[0] 163 | 164 | return (self.__best_result, self.__best_fitness) 165 | 166 | if __name__ == '__main__': 167 | random.seed(1) 168 | city_info = { city_id: (random.random() * 100, random.random() * 100) for city_id in range(30) } 169 | print('cities:') 170 | print(city_info) 171 | ant = AntTSP({ 172 | 'iterations': 100, 173 | 'ants': 10000, 174 | 'alpha': 1.1, 175 | 'beta': 1.5, 176 | 'evaporation': 0.85, 177 | 'q': 10000, 178 | 'nodes': city_info 179 | }) 180 | 181 | result = ant.run() 182 | print('Length: {}'.format(result[1])) 183 | print('Shortest Path: ' + ' => '.join(str(g) for g in result[0])) 184 | utils.plot_tsp_result(city_info, result[0]) 185 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/ant/python_ant_tsp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import math 3 | import numpy 4 | import random 5 | import sys 6 | from OpenCLGA import utils 7 | 8 | class PythonAntTSP(): 9 | 10 | def __init__(self, options): 11 | self.__iterations = options['iterations'] 12 | self.__ants = options['ants'] 13 | # the option for pheromone affecting probability 14 | self.__alpha = options['alpha'] 15 | # the option for length affecting probability 16 | self.__beta = options['beta'] 17 | # node should be an array of object. The structure of object should be 18 | # 1. x: the position of x a float 19 | # 2. y: the position of y a float 20 | self.__nodes = options['nodes'] 21 | self.__node_count = len(self.__nodes) 22 | self.__matrix_size = self.__node_count * self.__node_count 23 | # the option for pheromone evaporating 24 | self.__evaporation = options['evaporation'] 25 | # the option for leaking pheromone 26 | self.__q = options['q'] 27 | 28 | self.__init_member() 29 | 30 | def __init_member(self): 31 | self.__calculate_distances() 32 | # initialize all pheromones of paths with 1 33 | self.__path_pheromones = numpy.empty(shape=[self.__node_count, self.__node_count], 34 | dtype=numpy.float32) 35 | self.__path_pheromones.fill(1) 36 | self.__best_result = None 37 | self.__best_fitness = sys.float_info.max 38 | 39 | def __calculate_distances(self): 40 | # calculate the distances betwen two points. 41 | self.__path_distances = numpy.empty(shape=[self.__node_count, self.__node_count], 42 | dtype=numpy.float32) 43 | for start in range(self.__node_count): 44 | for end in range(self.__node_count): 45 | if start == end: 46 | self.__path_distances[(start, end)] = 0 47 | else: 48 | self.__path_distances[(start, end)] = math.hypot(self.__nodes[start][0] - self.__nodes[end][0], 49 | self.__nodes[start][1] - self.__nodes[end][1]) 50 | 51 | def __calculate_path_probabilities(self, visited_nodes): 52 | path_probabilities = numpy.empty(shape=[self.__node_count], dtype=numpy.float32) 53 | pheromones = numpy.empty(shape=[self.__node_count], dtype=numpy.float32) 54 | total = 0.0 55 | current_node = visited_nodes[-1] 56 | for end in range(self.__node_count): 57 | if current_node == end: 58 | pheromones[end] = 0 59 | elif end in visited_nodes: 60 | pheromones[end] = 0 61 | else: 62 | pheromones[end] = (self.__path_pheromones[(current_node, end)] ** self.__alpha) * ((1 / self.__path_distances[(current_node, end)]) ** self.__beta) 63 | total += pheromones[end] 64 | 65 | for end in range(self.__node_count): 66 | if current_node == end: 67 | path_probabilities[end] = 0 68 | elif end in visited_nodes: 69 | path_probabilities[end] = 0 70 | else: 71 | path_probabilities[end] = pheromones[end] / total 72 | 73 | return path_probabilities 74 | 75 | def __random_choose(self, probabilities): 76 | rnd = random.random() 77 | for end in range(self.__node_count): 78 | if probabilities[end] == 0: 79 | continue 80 | elif rnd >= probabilities[end]: 81 | rnd -= probabilities[end] 82 | else: 83 | return end 84 | 85 | 86 | def __update_path_pheromones(self, visited_nodes, fitness): 87 | for index, node in enumerate(visited_nodes): 88 | if index < len(visited_nodes) - 1: 89 | if node < visited_nodes[index + 1]: 90 | self.__path_pheromones[(node, visited_nodes[index + 1])] += self.__q / fitness; 91 | else: 92 | self.__path_pheromones[(visited_nodes[index + 1], node)] += self.__q / fitness; 93 | else: 94 | if node < visited_nodes[0]: 95 | self.__path_pheromones[(node, visited_nodes[0])] += self.__q / fitness; 96 | else: 97 | self.__path_pheromones[(visited_nodes[0], node)] += self.__q / fitness; 98 | 99 | def __calculate_visited_fitness(self, visited_nodes): 100 | result = 0.0; 101 | for index, node in enumerate(visited_nodes): 102 | if index < len(visited_nodes) - 1: 103 | if node < visited_nodes[index + 1]: 104 | result += self.__path_distances[(node, visited_nodes[index + 1])] 105 | else: 106 | result += self.__path_distances[(visited_nodes[index + 1], node)] 107 | else: 108 | if node < visited_nodes[0]: 109 | result += self.__path_distances[(node, visited_nodes[0])] 110 | else: 111 | result += self.__path_distances[(visited_nodes[0], node)] 112 | return result 113 | 114 | def __execute_single_generation(self, generation): 115 | ant_result = [] 116 | # send a lot of ants out 117 | for ant in range(self.__ants): 118 | visited_nodes = [random.randint(0, self.__node_count - 1)] 119 | # run all nodes 120 | while len(visited_nodes) < self.__node_count: 121 | probabilities = self.__calculate_path_probabilities(visited_nodes) 122 | visited_nodes.append(self.__random_choose(probabilities)) 123 | 124 | # calculate fitness 125 | fitness = self.__calculate_visited_fitness(visited_nodes) 126 | ant_result.append((visited_nodes, fitness)) 127 | # update best 128 | if fitness < self.__best_fitness: 129 | self.__best_fitness = fitness 130 | self.__best_result = visited_nodes 131 | 132 | # evaporate the pheromones on each path and increase a base value. 133 | for start, value1 in enumerate(self.__path_pheromones): 134 | for end, value2 in enumerate(value1): 135 | self.__path_pheromones[(start, end)] *= (1 - self.__evaporation) 136 | self.__path_pheromones[(start, end)] += 1 137 | 138 | # update pheromone 139 | for result in ant_result: 140 | self.__update_path_pheromones(result[0], result[1]) 141 | 142 | def run(self): 143 | for generation in range(self.__iterations): 144 | self.__execute_single_generation(generation) 145 | print('best fitness #{}: {}'.format(generation, self.__best_fitness)) 146 | 147 | return (self.__best_result, self.__best_fitness) 148 | 149 | if __name__ == '__main__': 150 | random.seed(1) 151 | city_info = { city_id: (random.random() * 100, random.random() * 100) for city_id in range(30) } 152 | print('cities:') 153 | print(city_info) 154 | ant = PythonAntTSP({ 155 | 'iterations': 20, 156 | 'ants': 100, 157 | 'alpha': 1, 158 | 'beta': 9, 159 | 'evaporation': 0.9, 160 | 'q': 10000, 161 | 'nodes': city_info 162 | }) 163 | 164 | result = ant.run() 165 | print('Length: {}'.format(result[1])) 166 | print('Shortest Path: ' + ' => '.join(str(g) for g in result[0])) 167 | utils.plot_tsp_result(city_info, result[0]) 168 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/memory_usage/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import sys 5 | sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) 6 | 7 | import math 8 | import time 9 | import utils 10 | import numpy 11 | import pyopencl as cl 12 | 13 | 14 | def get_context(): 15 | contexts = [] 16 | platforms = cl.get_platforms() 17 | for platform in platforms: 18 | devices = platform.get_devices() 19 | for device in devices: 20 | try: 21 | context = cl.Context(devices=[device]) 22 | contexts.append(context) 23 | except: 24 | print('Can NOT create context from P(%s)-D(%s)'%(platform, device)) 25 | continue 26 | return contexts[0] if len(contexts) > 0 else None 27 | 28 | def build_program(ctx, filename): 29 | prog = None 30 | try: 31 | f = open(filename, 'r') 32 | fstr = ''.join(f.readlines()) 33 | f.close() 34 | # -Werror : Make all warnings into errors. 35 | # https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clBuildProgram.html 36 | prog = cl.Program(ctx, fstr).build(options=['-Werror'], cache_dir=None); 37 | except: 38 | import traceback 39 | traceback.print_exc() 40 | return prog 41 | 42 | def create_queue(ctx): 43 | return cl.CommandQueue(ctx) 44 | 45 | def create_bytearray(ctx, size): 46 | mf = cl.mem_flags 47 | py_buffer = numpy.zeros(size, dtype=numpy.int32) 48 | cl_buffer = cl.Buffer(ctx, 49 | mf.READ_WRITE | mf.COPY_HOST_PTR, 50 | hostbuf=py_buffer) 51 | return py_buffer, cl_buffer 52 | 53 | def create_local_bytearray(size): 54 | return cl.LocalMemory(size) 55 | 56 | def get_work_item_dimension(ctx): 57 | from pyopencl import context_info as ci 58 | from pyopencl import device_info as di 59 | devices = ctx.get_info(ci.DEVICES) 60 | assert len(devices) == 1 61 | dev = devices[0] 62 | # print('Max WI Dimensions : {}'.format(dev.get_info(di.MAX_WORK_ITEM_DIMENSIONS))) 63 | WGSize = dev.get_info(di.MAX_WORK_GROUP_SIZE) 64 | WISize = dev.get_info(di.MAX_WORK_ITEM_SIZES) 65 | 66 | LM = dev.get_info(di.LOCAL_MEM_SIZE) 67 | print('LM Size : {}'.format(LM)) 68 | print('Max WG Size : {}'.format(WGSize)) 69 | print('Max WI Size : {}'.format(WISize)) 70 | return WGSize, WISize 71 | 72 | def get_args(ctx, kernal_func_name, total_work_items): 73 | args = None 74 | py_in, dev_in = create_bytearray(ctx, total_work_items) 75 | py_out, dev_out = create_bytearray(ctx, total_work_items) 76 | if kernal_func_name == 'test_input': 77 | local_array_size = 8192 78 | args = (numpy.int32(total_work_items), 79 | dev_in, dev_out, 80 | create_local_bytearray(4 * local_array_size), 81 | numpy.int32(local_array_size),) 82 | elif kernal_func_name == 'test': 83 | args = (numpy.int32(total_work_items), 84 | dev_in, dev_out,) 85 | return args, (py_out, dev_out) 86 | 87 | def evaluate(ctx, prog, queue, kernal_func_name, total_work_items, work_items_per_group, args, outs = None): 88 | 89 | min_time = None 90 | min_time_gws = None 91 | min_time_lws = None 92 | 93 | max_wgsize, wisize = get_work_item_dimension(ctx) 94 | assert total_work_items <= wisize[0] * wisize[1] * wisize[2] 95 | 96 | iter_global_WIs= int(math.log(total_work_items, 2)) 97 | for g_factor in range(iter_global_WIs+1): 98 | print('=========================================== ') 99 | g_f_x = int(math.pow(2, g_factor)) 100 | g_wi_size = (int(total_work_items/g_f_x), g_f_x, ) 101 | print(' Global Work Group Size : {}'.format(g_wi_size)) 102 | iterations = int(math.log(work_items_per_group, 2)) 103 | for factor in range(iterations+1): 104 | l_f_x = int(math.pow(2, factor)) 105 | l_wi_size = (int(work_items_per_group/l_f_x), l_f_x, ) 106 | if l_wi_size[1] > g_wi_size[1] or l_wi_size[0] > g_wi_size[0]: 107 | # Local id dimensions should not exceed global dimensions. 108 | continue 109 | print('-------- ') 110 | print(' Local Work Group Size : {}'.format(l_wi_size)) 111 | 112 | divided_wg_info = [int(gwi/l_wi_size[idx]) for idx, gwi in enumerate(g_wi_size)] 113 | print(' Divided Work Groups Info : {}'.format(divided_wg_info)) 114 | start_time = time.perf_counter() 115 | 116 | caller = eval('prog.{}'.format(kernal_func_name)) 117 | caller(queue, g_wi_size, l_wi_size, *args).wait() 118 | 119 | elapsed_time = time.perf_counter() - start_time 120 | if not min_time: 121 | min_time = elapsed_time 122 | min_time_gws = g_wi_size 123 | min_time_lws = l_wi_size 124 | else: 125 | if elapsed_time <= min_time: 126 | min_time = elapsed_time 127 | min_time_gws = g_wi_size 128 | min_time_lws = l_wi_size 129 | 130 | if outs: 131 | cl.enqueue_read_buffer(queue, outs[1], outs[0]) 132 | print('**************************************** ') 133 | print(outs[0]) 134 | print(' Best Global WI Info : {}'.format(min_time_gws)) 135 | print(' Best Local WI Info : {}'.format(min_time_lws)) 136 | print(' Best Elapsed Time : {}'.format(min_time)) 137 | 138 | lines = '' 139 | def get_input(): 140 | global lines 141 | data = None 142 | try: 143 | if sys.platform in ['linux', 'darwin']: 144 | import select 145 | time.sleep(0.01) 146 | if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): 147 | data = sys.stdin.readline().rstrip() 148 | elif sys.platform == 'win32': 149 | import msvcrt 150 | time.sleep(0.01) 151 | if msvcrt.kbhit(): 152 | data = msvcrt.getch().decode('utf-8') 153 | if data == '\r': 154 | # Enter is pressed 155 | data = lines 156 | lines = '' 157 | else: 158 | lines += data 159 | print(data) 160 | data = None 161 | else: 162 | pass 163 | except KeyboardInterrupt: 164 | data = 'exit' 165 | return data 166 | 167 | if __name__ == '__main__': 168 | ctx = get_context() 169 | prog = None 170 | print('Enter 1 to test local memory usage') 171 | print('Enter 2 to test private memory usage') 172 | while True: 173 | user_input = get_input() 174 | if user_input == '1': 175 | prog = build_program(ctx, 'test_local.c') 176 | break 177 | elif user_input == '2': 178 | prog = build_program(ctx, 'test_private.c') 179 | break 180 | else: 181 | pass 182 | 183 | total_WorkItems = 1024 184 | # https://software.intel.com/sites/landingpage/opencl/optimization-guide/Work-Group_Size_Considerations.htm 185 | recommended_wi_per_group = 8 186 | kernal_func_name = 'test_input' 187 | args, outs = get_args(ctx, kernal_func_name, total_WorkItems) 188 | 189 | cwg, pwgs, lm, pm = None, None, None, None 190 | if ctx and prog: 191 | cwg, pwgs, lm, pm = utils.calculate_estimated_kernel_usage(prog, ctx, kernal_func_name) 192 | else: 193 | print('Nothing is calculated !') 194 | 195 | queue = create_queue(ctx) 196 | evaluate(ctx, prog, queue, kernal_func_name, total_WorkItems, recommended_wi_per_group, args, outs = outs) 197 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/memory_usage/test_local.c: -------------------------------------------------------------------------------- 1 | 2 | #define LM_SIZE 8192 3 | 4 | __kernel void test(int size, global int* in, global int* out) 5 | { 6 | int2 globalId = (int2)(get_global_id(0), get_global_id(1)); 7 | int2 localId = (int2)(get_local_id(0), get_local_id(1)); 8 | int2 groupId = (int2)(get_group_id (0), get_group_id (1)); 9 | int2 globalSize = (int2)(get_global_size(0), get_global_size(1)); 10 | int2 locallSize = (int2)(get_local_size(0), get_local_size(1)); 11 | if (globalId.x + globalId.y * globalSize.x >= size) { 12 | return; 13 | } 14 | 15 | int gIdx = globalId.x + globalId.y * globalSize.x; 16 | /* 17 | * Device local memory size can be queired from 18 | import pyopencl as cl 19 | cl.Kernel.get_work_group_info(cl.kernel_work_group_info.LOCAL_MEM_SIZE, cl.Device) 20 | */ 21 | 22 | // The local memory usage will be 4*LM_SIZE bytes. 23 | // You may adjust LM_SIZE to test if OUT OF RESOURCES while compiling. 24 | __local int lv[LM_SIZE]; 25 | int lIdx = gIdx % LM_SIZE; 26 | lv[lIdx] = globalId.y + globalId.x * globalSize.y; 27 | 28 | /* 29 | * On Intel CPU, 128 bytes private memory is used for the barrier below. 30 | */ 31 | // barrier(CLK_LOCAL_MEM_FENCE); 32 | out[gIdx] = lv[lIdx] - gIdx; 33 | } 34 | 35 | __kernel void test_input(int size, global int* in, global int* out, local int* lv, int lv_size) 36 | { 37 | int2 globalId = (int2)(get_global_id(0), get_global_id(1)); 38 | int2 localId = (int2)(get_local_id(0), get_local_id(1)); 39 | int2 groupId = (int2)(get_group_id (0), get_group_id (1)); 40 | int2 globalSize = (int2)(get_global_size(0), get_global_size(1)); 41 | int2 locallSize = (int2)(get_local_size(0), get_local_size(1)); 42 | if (globalId.x + globalId.y * globalSize.x >= size) { 43 | return; 44 | } 45 | 46 | int gIdx = globalId.x + globalId.y * globalSize.x; 47 | /* 48 | * Device local memory size can be queired from 49 | import pyopencl as cl 50 | cl.Kernel.get_work_group_info(cl.kernel_work_group_info.LOCAL_MEM_SIZE, cl.Device) 51 | */ 52 | 53 | // The local memory usage will be 4*LM_SIZE bytes. 54 | // You may adjust LM_SIZE to test if OUT OF RESOURCES while compiling. 55 | int lIdx = gIdx % lv_size; 56 | lv[lIdx] = globalId.y + globalId.x * globalSize.y; 57 | if (lIdx >= 512) { 58 | lv[lIdx] -= 128; 59 | } 60 | /* 61 | * On Intel CPU, 128 bytes private memory is used for the barrier below. 62 | */ 63 | // barrier(CLK_LOCAL_MEM_FENCE); 64 | out[gIdx] = lv[lIdx] - gIdx; 65 | } 66 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/memory_usage/test_private.c: -------------------------------------------------------------------------------- 1 | 2 | int calcutate(int index) 3 | { 4 | int a = (index * 32) & 128; 5 | return a; 6 | } 7 | 8 | #define PM_SIZE 10240 + 4096 + 200 9 | 10 | __kernel void test(int size, global int* in, global int* out) 11 | { 12 | int idx = get_global_id(0); 13 | // out of bound kernel task for padding 14 | 15 | if (idx >= size) { 16 | return; 17 | } 18 | 19 | /* 20 | On Intel CPU, the private memroy limitation is 64 KB. 21 | */ 22 | int ga[PM_SIZE] = {1}; 23 | 24 | /* 25 | On Intel CPU, private memory will be used more efficient if the barrier below is used. 26 | That is, we can create larger ga. 27 | */ 28 | // barrier(CLK_LOCAL_MEM_FENCE); 29 | 30 | out[idx] = ga[idx%PM_SIZE]; 31 | } 32 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/simulated_annealing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/evaluation/simulated_annealing/__init__.py -------------------------------------------------------------------------------- /OpenCLGA/evaluation/simulated_annealing/ocl_sa.cl: -------------------------------------------------------------------------------- 1 | 2 | #include "ga_utils.cl" 3 | 4 | float calc_linear_distance(float x1, float y1, float x2, float y2) 5 | { 6 | return sqrt(pown(x2 - x1, 2) + pown(y2 - y1, 2)); 7 | } 8 | 9 | float calc_cost(local int* solution, global float* xy) 10 | { 11 | float cost = 0.0; 12 | int next_i, x, y, nx, ny; 13 | for (int i = 0; i < SOLUTION_SIZE; i++) { 14 | next_i = (i+1) % SOLUTION_SIZE; 15 | x = xy[solution[i]*2]; 16 | y = xy[solution[i]*2+1]; 17 | nx = xy[solution[next_i]*2]; 18 | ny = xy[solution[next_i]*2+1]; 19 | cost += calc_linear_distance(x, y, nx, ny); 20 | } 21 | return cost; 22 | } 23 | 24 | float acceptance_probability(float old_cost, float new_cost, float temperature) 25 | { 26 | if (new_cost < old_cost) { 27 | return 1.0; 28 | } 29 | return exp((old_cost - new_cost) / temperature); 30 | } 31 | 32 | void find_neighbor(uint* rand_holder, local int* ori_solution, 33 | local int* neighbor_solution) 34 | { 35 | int rndIdxA, rndIdxB; 36 | rndIdxA = rand_range(rand_holder, SOLUTION_SIZE); 37 | rndIdxB = rand_range(rand_holder, SOLUTION_SIZE); 38 | while (rndIdxA == rndIdxB) { 39 | rndIdxB = rand_range(rand_holder, SOLUTION_SIZE); 40 | } 41 | neighbor_solution[rndIdxA] = ori_solution[rndIdxB]; 42 | neighbor_solution[rndIdxB] = ori_solution[rndIdxA]; 43 | } 44 | 45 | __kernel void ocl_sa_populate_solutions(int iterations, 46 | float temperature, 47 | float terminate_temperature, 48 | float alpha, 49 | global int* solutions, 50 | global uint* rand_holder, 51 | global float* xy, 52 | global float* costs) 53 | { 54 | int idx = get_global_id(0); 55 | 56 | if (idx >= NUM_OF_SOLUTION) { 57 | return; 58 | } 59 | // create a private variable for each kernel to hold randome number. 60 | uint ra[1]; 61 | init_rand(rand_holder[idx], ra); 62 | 63 | int elements[] = ELEMENT_SPACE; 64 | int rndIdx; 65 | 66 | __local int target_solution[SOLUTION_SIZE]; 67 | __local int neighbor_solution[SOLUTION_SIZE]; 68 | 69 | for (int i = 0; i < SOLUTION_SIZE - 1; i++) { 70 | rndIdx = rand_range(ra, (SOLUTION_SIZE - i - 1)); 71 | target_solution[i] = elements[rndIdx]; 72 | elements[rndIdx] = elements[SOLUTION_SIZE - i - 1]; 73 | } 74 | target_solution[SOLUTION_SIZE - 1] = elements[0]; 75 | 76 | int iter; 77 | float ap; 78 | float target_cost, neighbor_cost; 79 | float temp_temperature = temperature; 80 | 81 | target_cost = calc_cost(target_solution, xy); 82 | while (temp_temperature > terminate_temperature) { 83 | iter = 1; 84 | while (iter <= iterations) { 85 | for (int i = 0; i < SOLUTION_SIZE; i++) { 86 | neighbor_solution[i] = target_solution[i]; 87 | } 88 | find_neighbor(ra, target_solution, neighbor_solution); 89 | neighbor_cost = calc_cost(neighbor_solution, xy); 90 | 91 | ap = acceptance_probability(target_cost, neighbor_cost, temp_temperature); 92 | if (ap > rand_prob(ra)) { 93 | for (int i = 0; i < SOLUTION_SIZE; i++) { 94 | target_solution[i] = neighbor_solution[i]; 95 | target_cost = neighbor_cost; 96 | } 97 | } 98 | iter += 1; 99 | } 100 | temp_temperature = temp_temperature * alpha; 101 | } 102 | 103 | global int* result_solution = solutions + idx * SOLUTION_SIZE; 104 | for (int i = 0; i < SOLUTION_SIZE; i++) { 105 | result_solution[i] = target_solution[i]; 106 | } 107 | costs[idx] = target_cost; 108 | } 109 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/simulated_annealing/ocl_sa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import sys 4 | sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) 5 | 6 | from abc import ABCMeta 7 | from utils import calc_linear_distance, plot_tsp_result, plot_grouping_result 8 | import math 9 | import numpy 10 | import random 11 | import pyopencl as cl 12 | 13 | from sa import SimulatedAnnealing, TSPSolution 14 | 15 | class OclTSPSolution(TSPSolution): 16 | def __init__(self, city_info): 17 | TSPSolution.__init__(self, city_info) 18 | 19 | self.size_of_solution = len(city_info.keys()) 20 | self.num_of_solutions = 100 21 | 22 | @property 23 | def elements_kernel_str(self): 24 | # Chromosome can use this function to declare elements array 25 | elements_str = ', '.join([str(v) for v in list(self.city_info.keys())]) 26 | return '{' + elements_str + '}\n' 27 | 28 | def kernelize(self): 29 | candidates = '#define ELEMENT_SPACE ' + self.elements_kernel_str + '\n' 30 | populats = '#define NUM_OF_SOLUTION ' + str(self.num_of_solutions) + '\n' 31 | defines = '#define SOLUTION_SIZE ' + str(self.size_of_solution) + '\n' 32 | return candidates + populats + defines 33 | 34 | def get_solution_info(self): 35 | self.__np_solution = numpy.zeros(self.size_of_solution * self.num_of_solutions, dtype=numpy.int32) 36 | return self.num_of_solutions, self.__np_solution 37 | 38 | def get_cost_buffer(self): 39 | self.__np_costs = numpy.zeros(self.num_of_solutions, dtype=numpy.float32) 40 | return self.__np_costs 41 | 42 | def create_internal_buffer(self, ctx): 43 | cityxy = [(self.city_info[idx][0], self.city_info[idx][1]) for idx in range(len(self.city_info))] 44 | self.__np_cityxy = numpy.array(cityxy, dtype=numpy.float32) 45 | 46 | mf = cl.mem_flags 47 | 48 | self.__dev_cityxy = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 49 | hostbuf=self.__np_cityxy) 50 | 51 | self.__dev_cityxy = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 52 | hostbuf=self.__np_cityxy) 53 | 54 | self.__np_iterations = numpy.int32(self.iterations) 55 | self.__np_temperature = numpy.float32(self.temperature) 56 | self.__np_terminate_temperature = numpy.float32(self.terminate_temperature) 57 | self.__np_alpha = numpy.float32(self.alpha) 58 | 59 | def anneal(self, prog, queue, rand, solutions, costs): 60 | prog.ocl_sa_populate_solutions(queue, 61 | (self.num_of_solutions,), 62 | (1,), 63 | self.__np_iterations, 64 | self.__np_temperature, 65 | self.__np_terminate_temperature, 66 | self.__np_alpha, 67 | solutions, 68 | rand, 69 | self.__dev_cityxy, 70 | costs).wait() 71 | 72 | cl.enqueue_copy(queue, self.__np_solution, solutions).wait() 73 | cl.enqueue_copy(queue, self.__np_costs, costs).wait() 74 | self.plot_best_solution() 75 | 76 | def plot_best_solution(self): 77 | min_cost = float('inf') 78 | min_idx = 0 79 | for idx, cost in enumerate(self.__np_costs): 80 | if cost < min_cost: 81 | min_cost = cost 82 | min_idx = idx 83 | 84 | solution = self.__np_solution[min_idx*self.size_of_solution:(min_idx+1)*self.size_of_solution] 85 | plot_tsp_result(self.city_info, solution) 86 | 87 | def plot_all_solutions(self): 88 | for i in range(self.num_of_solutions): 89 | solution = [] 90 | if i == self.num_of_solutions - 1: 91 | solution = self.__np_solution[i * self.size_of_solution:] 92 | else: 93 | solution = self.__np_solution[i * self.size_of_solution:(i+1) * self.size_of_solution] 94 | plot_tsp_result(self.city_info, solution) 95 | 96 | class OpenCLSA(SimulatedAnnealing): 97 | def __init__(self, cls_solution, options): 98 | SimulatedAnnealing.__init__(self, cls_solution) 99 | 100 | extra_path = options.get('extra_include_path', []) 101 | cl_context = options.get('cl_context', None) 102 | 103 | self.__debug_mode = True 104 | self.__init_cl(cl_context, extra_path) 105 | self.__create_program() 106 | self.__init_cl_member() 107 | pass 108 | 109 | def __init_cl(self, cl_context, extra_include_path): 110 | # create OpenCL context, queue, and memory 111 | # NOTE: Please set PYOPENCL_CTX=N (N is the device number you want to use) 112 | # at first if it's in external_process mode, otherwise a exception 113 | # will be thrown, since it's not in interactive mode. 114 | # TODO: Select a reliable device during runtime by default. 115 | self.__ctx = cl_context if cl_context is not None else cl.create_some_context() 116 | self.__queue = cl.CommandQueue(self.__ctx) 117 | self.__include_path = [] 118 | 119 | ocl_kernel_path = os.path.join(os.path.dirname(os.path.abspath('../../' + __file__)), 'kernel').replace(' ', '\\ ') 120 | paths = extra_include_path + [ocl_kernel_path] 121 | for path in paths: 122 | escapedPath = path.replace(' ', '^ ') if sys.platform.startswith('win')\ 123 | else path.replace(' ', '\\ ') 124 | # After looking into the source code of pyopencl/__init__.py 125 | # '-I' and folder path should be sepearetd. And ' should not included in string path. 126 | self.__include_path.append('-I') 127 | self.__include_path.append(os.path.join(os.getcwd(), escapedPath)) 128 | 129 | def __create_program(self): 130 | self.__include_code = self.sas.kernelize() 131 | codes = self.__include_code + '\n' 132 | # codes = self.__args_codes + '\n' +\ 133 | # self.__populate_codes + '\n' +\ 134 | # self.__evaluate_code + '\n' +\ 135 | # self.__include_code + '\n' +\ 136 | # self.__fitness_kernel_str 137 | 138 | f = open('ocl_sa.cl', 'r') 139 | fstr = ''.join(f.readlines()) 140 | f.close() 141 | 142 | if self.__debug_mode: 143 | fdbg = open('final.cl', 'w') 144 | fdbg.write(codes + fstr) 145 | fdbg.close() 146 | 147 | self.__prg = cl.Program(self.__ctx, codes + fstr).build(self.__include_path); 148 | 149 | def __init_cl_member(self): 150 | self.__np_costs = self.sas.get_cost_buffer() 151 | num_of_solution, self.__np_solution = self.sas.get_solution_info() 152 | 153 | mf = cl.mem_flags 154 | 155 | # Random number should be given by Host program because OpenCL doesn't have a random number 156 | # generator. We just include one, Noise.cl. 157 | rnum = [random.randint(0, 4294967295) for i in range(num_of_solution)] 158 | ## note: numpy.random.rand() gives us a list float32 and we cast it to uint32 at the calling 159 | ## of kernel function. It just views the original byte order as uint32. 160 | self.__dev_rnum = cl.Buffer(self.__ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 161 | hostbuf=numpy.array(rnum, dtype=numpy.uint32)) 162 | 163 | self.__dev_costs = cl.Buffer(self.__ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 164 | hostbuf=self.__np_costs) 165 | self.__dev_solution = cl.Buffer(self.__ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 166 | hostbuf=self.__np_solution) 167 | 168 | self.sas.create_internal_buffer(self.__ctx) 169 | 170 | ## To save the annealing state 171 | def save(self): 172 | pass 173 | 174 | ## To restore the annealing state 175 | def restore(self): 176 | pass 177 | 178 | ## Start annealing 179 | def anneal(self): 180 | self.sas.anneal(self.__prg, 181 | self.__queue, 182 | self.__dev_rnum, 183 | self.__dev_solution, 184 | self.__dev_costs) 185 | 186 | pass 187 | 188 | if __name__ == '__main__': 189 | sa = OpenCLSA(OclTSPSolution, {}) 190 | sa.anneal() -------------------------------------------------------------------------------- /OpenCLGA/evaluation/simulated_annealing/sa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import sys 4 | sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) 5 | 6 | from abc import ABCMeta 7 | from utils import calc_linear_distance, plot_tsp_result, plot_grouping_result 8 | import math 9 | import random 10 | 11 | class SAImpl(metaclass = ABCMeta): 12 | def __init__(self): 13 | self.temperature = 1000.0 14 | self.alpha = 0.9 15 | self.terminate_temperature = 0.00001 16 | self.iterations = 500 17 | pass 18 | 19 | ## Get the initial solution to anneal 20 | def get_init_solution(self): 21 | return None 22 | ## Calculate the cost of the solution 23 | def cost(self, solution): 24 | return None 25 | ## Return a new neighbor solution 26 | def neighbor(self, solution): 27 | return None 28 | ## Return a probability to decide whether accpet or not. 29 | def acceptance_probability(self, old_cost, new_cost, temperature): 30 | return None 31 | ## Start annealing 32 | def anneal(self): 33 | solution = self.get_init_solution() 34 | old_cost = self.cost(solution) 35 | # print('1st round : cost = {} '.format(old_cost)) 36 | T = self.temperature 37 | T_min = self.terminate_temperature 38 | alpha = self.alpha 39 | while T > T_min: 40 | i = 1 41 | print('T={}'.format(T)) 42 | while i <= self.iterations: 43 | new_solution = self.neighbor(solution) 44 | new_cost = self.cost(new_solution) 45 | ap = self.acceptance_probability(old_cost, new_cost, T) 46 | if ap > random.random(): 47 | solution = new_solution 48 | old_cost = new_cost 49 | # print('i={} round : cost = {} '.format(T, i, old_cost)) 50 | i += 1 51 | T = T*alpha 52 | return solution 53 | 54 | class ClassificationSolution(SAImpl): 55 | def __init__(self, group_info): 56 | SAImpl.__init__(self) 57 | self.group_info = group_info 58 | 59 | def get_init_solution(self): 60 | return self.group_info['init_solution'] 61 | 62 | @staticmethod 63 | def get_init_params(): 64 | # The number of points randomly generated 65 | num_points = 40 66 | random.seed() 67 | point_ids = list(range(0, num_points)) 68 | point_info = {point_id: (random.random() * 100, random.random() * 100) for point_id in point_ids} 69 | pointX = [point_info[v][0] for v in point_info] 70 | pointY = [point_info[v][1] for v in point_info] 71 | 72 | # The number of group you want to divide. 73 | numOfGroups = 5 74 | group_id_set = list(range(0, numOfGroups)) 75 | init_solution = [random.randint(0,numOfGroups-1) for x in range(num_points)] 76 | info = { 'num_of_group' : numOfGroups, 'init_solution' : init_solution, 77 | 'X' : pointX, 'Y' : pointY, 'g_set' : set(group_id_set), 78 | 'point_info' : point_info} 79 | return info 80 | 81 | ## For classification, we calculate the total distance among all points in 82 | ## the same group. 83 | def cost(self, solution): 84 | total = len(solution) 85 | cost = 0 86 | for i in range(self.group_info['num_of_group']): 87 | for j, gid in enumerate(solution): 88 | k = (j + 1) 89 | next_gid = gid 90 | while k < total: 91 | next_gid = solution[k] 92 | if gid == i and next_gid == i: 93 | cost += calc_linear_distance(self.group_info['X'][j], self.group_info['Y'][j], 94 | self.group_info['X'][k], self.group_info['Y'][k]) 95 | k += 1 96 | return cost 97 | 98 | ## Find a neighbor solution by swapping random two nodes. 99 | def neighbor(self, solution): 100 | neighbor = solution[:] 101 | total = len(solution) 102 | a = random.randint(0, total-1) 103 | b = random.randint(0, total-1) 104 | while a == b: 105 | b = random.randint(0, total-1) 106 | neighbor[a] = solution[b] 107 | neighbor[b] = solution[a] 108 | return neighbor 109 | 110 | def acceptance_probability(self, old_cost, new_cost, temperature): 111 | if new_cost < old_cost: 112 | return 1.0 113 | else: 114 | return math.exp(float(old_cost - new_cost) / temperature) 115 | 116 | def anneal(self): 117 | solution = SAImpl.anneal(self) 118 | plot_grouping_result(self.group_info['g_set'], solution, self.group_info['point_info']) 119 | return solution 120 | 121 | class TSPSolution(SAImpl): 122 | def __init__(self, tsp_info): 123 | SAImpl.__init__(self) 124 | self.tsp_info = tsp_info 125 | 126 | def get_init_solution(self): 127 | return self.tsp_info['init_solution'] 128 | 129 | @staticmethod 130 | def get_init_params(): 131 | num_cities = 20 132 | random.seed() 133 | city_ids = list(range(0, num_cities)) 134 | city_info = {city_id: (random.random() * 100, random.random() * 100) for city_id in city_ids} 135 | solution = list(city_info.keys()) 136 | random.shuffle(solution) 137 | tsp_info = {} 138 | tsp_info['init_solution'] = solution 139 | tsp_info['city_info'] = city_info 140 | return tsp_info 141 | 142 | ## For TSP, we calculate the total distance between all cities. 143 | def cost(self, solution): 144 | city_info = self.tsp_info['city_info'] 145 | total = len(city_info.keys()) 146 | cost = 0 147 | for index, cid in enumerate(solution): 148 | first_city = cid 149 | next_city = solution[(index + 1) % total] 150 | 151 | cost += calc_linear_distance(city_info[first_city][0], city_info[first_city][1], 152 | city_info[next_city][0], city_info[next_city][1]) 153 | return cost 154 | 155 | ## Find a neighbor solution by swapping random two nodes. 156 | def neighbor(self, solution): 157 | city_info = self.tsp_info['city_info'] 158 | neighbor = solution[:] 159 | total = len(city_info.keys()) 160 | a = random.randint(0, total-1) 161 | b = random.randint(0, total-1) 162 | while a == b: 163 | b = random.randint(0, total-1) 164 | neighbor[a] = solution[b] 165 | neighbor[b] = solution[a] 166 | return neighbor 167 | 168 | def acceptance_probability(self, old_cost, new_cost, temperature): 169 | if new_cost < old_cost: 170 | return 1.0 171 | else: 172 | return math.exp(float(old_cost - new_cost) / temperature) 173 | 174 | def anneal(self): 175 | solution = SAImpl.anneal(self) 176 | plot_tsp_result(self.tsp_info['city_info'], solution) 177 | return solution 178 | 179 | class SimulatedAnnealing(object): 180 | def __init__(self, cls_solution): 181 | self.sas = cls_solution(cls_solution.get_init_params()) 182 | pass 183 | 184 | ## To save the annealing state 185 | def save(self): 186 | pass 187 | 188 | ## To restore the annealing state 189 | def restore(self): 190 | pass 191 | 192 | ## Start annealing 193 | def anneal(self): 194 | best_solution = self.sas.anneal() 195 | return best_solution 196 | 197 | def main(): 198 | print('Input 1 for SA-TSP ; 2 for SA-Classification') 199 | try: 200 | sa = None 201 | int_choice = int(input()) 202 | if int_choice == 1: 203 | sa = SimulatedAnnealing(TSPSolution) 204 | elif int_choice == 2: 205 | sa = SimulatedAnnealing(ClassificationSolution) 206 | else: 207 | print('Unsupported input, bye !') 208 | return None 209 | sa.anneal() 210 | except Exception as e: 211 | print('Exception : {}'.format(e)) 212 | 213 | if __name__ == '__main__': 214 | main() 215 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/type_casting/casting.c: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | float data[GLOBAL_SIZE]; 3 | } TypedStruct; 4 | 5 | __kernel void casting_test(__global const float* a_g, __global const float* b_g, 6 | __global float *res_g) { 7 | 8 | int id = get_global_id(0); 9 | if (id >= GLOBAL_SIZE) { 10 | return; 11 | } 12 | __global TypedStruct* tsA = (__global TypedStruct*) a_g; 13 | __global TypedStruct* tsB = (__global TypedStruct*) b_g; 14 | __global TypedStruct* tsR = (__global TypedStruct*) res_g; 15 | tsR->data[id] = tsA->data[id] + tsB->data[id]; 16 | } 17 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/type_casting/casting.py: -------------------------------------------------------------------------------- 1 | import pyopencl as cl 2 | import numpy as np 3 | 4 | def run(vector): 5 | ctx = cl.create_some_context() 6 | queue = cl.CommandQueue(ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) 7 | f = open('casting_vector.c' if vector else 'casting.c', 'r') 8 | fstr = ''.join(f.readlines()) 9 | f.close() 10 | 11 | data_size = 100; 12 | global_size = int(data_size / 4) if vector else data_size 13 | 14 | if vector: 15 | struct = 'typedef struct {\n' 16 | code = ' switch(id) {\n' 17 | codeTemp = ' case {0}:\n tsR->data{0} = tsA->data{0} + tsB->data{0};\n break;\n' 18 | for i in range(global_size): 19 | struct += ' float4 data' + str(i) + ';\n' 20 | code += codeTemp.format(i) 21 | struct += '} TypedStruct2;\n' 22 | code += ' }\n' 23 | fstr = fstr.replace('%code_generation%', code); 24 | fstr = '#define GLOBAL_SIZE ' + str(global_size) + '\n' + struct + fstr 25 | else: 26 | fstr = '#define GLOBAL_SIZE ' + str(global_size) + '\n' + fstr; 27 | 28 | print('=' * 50) 29 | print(fstr) 30 | print('-' * 50) 31 | 32 | a_np = np.random.rand(data_size).astype(np.float32) 33 | b_np = np.random.rand(data_size).astype(np.float32) 34 | 35 | mf = cl.mem_flags 36 | a_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=a_np) 37 | b_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=b_np) 38 | 39 | res_g = cl.Buffer(ctx, mf.WRITE_ONLY, a_np.nbytes) 40 | 41 | prg = cl.Program(ctx, fstr).build(); 42 | exec_evt = prg.casting_test(queue, (global_size,), None, a_g, b_g, res_g) 43 | exec_evt.wait() 44 | 45 | res_np = np.empty_like(a_np) 46 | cl.enqueue_copy(queue, res_np, res_g).wait() 47 | print(res_np) 48 | 49 | elapsed = 1e-9 * (exec_evt.profile.end - exec_evt.profile.start) 50 | print('Vector: {0} => Execution time of test: {1}s'.format(vector, elapsed)) 51 | 52 | if __name__ == '__main__': 53 | run(False) 54 | run(True) 55 | -------------------------------------------------------------------------------- /OpenCLGA/evaluation/type_casting/casting_vector.c: -------------------------------------------------------------------------------- 1 | 2 | __kernel void casting_test(__global const float4* a_g, __global const float4* b_g, 3 | __global float4 *res_g) { 4 | 5 | int id = get_global_id(0); 6 | if (id >= (GLOBAL_SIZE)) { 7 | return; 8 | } 9 | __global TypedStruct2* tsA = (__global TypedStruct2*) a_g; 10 | __global TypedStruct2* tsB = (__global TypedStruct2*) b_g; 11 | __global TypedStruct2* tsR = (__global TypedStruct2*) res_g; 12 | 13 | %code_generation% 14 | } 15 | -------------------------------------------------------------------------------- /OpenCLGA/kernel/ga_utils.cl: -------------------------------------------------------------------------------- 1 | #ifndef __ga_utils__ 2 | #define __ga_utils__ 3 | 4 | #include "Noise.cl" 5 | 6 | /** 7 | * prints the value of chromosomes. We can also use this function to print a 8 | * single chromome with 1 value of num_of_chromosomes. 9 | * @param *chromosomes (global) the reference of chromosomes array 10 | * @param size_of_chromosome the size of a single chromesome 11 | * @param num_of_chromosomes the number of chromosomes in this array. 12 | * @param *fitnesses (global) the fitness array of all chromosomes. The size of 13 | * this array is num_of_chromosomes. 14 | */ 15 | void print_chromosomes(global int* chromosomes, int size_of_chromosome, 16 | int num_of_chromosomes, global float* fitnesses) 17 | { 18 | int idx = get_global_id(0); 19 | if (idx > 0) { 20 | // We use this function to dump all of chromosomes. In most of the cases, 21 | // we shouldn't let all threads to print result because it may give us too 22 | // many information. So, the first thread is the only one can dump infos. 23 | return; 24 | } 25 | for (int c = 0; c < num_of_chromosomes; c++) { 26 | int start = c * size_of_chromosome; 27 | printf("Chromosome[%d]/dist[%f]:", c, fitnesses[c]); 28 | for (int i = 0; i < size_of_chromosome; i++) { 29 | printf("->(%d)", chromosomes[start+i]); 30 | } 31 | printf("\n"); 32 | } 33 | printf("\n"); 34 | } 35 | 36 | /** 37 | * rand generates a random number between 0 to max value of uint. 38 | * NOTE : Since we cannot create a real random number in kernel, 39 | * By passing in a random value from python, and storing the last 40 | * random value generated from table, we could simulate a pesudo random 41 | * number in kernel. 42 | * @param *holder a pointer of uint for storing the last rand value. 43 | * @return a random uint value. 44 | */ 45 | uint rand(uint* holder) 46 | { 47 | uint b = ParallelRNG(holder[0]); 48 | uint c = ParallelRNG2(b, holder[0]); 49 | uint d = ParallelRNG3(c, b, holder[0]); 50 | holder[0] = c; 51 | return d; 52 | } 53 | 54 | /** 55 | * rand_range generates a random number between 0 <= return_vlue < range. 56 | * @param *holder a pointer of uint for storing the last rand value. 57 | * @param range the max value of random number. 58 | * @return a random uint value in the range. 59 | */ 60 | uint rand_range(uint* holder, uint range) 61 | { 62 | uint r = rand(holder) % range; 63 | return r; 64 | } 65 | 66 | /** 67 | * rand_range_exclude generates a random number between 0 < return_vlue < range. 68 | * But the value aExcluded is excluded. 69 | * @param *holder a pointer of uint for storing the last rand value. 70 | * @param range the max value of random number. 71 | * @param aExclude the excluded value 72 | * @return a random uint value in the range except aExcluded. 73 | */ 74 | uint rand_range_exclude(uint* holder, uint range, uint aExcluded) 75 | { 76 | uint r = rand(holder) % (range - 1); 77 | return r == aExcluded ? range - 1 : r; 78 | } 79 | 80 | /** 81 | * rand_prob generates a random number between 0 < return_vlue < 1 in float. 82 | * @param *holder a pointer of uint for storing the last rand value. 83 | * @return a random float value. 84 | */ 85 | float rand_prob(uint* holder) 86 | { 87 | uint r = rand(holder); 88 | float p = r / (float)UINT_MAX; 89 | return p; 90 | } 91 | 92 | /** 93 | * initialze the random seed. 94 | * @param seed the reandom seed. 95 | * @param *holder a pointer of uint for storing the last rand value. 96 | */ 97 | void init_rand(int seed, uint* holder) 98 | { 99 | holder[0] = ParallelRNG(seed); 100 | } 101 | 102 | /** 103 | * random choose a chromosome based on the ratio. For GA, we need to choose a 104 | * chromosome for crossover based on fitnesses. If a chromosome with better 105 | * fitness, the probability is higher. The ratio is an array with population in 106 | * size. The value in ratio array is the uniform[0, 1] distribution value. The 107 | * accumulated value of the whole array is 1. 108 | * @param *ratio (global) the probability array for each chromosomes. 109 | * @param *holder a pointer of uint for storing the last rand value. 110 | * @param num_of_chromosomes the size of ratio. 111 | */ 112 | int random_choose_by_ratio(global float* ratio, uint* holder, 113 | int num_of_chromosomes) 114 | { 115 | 116 | // generate a random number from between 0 and 1 117 | float rand_choose = rand_prob(holder); 118 | float accumulated = 0.0; 119 | int i; 120 | // random choose a chromosome based on probability of each chromosome. 121 | for (i = 0; i < num_of_chromosomes; i++) { 122 | accumulated += ratio[i]; 123 | if (accumulated > rand_choose) { 124 | return i; 125 | } 126 | } 127 | return num_of_chromosomes - 1; 128 | } 129 | 130 | /** 131 | * calc_min_max_fitness find the max and min value among all fitness values. 132 | * @param *fitnesses (global) the fitness value array of all chromosomes 133 | * @param num_of_chromosomes the number of chromosomes 134 | * @param *min (out) for returing the min fitness value 135 | * @param *max (out) for returning the max fitness value 136 | */ 137 | void calc_min_max_fitness(global float* fitnesses, int num_of_chromosomes, 138 | float* min, float* max) 139 | { 140 | for (int i = 0; i < num_of_chromosomes; i++) { 141 | max[0] = fmax(fitnesses[i], max[0]); 142 | min[0] = fmin(fitnesses[i], min[0]); 143 | } 144 | } 145 | 146 | /** 147 | * utils_calc_ratio find the best, worst, avg fitnesses among all chromosomes. 148 | * It also calculates the probability for each chromosomes based on their 149 | * fitness value. The best and worst definition is based on the initial options 150 | * of OpenCLGA. 151 | * @param *fitness (global) the fitness value array of all chromosomes 152 | * @param *ratio (global, out) the probability array of each chromosomes 153 | * @param num_of_chromosomes the number of chromosomes. 154 | */ 155 | void utils_calc_ratio(global float* fitness, 156 | global float* ratio, 157 | int num_of_chromosomes) 158 | { 159 | float local_min = INT_MAX; 160 | float local_max = 0; 161 | // OPTIMIZATION_FOR_MAX is set at ocl_ga.py 162 | float best; 163 | float worst; 164 | #if OPTIMIZATION_FOR_MAX 165 | calc_min_max_fitness(fitness, num_of_chromosomes, &local_max, &local_min); 166 | best = local_max; 167 | worst = local_min; 168 | #else 169 | calc_min_max_fitness(fitness, num_of_chromosomes, &local_min, &local_max); 170 | best = local_min; 171 | worst = local_max; 172 | #endif 173 | 174 | float temp_worst = worst; 175 | float diffTotal = 0; 176 | int i; 177 | // we use total and diff to calculate the probability for each chromosome 178 | for (i = 0; i < num_of_chromosomes; i++) { 179 | // to have a significant different between better and worst, we use square 180 | // of diff to calculate the probability. 181 | diffTotal += (temp_worst - fitness[i]) * (temp_worst - fitness[i]); 182 | } 183 | // calculate probability for each one 184 | for (i = 0; i < num_of_chromosomes; i++) { 185 | ratio[i] = (temp_worst - fitness[i]) * (temp_worst - fitness[i]) / 186 | diffTotal; 187 | } 188 | } 189 | 190 | #endif 191 | -------------------------------------------------------------------------------- /OpenCLGA/kernel/ocl_ga.cl: -------------------------------------------------------------------------------- 1 | #include "ga_utils.cl" 2 | 3 | /** 4 | * ocl_ga_calculate_fitness is a wrapper function to call specified fitness 5 | * function. To simplify the implementation of fitness calcuation, we handles 6 | * the multi-threading part and let implementor write the core calculation. 7 | * Note: this is a kernel function and will be called by python. 8 | * 9 | * @param *chromosomes (global) the chromosomes array 10 | * @param *fitness (global) the fitness array for each chromosomes. 11 | * @param FITNESS_ARGS the fitness arguments from ocl_ga options. 12 | */ 13 | __kernel void ocl_ga_calculate_fitness(global int* chromosomes, 14 | global float* fitness FITNESS_ARGS) 15 | { 16 | int idx = get_global_id(0); 17 | // out of bound kernel task for padding 18 | if (idx >= POPULATION_SIZE) { 19 | return; 20 | } 21 | // calls the fitness function specified by user and gives the chromosome for 22 | // current thread. 23 | CALCULATE_FITNESS(((global CHROMOSOME_TYPE*) chromosomes) + idx, 24 | fitness + idx, 25 | CHROMOSOME_SIZE, POPULATION_SIZE FITNESS_ARGV); 26 | } 27 | -------------------------------------------------------------------------------- /OpenCLGA/kernel/simple_chromosome.cl: -------------------------------------------------------------------------------- 1 | #ifndef __oclga_simple_chromosome__ 2 | #define __oclga_simple_chromosome__ 3 | 4 | #include "ga_utils.cl" 5 | 6 | typedef struct { 7 | int genes[SIMPLE_CHROMOSOME_GENE_SIZE]; 8 | } __SimpleChromosome; 9 | 10 | /* ============== populate functions ============== */ 11 | /** 12 | * simple_chromosome_do_populate populates a chromosome randomly. Unlike shuffler chromosome, it 13 | * chooses a gene randomly based on gene's element. 14 | * @param *chromosome (global, out) the target chromosome. 15 | * @param *rand_holder the random seed holder. 16 | */ 17 | void simple_chromosome_do_populate(global __SimpleChromosome* chromosome, 18 | uint* rand_holder) 19 | { 20 | uint gene_elements_size[] = SIMPLE_CHROMOSOME_GENE_ELEMENTS_SIZE; 21 | for (int i = 0; i < SIMPLE_CHROMOSOME_GENE_SIZE; i++) { 22 | // choose an element randomly based on each gene's element size. 23 | chromosome->genes[i] = rand_range(rand_holder, gene_elements_size[i]); 24 | } 25 | } 26 | 27 | /** 28 | * simple_chromosome_populate populates all chromosomes randomly. 29 | * Note: this is a kernel function and will be called by python. 30 | * @param *cs (global, out) all chromosomes where population to be stored. 31 | * @param *input_rand (global) random seeds. 32 | */ 33 | __kernel void simple_chromosome_populate(global int* cs, 34 | global uint* input_rand) 35 | { 36 | int idx = get_global_id(0); 37 | // out of bound kernel task for padding 38 | if (idx >= POPULATION_SIZE) { 39 | return; 40 | } 41 | // create a private variable for each kernel to hold randome number. 42 | uint ra[1]; 43 | init_rand(input_rand[idx], ra); 44 | simple_chromosome_do_populate(((global __SimpleChromosome*) cs) + idx, 45 | ra); 46 | input_rand[idx] = ra[0]; 47 | } 48 | /* ============== end of populating functions ============== */ 49 | 50 | /* ============== mutation functions ============== */ 51 | /** 52 | * mutate a single gene of a chromosome. 53 | * @param *chromosome (global) the chromosome for mutation. 54 | * @param *ra random seed holder. 55 | */ 56 | void simple_chromosome_do_mutate(global __SimpleChromosome* chromosome, 57 | uint* ra) 58 | { 59 | // create element size list 60 | uint elements_size[] = SIMPLE_CHROMOSOME_GENE_ELEMENTS_SIZE; 61 | uint gene_idx = rand_range(ra, SIMPLE_CHROMOSOME_GENE_SIZE); 62 | // use gene's mutate function to mutate it. 63 | SIMPLE_CHROMOSOME_GENE_MUTATE_FUNC(chromosome->genes + gene_idx, 64 | elements_size[gene_idx], ra); 65 | } 66 | /** 67 | * mutate a single gene of all chromosomes based on the prob_mutate. If a 68 | * chromosome pass the probability, a single gene of it will be mutated. 69 | * @param *chromosome (global) the chromosome for mutation. 70 | * @param *ra (global) random seed holder. 71 | * @param prob_mutate the probability of mutation. 72 | */ 73 | __kernel void simple_chromosome_mutate(global int* cs, 74 | global uint* input_rand, 75 | float prob_mutate) 76 | { 77 | int idx = get_global_id(0); 78 | // out of bound kernel task for padding 79 | if (idx >= POPULATION_SIZE) { 80 | return; 81 | } 82 | 83 | uint ra[1]; 84 | init_rand(input_rand[idx], ra); 85 | float prob_m = rand_prob(ra); 86 | if (prob_m > prob_mutate) { 87 | input_rand[idx] = ra[0]; 88 | return; 89 | } 90 | 91 | simple_chromosome_do_mutate((global __SimpleChromosome*) cs, ra); 92 | } 93 | 94 | /** 95 | * mutate all genes of all chromosomes based on the prob_mutate. Once a 96 | * chromosome passes the probability, all genes of it will be mutated. 97 | * @param *chromosome (global) the chromosome for mutation. 98 | * @param *ra (global) random seed holder. 99 | * @param prob_mutate the probability of mutation. 100 | */ 101 | __kernel void simple_chromosome_mutate_all(global int* cs, 102 | global uint* input_rand, 103 | float prob_mutate) 104 | { 105 | int idx = get_global_id(0); 106 | // out of bound kernel task for padding 107 | if (idx >= POPULATION_SIZE) { 108 | return; 109 | } 110 | uint elements_size[] = SIMPLE_CHROMOSOME_GENE_ELEMENTS_SIZE; 111 | int i; 112 | uint ra[1]; 113 | init_rand(input_rand[idx], ra); 114 | for (i = 0; i < SIMPLE_CHROMOSOME_GENE_SIZE; i++) { 115 | if (rand_prob(ra) > prob_mutate) { 116 | continue; 117 | } 118 | SIMPLE_CHROMOSOME_GENE_MUTATE_FUNC(cs + i, elements_size[i], ra); 119 | } 120 | 121 | input_rand[idx] = ra[0]; 122 | } 123 | /* ============== end of mutation functions ============== */ 124 | 125 | /* ============== crossover functions ============== */ 126 | /** 127 | * simple_chromosome_calc_ratio uses utils_calc_ratio to find the best, worst, 128 | * avg fitnesses among all chromosomes the probability for each chromosomes 129 | * based on their fitness value. 130 | * Note: this is a kernel function and will be called by python. 131 | * @param *fitness (global) the fitness value array of all chromosomes 132 | * @param *ratio (global, out) the probability array of each chromosomes 133 | * @seealso ::utils_calc_ratio 134 | */ 135 | __kernel void simple_chromosome_calc_ratio(global float* fitness, 136 | global float* ratio) 137 | { 138 | int idx = get_global_id(0); 139 | // we use the first kernel to calculate the ratio 140 | if (idx > 0) { 141 | return; 142 | } 143 | utils_calc_ratio(fitness, ratio, POPULATION_SIZE); 144 | } 145 | 146 | /** 147 | * simple_chromosome_pick_chromosomes picks a chromosome randomly based on the 148 | * ratio of each chromosome and copy all genes to p_other for crossover. The 149 | * reason copy to p_other is that OpenCLGA runs crossover at multi-thread mode. 150 | * The picked chromosomes may also be modified at the same time while crossing 151 | * over. If we don't copy them, we may have duplicated genes in a chromosome. 152 | * Note: this is a kernel function and will be called by python. 153 | * @param *cs (global) all chromosomes 154 | * @param *fitness (global) all fitness of chromosomes 155 | * @param *p_other (global) a spared space for storing another chromosome for 156 | * crossover. 157 | * @param *ratio (global) the ratio of all chromosomes. 158 | * @param *input_rand (global) all random seeds. 159 | */ 160 | __kernel void simple_chromosome_pick_chromosomes(global int* cs, 161 | global float* fitness, 162 | global int* p_other, 163 | global float* ratio, 164 | global uint* input_rand) 165 | { 166 | int idx = get_global_id(0); 167 | // out of bound kernel task for padding 168 | if (idx >= POPULATION_SIZE) { 169 | return; 170 | } 171 | uint ra[1]; 172 | init_rand(input_rand[idx], ra); 173 | global __SimpleChromosome* chromosomes = (global __SimpleChromosome*) cs; 174 | global __SimpleChromosome* other = (global __SimpleChromosome*) p_other; 175 | int i; 176 | // Pick another chromosome as parent_other. 177 | int cross_idx = random_choose_by_ratio(ratio, ra, POPULATION_SIZE); 178 | // copy the chromosome to local memory for cross over 179 | for (i = 0; i < SIMPLE_CHROMOSOME_GENE_SIZE; i++) { 180 | other[idx].genes[i] = chromosomes[cross_idx].genes[i]; 181 | } 182 | input_rand[idx] = ra[0]; 183 | } 184 | 185 | /** 186 | * simple_chromosome_do_crossover does crossover for all chromosomes. 187 | * If a chromosomes passes the prob_crossover, we pick another chromosome for 188 | * crossover, see simple_chromosome_pick_chromosomes for more information. The 189 | * crossover procedure copys a range of genes from parent 2(p_other) to 190 | * parent 1(cs), like: 191 | * CS1 |----------------------------------| 192 | * |start (copy from parent 2) |end 193 | * |^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 194 | * CS2 |----------------------------------| 195 | */ 196 | __kernel void simple_chromosome_do_crossover(global int* cs, 197 | global float* fitness, 198 | global int* p_other, 199 | global uint* input_rand, 200 | float best_fitness, 201 | float prob_crossover) 202 | { 203 | int idx = get_global_id(0); 204 | // out of bound kernel task for padding 205 | if (idx >= POPULATION_SIZE) { 206 | return; 207 | } 208 | uint ra[1]; 209 | init_rand(input_rand[idx], ra); 210 | 211 | // keep the shortest path, we have to return here to prevent async barrier 212 | // if someone is returned. 213 | if (fabs(fitness[idx] - best_fitness) < 0.000001) { 214 | input_rand[idx] = ra[0]; 215 | return; 216 | } else if (rand_prob(ra) >= prob_crossover) { 217 | input_rand[idx] = ra[0]; 218 | return; 219 | } 220 | global __SimpleChromosome* chromosomes = (global __SimpleChromosome*) cs; 221 | global __SimpleChromosome* other = (global __SimpleChromosome*) p_other; 222 | int i; 223 | // keep at least one for . 224 | int start = rand_range(ra, SIMPLE_CHROMOSOME_GENE_SIZE - 1); 225 | int end = start + rand_range(ra, SIMPLE_CHROMOSOME_GENE_SIZE - start); 226 | // copy partial genes from other chromosome 227 | for (i = start; i < end; i++) { 228 | chromosomes[idx].genes[i] = other[idx].genes[i]; 229 | } 230 | 231 | input_rand[idx] = ra[0]; 232 | } 233 | /* ============== end of crossover functions ============== */ 234 | /* ============== elitism ================================= */ 235 | /** 236 | * simple_chromosome_get_the_elites get the elites which meet the best_fitness 237 | * Note: this is a kernel function and will be called by python. 238 | * @param top (global) the number of chromosomes in the indices. 239 | * @param *best_indices (global) the index list of top N best fitness chromosomes. 240 | * @param *cs (global) all chromosomes. 241 | * @param *elites (global) elite chromosomes. 242 | */ 243 | __kernel void simple_chromosome_get_the_elites(global float* best_indices, 244 | global int* cs, 245 | global int* elites, 246 | int top) 247 | { 248 | int idx = get_global_id(0); 249 | // we use the first kernel to get the best chromosome for now. 250 | if (idx > 0) { 251 | return; 252 | } 253 | int i; 254 | int j; 255 | int index; 256 | global __SimpleChromosome* chromosomes = (global __SimpleChromosome*) cs; 257 | global __SimpleChromosome* elites_chromosome = (global __SimpleChromosome*) elites; 258 | for (i = 0; i < top; i++) { 259 | index = best_indices[i]; 260 | for (j = 0; j < SIMPLE_CHROMOSOME_GENE_SIZE; j++) { 261 | elites_chromosome[i].genes[j] = chromosomes[index].genes[j]; 262 | } 263 | } 264 | } 265 | 266 | /** 267 | * simple_chromosome_update_the_elites update sorted elites into chromosomes. 268 | * Note: this is a kernel function and will be called by python. 269 | * @param top (local) the number of chromosomes in the indices. 270 | * @param *worst_indices (global) the index list of bottom N worst fitness chromosomes. 271 | * @param *cs (global) all chromosomes. 272 | * @param *fitnesses (global) fitnesses of all chromosomes 273 | * @param *elites (global) elite chromosomes. 274 | * @param *elite_fitnesses (global) fitnesses of all elite chromosomes. 275 | */ 276 | __kernel void simple_chromosome_update_the_elites(int top, 277 | global int* worst_indices, 278 | global int* cs, 279 | global int* elites, 280 | global float* fitnesses, 281 | global float* elite_fitnesses) 282 | { 283 | int idx = get_global_id(0); 284 | // we use the first kernel to update all elites and their fitnesses. 285 | if (idx > 0) { 286 | return; 287 | } 288 | int i; 289 | int j; 290 | int index; 291 | global __SimpleChromosome* chromosomes = (global __SimpleChromosome*) cs; 292 | global __SimpleChromosome* elites_chromosome = (global __SimpleChromosome*) elites; 293 | for (i = 0 ; i < top; i++) { 294 | index = worst_indices[i]; 295 | for (j = 0; j < SIMPLE_CHROMOSOME_GENE_SIZE; j++) { 296 | chromosomes[index].genes[j] = elites_chromosome[i].genes[j]; 297 | } 298 | fitnesses[index] = elite_fitnesses[index]; 299 | } 300 | } 301 | /* ============== end of elitism functions ============== */ 302 | #endif 303 | -------------------------------------------------------------------------------- /OpenCLGA/kernel/simple_gene.cl: -------------------------------------------------------------------------------- 1 | #ifndef __oclga_simple_gene__ 2 | #define __oclga_simple_gene__ 3 | 4 | #include "ga_utils.cl" 5 | 6 | /** 7 | * simle_gene_mutate mutates a single gene. Because we mapped the elements as 8 | * the index, we random select another index as the value of the gene. 9 | * @param *gene (global) the gene we need to mutate 10 | * @param max the size of elements. 11 | * @param *ra the random number holder. 12 | */ 13 | void simple_gene_mutate(global int* gene, uint max, uint* ra) { 14 | *gene = rand_range_exclude(ra, max, *gene); 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /OpenCLGA/ocl_ga_wsserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import sys 4 | import ssl 5 | import threading 6 | from base64 import b64encode 7 | from socketserver import ThreadingMixIn 8 | from http.server import HTTPServer 9 | from io import StringIO 10 | 11 | from .utilities.generaltaskthread import TaskThread, Task, Logger 12 | from .utilities.httpwebsocketserver import HTTPWebSocketsHandler 13 | 14 | ## A Handler class when the Http request is upgraded to websocket, the following 15 | # methods will be called accordingly. 16 | class HttpWSMessageHandler(HTTPWebSocketsHandler): 17 | 18 | base_path = None 19 | cn_hdlr = None 20 | msg_hdlr = None 21 | dcn_hdlr = None 22 | def on_ws_message(self, message): 23 | if message is None: 24 | message = '' 25 | 26 | self.log_message('websocket received %s', str(message)) 27 | if self.msg_hdlr: 28 | self.msg_hdlr(self.client_address, message) 29 | 30 | def on_ws_connected(self): 31 | self.log_message('%s','websocket connected') 32 | if self.cn_hdlr: 33 | self.cn_hdlr(self.client_address, self) 34 | 35 | def on_ws_closed(self): 36 | if self.dcn_hdlr: 37 | self.dcn_hdlr(self.client_address) 38 | self.log_message('%s','websocket closed') 39 | 40 | ## Handle requests in a separate thread. 41 | class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 42 | pass 43 | 44 | ## A task class which intends to call HTTPServer's serve_forever in separated 45 | # thread. 46 | # @param server The Http Server instance 47 | # @param credentials The credentials to be wrapped if secure connection is required. 48 | class HttpWSTask(Task): 49 | def __init__(self, server, credentials = ''): 50 | Task.__init__(self) 51 | self.logger_level = Logger.MSG_ALL ^ Logger.MSG_VERBOSE 52 | self.server = server 53 | self.server.daemon_threads = True 54 | self.server.auth = b64encode(credentials.encode('ascii')) 55 | if credentials: 56 | self.server.socket = ssl.wrap_socket(self.server.socket, certfile='./server.pem', server_side=True) 57 | self.info('Secure https server is created @ port {}.'.format(self.server.server_port)) 58 | else: 59 | self.info('Http server is created @ port {}.'.format(self.server.server_port)) 60 | 61 | def run(self): 62 | self.verbose('Http WS server is serving forever now !!') 63 | try: 64 | self.server.serve_forever() 65 | except: 66 | pass 67 | 68 | ## Create threaded http server which is able to upgrade HTTP request to websocket 69 | # @param ip IP for server. 70 | # @param port Listen on this port to accept connection. 71 | # @param credentials The credentials file if a secure connection is required. 72 | # @param connect_handler A handler function which is called when the http request 73 | # is upgraded to websocket. 74 | # @param message_handler A handler function which is called when there's any 75 | # message received by the websocket. 76 | # @param disconnect_handler A handler function which is called when the websocket 77 | # disconnects to server. 78 | class OclGAWSServer(object): 79 | def __init__(self, ip, port, credentials = '', connect_handler = None, 80 | message_handler = None, disconnect_handler = None, 81 | base_path = None): 82 | HttpWSMessageHandler.cn_hdlr = connect_handler 83 | HttpWSMessageHandler.msg_hdlr = message_handler 84 | HttpWSMessageHandler.dcn_hdlr = disconnect_handler 85 | HttpWSMessageHandler.base_path = base_path 86 | self.httpwsserver = ThreadedHTTPServer((ip, port), HttpWSMessageHandler) 87 | self.httpwsserver_thread = TaskThread(name='httpwsserver') 88 | self.httpwsserver_thread.daemon = True 89 | self.credentials = credentials 90 | 91 | ## Run the http server's serve_forever function in a separated thread. 92 | def run_server(self): 93 | if self.httpwsserver_thread: 94 | self.httpwsserver_thread.start() 95 | task = HttpWSTask(self.httpwsserver, self.credentials) 96 | self.httpwsserver_thread.addtask(task) 97 | 98 | ## Shut down HttpServer and close the thread for it. 99 | def shutdown(self): 100 | if self.httpwsserver: 101 | self.httpwsserver.socket.close() 102 | self.httpwsserver.shutdown() 103 | self.httpwsserver = None 104 | if self.httpwsserver_thread: 105 | self.httpwsserver_thread.stop() 106 | self.httpwsserver_thread = None 107 | -------------------------------------------------------------------------------- /OpenCLGA/shuffler_chromosome.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import numpy 3 | import pyopencl as cl 4 | 5 | from .simple_gene import SimpleGene 6 | 7 | class ShufflerChromosome: 8 | # ShufflerChromosome - a chromosome contains a list of Genes. 9 | # __genes - an ordered list of Genes 10 | # __name - name of the chromosome 11 | # __improving_func - function name in kernel to gurantee a better mutation result. 12 | # dna - an listed of Gene's dna 13 | # dna_total_length - sum of the lenght of all genes's dna 14 | def __init__(self, genes, name = ''): 15 | assert all(isinstance(gene, SimpleGene) for gene in genes) 16 | assert type(genes) == list 17 | self.__genes = genes 18 | self.__name = name 19 | self.__improving_func = None 20 | 21 | @property 22 | def num_of_genes(self): 23 | return len(self.__genes) 24 | 25 | @property 26 | def name(self): 27 | return self.__name 28 | 29 | @property 30 | def dna_total_length(self): 31 | return self.num_of_genes 32 | 33 | @property 34 | def dna(self): 35 | return [gene.dna for gene in self.__genes] 36 | 37 | @dna.setter 38 | def dna(self, dna): 39 | assert self.num_of_genes == len(dna) 40 | for i, gene in enumerate(self.__genes): 41 | gene.dna = dna[i] 42 | 43 | @property 44 | def genes(self): 45 | return self.__genes 46 | 47 | @property 48 | def gene_elements(self): 49 | return [] if len(self.__genes) == 0 else self.__genes[0].elements 50 | 51 | @property 52 | def gene_elements_in_kernel(self): 53 | return [] if len(self.__genes) == 0 else self.__genes[0].elements_in_kernel 54 | 55 | @property 56 | def kernel_file(self): 57 | return 'shuffler_chromosome.cl' 58 | 59 | @property 60 | def struct_name(self): 61 | return '__ShufflerChromosome'; 62 | 63 | @property 64 | def chromosome_size_define(self): 65 | return 'SHUFFLER_CHROMOSOME_GENE_SIZE' 66 | 67 | def early_terminated(self, best, worst): 68 | return False 69 | 70 | def from_kernel_value(self, data): 71 | assert len(data) == self.num_of_genes 72 | genes = [self.__genes[idx].from_kernel_value(v) for idx, v in enumerate(data)] 73 | return ShufflerChromosome(genes, self.__name) 74 | 75 | def use_improving_only_mutation(self, helper_func_name): 76 | self.__improving_func = helper_func_name 77 | 78 | def kernelize(self): 79 | improving_func = self.__improving_func if self.__improving_func is not None\ 80 | else 'shuffler_chromosome_dummy_improving_func' 81 | candidates = '#define SIMPLE_GENE_ELEMENTS ' + self.__genes[0].elements_in_kernel_str 82 | defines = '#define SHUFFLER_CHROMOSOME_GENE_SIZE ' + str(self.num_of_genes) + '\n' +\ 83 | '#define IMPROVED_FITNESS_FUNC ' + improving_func + '\n' 84 | 85 | improving_func_header = 'int ' + improving_func + '(global int* c,' +\ 86 | 'int idx,' +\ 87 | 'int chromosome_size FITNESS_ARGS);' 88 | return candidates + defines + improving_func_header 89 | 90 | def save(self, data, ctx, queue, population): 91 | total_dna_size = population * self.dna_total_length 92 | # prepare memory 93 | other_chromosomes = numpy.zeros(total_dna_size, dtype=numpy.int32) 94 | cross_map = numpy.zeros(total_dna_size, dtype=numpy.int32) 95 | ratios = numpy.zeros(population, dtype=numpy.float32) 96 | # read data from cl 97 | cl.enqueue_read_buffer(queue, self.__dev_ratios, ratios) 98 | cl.enqueue_read_buffer(queue, self.__dev_other_chromosomes, other_chromosomes) 99 | cl.enqueue_read_buffer(queue, self.__dev_cross_map, cross_map).wait() 100 | # save all of them 101 | data['other_chromosomes'] = other_chromosomes 102 | data['cross_map'] = cross_map 103 | data['ratios'] = ratios 104 | 105 | def restore(self, data, ctx, queue, population): 106 | other_chromosomes = data['other_chromosomes'] 107 | cross_map = data['cross_map'] 108 | ratios = data['ratios'] 109 | # build CL memory from restored memory 110 | mf = cl.mem_flags 111 | self.__dev_ratios = cl.Buffer(ctx, mf.WRITE_ONLY, ratios.nbytes) 112 | self.__dev_other_chromosomes = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 113 | hostbuf=other_chromosomes) 114 | self.__dev_cross_map = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 115 | hostbuf=cross_map) 116 | 117 | def preexecute_kernels(self, ctx, queue, population): 118 | ## initialize global variables for kernel execution 119 | total_dna_size = population * self.dna_total_length 120 | 121 | other_chromosomes = numpy.zeros(total_dna_size, dtype=numpy.int32) 122 | cross_map = numpy.zeros(total_dna_size, dtype=numpy.int32) 123 | ratios = numpy.zeros(population, dtype=numpy.float32) 124 | 125 | mf = cl.mem_flags 126 | 127 | self.__dev_ratios = cl.Buffer(ctx, mf.WRITE_ONLY, ratios.nbytes) 128 | self.__dev_other_chromosomes = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 129 | hostbuf=other_chromosomes) 130 | self.__dev_cross_map = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 131 | hostbuf=cross_map) 132 | 133 | def get_populate_kernel_names(self): 134 | return ['shuffler_chromosome_populate'] 135 | 136 | def get_crossover_kernel_names(self): 137 | return ['shuffler_chromosome_calc_ratio',\ 138 | 'shuffler_chromosome_pick_chromosomes',\ 139 | 'shuffler_chromosome_do_crossover'] 140 | 141 | def get_mutation_kernel_names(self): 142 | return ['shuffler_chromosome_single_gene_mutate'] 143 | 144 | def execute_populate(self, prg, queue, population, dev_chromosomes, dev_rnum): 145 | prg.shuffler_chromosome_populate(queue, 146 | (population,), 147 | (1,), 148 | dev_chromosomes, 149 | dev_rnum).wait() 150 | 151 | def selection_preparation(self, prg, queue, dev_fitnesses): 152 | prg.shuffler_chromosome_calc_ratio(queue, 153 | (1,), 154 | (1,), 155 | dev_fitnesses, 156 | self.__dev_ratios).wait() 157 | 158 | def execute_get_current_elites(self, prg, queue, top, 159 | dev_chromosomes, dev_current_elites, 160 | dev_best_indices): 161 | prg.shuffler_chromosome_get_the_elites(queue, (1,), (1,), 162 | dev_best_indices, 163 | dev_chromosomes, 164 | dev_current_elites, 165 | numpy.int32(top)).wait() 166 | 167 | def execute_update_current_elites(self, prg, queue, top, dev_worst_indices, 168 | dev_chromosomes, dev_updated_elites, 169 | dev_fitnesses, dev_updated_elite_fitness): 170 | prg.shuffler_chromosome_update_the_elites(queue, (1,), (1,), 171 | numpy.int32(top), 172 | dev_worst_indices, 173 | dev_chromosomes, 174 | dev_updated_elites, 175 | dev_fitnesses, 176 | dev_updated_elite_fitness).wait() 177 | 178 | def execute_crossover(self, prg, queue, population, generation_idx, prob_crossover, 179 | dev_chromosomes, dev_fitnesses, dev_rnum, best_fitness): 180 | prg.shuffler_chromosome_pick_chromosomes(queue, 181 | (population,), 182 | (1,), 183 | dev_chromosomes, 184 | dev_fitnesses, 185 | self.__dev_other_chromosomes, 186 | self.__dev_ratios, 187 | dev_rnum).wait() 188 | prg.shuffler_chromosome_do_crossover(queue, 189 | (population,), 190 | (1,), 191 | dev_chromosomes, 192 | dev_fitnesses, 193 | self.__dev_other_chromosomes, 194 | self.__dev_cross_map, 195 | dev_rnum, 196 | numpy.float32(best_fitness), 197 | numpy.float32(prob_crossover)).wait() 198 | 199 | 200 | def execute_mutation(self, prg, queue, population, generation_idx, prob_mutate, 201 | dev_chromosomes, dev_fitnesses, dev_rnum, extra_list): 202 | 203 | args = [dev_chromosomes, 204 | dev_rnum, 205 | numpy.float32(prob_mutate), 206 | numpy.int32(self.__improving_func is not None)] 207 | args = args + extra_list 208 | prg.shuffler_chromosome_single_gene_mutate(queue, 209 | (population,), 210 | (1,), 211 | *args).wait() 212 | -------------------------------------------------------------------------------- /OpenCLGA/simple_chromosome.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import numpy 3 | import pyopencl as cl 4 | from .simple_gene import SimpleGene 5 | 6 | class SimpleChromosome: 7 | # SimpleChromosome - a chromosome contains a list of Genes. 8 | # __genes - a list of Genes 9 | # __name - name of the chromosome 10 | # __improving_func - a function name in kernel to gurantee a better mutation result. 11 | # dna - an listed of Gene's dna 12 | # dna_total_length - sum of the lenght of all genes's dna 13 | def __init__(self, genes, name = ''): 14 | assert all(isinstance(gene, SimpleGene) for gene in genes) 15 | assert type(genes) == list 16 | self.__genes = genes 17 | self.__name = name 18 | self.__improving_func = None 19 | 20 | @property 21 | def num_of_genes(self): 22 | # The number of genes inside this SimpleChromosome. 23 | return len(self.__genes) 24 | 25 | @property 26 | def name(self): 27 | return self.__name 28 | 29 | @property 30 | def dna_total_length(self): 31 | # Sum of the dna lenght of each gene. 32 | return sum([gene.length for gene in self.__genes]) 33 | 34 | @property 35 | def dna(self): 36 | return [gene.dna for gene in self.__genes] 37 | 38 | @dna.setter 39 | def dna(self, dna_sequence): 40 | assert self.num_of_genes == len(dna_sequence) 41 | for i, gene in enumerate(self.__genes): 42 | gene.dna = dna_sequence[i] 43 | 44 | @property 45 | def genes(self): 46 | return self.__genes 47 | 48 | @property 49 | def gene_elements(self): 50 | return [] if len(self.__genes) == 0 else self.__genes[0].elements 51 | 52 | @property 53 | def gene_elements_in_kernel(self): 54 | return [] if len(self.__genes) == 0 else self.__genes[0].elements_in_kernel 55 | 56 | @property 57 | def kernel_file(self): 58 | return 'simple_chromosome.cl' 59 | 60 | @property 61 | def struct_name(self): 62 | return '__SimpleChromosome'; 63 | 64 | @property 65 | def chromosome_size_define(self): 66 | return 'SIMPLE_CHROMOSOME_GENE_SIZE' 67 | 68 | def early_terminated(self, best , worst): 69 | # If the difference between the best and the worst is negligible, 70 | # terminate the program to save time. 71 | return abs(worst - best) < 0.0001 72 | 73 | def from_kernel_value(self, data): 74 | # Construct a SimpleChromosome object on system memory according to 75 | # the calculated 'data' on opencl(device) memory. 76 | assert len(data) == self.num_of_genes 77 | genes = [self.__genes[idx].from_kernel_value(v) for idx, v in enumerate(data)] 78 | return SimpleChromosome(genes, self.__name) 79 | 80 | def use_improving_only_mutation(self, helper_func_name): 81 | # Set a helper function to make sure a better mutation result. 82 | self.__improving_func = helper_func_name 83 | 84 | def kernelize(self): 85 | # - Build a str which contains c99-like codes. This str will be written 86 | # into a final kernel document called 'final.cl' for execution. 87 | # - Gene elements, size, mutation function is pre-defined as MACRO for 88 | # easier usage. 89 | elements_size_list = [str(gene.elements_length) for gene in self.__genes] 90 | candidates = '#define SIMPLE_CHROMOSOME_GENE_ELEMENTS_SIZE {' +\ 91 | ', '.join(elements_size_list) + '}\n' 92 | defines = '#define SIMPLE_CHROMOSOME_GENE_SIZE ' + str(self.num_of_genes) + '\n' +\ 93 | '#define SIMPLE_CHROMOSOME_GENE_MUTATE_FUNC ' +\ 94 | self.__genes[0].mutate_func_name + '\n' 95 | 96 | return candidates + defines 97 | 98 | def save(self, data, ctx, queue, population): 99 | total_dna_size = population * self.dna_total_length 100 | # prepare memory 101 | other_chromosomes = numpy.zeros(total_dna_size, dtype=numpy.int32) 102 | ratios = numpy.zeros(population, dtype=numpy.float32) 103 | # read data from cl 104 | cl.enqueue_read_buffer(queue, self.__dev_ratios, ratios) 105 | cl.enqueue_read_buffer(queue, self.__dev_other_chromosomes, other_chromosomes).wait() 106 | # save all of them 107 | data['other_chromosomes'] = other_chromosomes 108 | data['ratios'] = ratios 109 | 110 | def restore(self, data, ctx, queue, population): 111 | other_chromosomes = data['other_chromosomes'] 112 | ratios = data['ratios'] 113 | # prepare CL memory 114 | mf = cl.mem_flags 115 | self.__dev_ratios = cl.Buffer(ctx, mf.WRITE_ONLY, ratios.nbytes) 116 | self.__dev_other_chromosomes = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 117 | hostbuf=other_chromosomes) 118 | # Copy data from main memory to GPU memory 119 | cl.enqueue_copy(queue, self.__dev_ratios, ratios) 120 | cl.enqueue_copy(queue, self.__dev_other_chromosomes, other_chromosomes) 121 | 122 | def preexecute_kernels(self, ctx, queue, population): 123 | # initialize global variables for kernel execution 124 | total_dna_size = population * self.dna_total_length 125 | 126 | other_chromosomes = numpy.zeros(total_dna_size, dtype=numpy.int32) 127 | ratios = numpy.zeros(population, dtype=numpy.float32) 128 | 129 | mf = cl.mem_flags 130 | 131 | # prepare device memory for usage. 132 | self.__dev_ratios = cl.Buffer(ctx, mf.WRITE_ONLY, ratios.nbytes) 133 | self.__dev_other_chromosomes = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, 134 | hostbuf=other_chromosomes) 135 | 136 | def get_populate_kernel_names(self): 137 | return ['simple_chromosome_populate'] 138 | 139 | def get_crossover_kernel_names(self): 140 | return ['simple_chromosome_calc_ratio',\ 141 | 'simple_chromosome_pick_chromosomes',\ 142 | 'simple_chromosome_do_crossover'] 143 | 144 | def get_mutation_kernel_names(self): 145 | return ['simple_chromosome_mutate_all'] 146 | 147 | def execute_populate(self, prg, queue, population, dev_chromosomes, dev_rnum): 148 | prg.simple_chromosome_populate(queue, 149 | (population,), 150 | (1,), 151 | dev_chromosomes, 152 | dev_rnum).wait() 153 | 154 | def selection_preparation(self, prg, queue, dev_fitnesses): 155 | prg.simple_chromosome_calc_ratio(queue, 156 | (1,), 157 | (1,), 158 | dev_fitnesses, 159 | self.__dev_ratios).wait() 160 | 161 | def execute_get_current_elites(self, prg, queue, top, 162 | dev_chromosomes, dev_current_elites, 163 | dev_best_indices): 164 | prg.simple_chromosome_get_the_elites(queue, (1,), (1,), 165 | dev_best_indices, 166 | dev_chromosomes, 167 | dev_current_elites, 168 | numpy.int32(top)).wait() 169 | 170 | def execute_update_current_elites(self, prg, queue, top, dev_worst_indices, 171 | dev_chromosomes, dev_updated_elites, 172 | dev_fitnesses, dev_updated_elite_fitness): 173 | prg.simple_chromosome_update_the_elites(queue, (1,), (1,), 174 | numpy.int32(top), 175 | dev_worst_indices, 176 | dev_chromosomes, 177 | dev_updated_elites, 178 | dev_fitnesses, 179 | dev_updated_elite_fitness).wait() 180 | 181 | def execute_crossover(self, prg, queue, population, generation_idx, prob_crossover, 182 | dev_chromosomes, dev_fitnesses, dev_rnum, best_fitness): 183 | prg.simple_chromosome_pick_chromosomes(queue, 184 | (population,), 185 | (1,), 186 | dev_chromosomes, 187 | dev_fitnesses, 188 | self.__dev_other_chromosomes, 189 | self.__dev_ratios, 190 | dev_rnum).wait() 191 | prg.simple_chromosome_do_crossover(queue, 192 | (population,), 193 | (1,), 194 | dev_chromosomes, 195 | dev_fitnesses, 196 | self.__dev_other_chromosomes, 197 | dev_rnum, 198 | numpy.float32(best_fitness), 199 | numpy.float32(prob_crossover)).wait() 200 | 201 | 202 | def execute_mutation(self, prg, queue, population, generation_idx, prob_mutate, 203 | dev_chromosomes, dev_fitnesses, dev_rnum, extra_list): 204 | prg.simple_chromosome_mutate_all(queue, 205 | (population,), 206 | (1,), 207 | dev_chromosomes, 208 | dev_rnum, 209 | numpy.float32(prob_mutate)).wait() 210 | -------------------------------------------------------------------------------- /OpenCLGA/simple_gene.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import random 3 | HUMAN_DNA_ELEMENTS = ['A','C','G','T'] 4 | 5 | class SimpleGene: 6 | 7 | @staticmethod 8 | def clone_gene(g): 9 | # Clone a new gene containing the same dna symbol in g. 10 | return SimpleGene(g.dna, g.elements, g.name) 11 | 12 | # SimpleGene - is a Gene with only one DNA element. 13 | # dna - a single element picked from elements. 14 | # elements - a set of element which is the basic component of dna. 15 | def __init__(self, dna, elements=HUMAN_DNA_ELEMENTS, name=''): 16 | assert dna is not None 17 | assert type(elements) == list 18 | self.__elements = elements 19 | self.__name = name 20 | self.dna = dna 21 | 22 | @property 23 | def dna(self): 24 | return self.__dna 25 | 26 | @dna.setter 27 | def dna(self, dna): 28 | assert dna is not None 29 | self.__dna = dna 30 | 31 | @property 32 | def dna_in_kernel(self): 33 | return self._elements.index(self.dna) 34 | 35 | @property 36 | def length(self): 37 | # SimpleGene is designed to be only 1 dna element inside. 38 | return 1 39 | 40 | @property 41 | def name(self): 42 | # The name of this SimpleGene 43 | return self.__name 44 | 45 | @property 46 | def elements(self): 47 | # The list of dna elements. 48 | return self.__elements 49 | 50 | @property 51 | def elements_in_kernel(self): 52 | return list(range(0, len(self.__elements))) 53 | 54 | @property 55 | def kernel_file(self): 56 | # Kernel file which contains related operating functions for SimpleGene, 57 | # i.e. simple_gene_mutate() 58 | return 'simple_gene.cl' 59 | 60 | @property 61 | def elements_length(self): 62 | # The elements size of this SimpleGene. 63 | # Could be considered as the problem space represented by this SimpleGene. 64 | return len(self.__elements) 65 | 66 | @property 67 | def mutate_func_name(self): 68 | # Chromosome can use this function to execute built-in mutate function which choose an 69 | # excluded elments randomly. 70 | return 'simple_gene_mutate' 71 | 72 | @property 73 | def elements_in_kernel_str(self): 74 | # Chromosome can use this function to declare elements array 75 | elements_str = ', '.join([str(v) for v in self.elements_in_kernel]) 76 | return '{' + elements_str + '}\n' 77 | 78 | def from_kernel_value(self, v): 79 | # Construct a SimpleGene object on system memory according to 80 | # the calculated index values 'v' on opencl(device) memory. 81 | assert 0 <= v < len(self.__elements) 82 | return SimpleGene(self.__elements[v], self.__elements, self.__name) 83 | -------------------------------------------------------------------------------- /OpenCLGA/ui/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/android-icon-144x144.png -------------------------------------------------------------------------------- /OpenCLGA/ui/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/android-icon-192x192.png -------------------------------------------------------------------------------- /OpenCLGA/ui/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/android-icon-36x36.png -------------------------------------------------------------------------------- /OpenCLGA/ui/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/android-icon-48x48.png -------------------------------------------------------------------------------- /OpenCLGA/ui/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/android-icon-72x72.png -------------------------------------------------------------------------------- /OpenCLGA/ui/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/android-icon-96x96.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-114x114.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-120x120.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-144x144.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-152x152.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-180x180.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-57x57.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-60x60.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-72x72.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-76x76.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon-precomposed.png -------------------------------------------------------------------------------- /OpenCLGA/ui/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/apple-icon.png -------------------------------------------------------------------------------- /OpenCLGA/ui/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.css": "static/css/main.5da4bf40.css", 3 | "main.css.map": "static/css/main.5da4bf40.css.map", 4 | "main.js": "static/js/main.7371ebc2.js", 5 | "main.js.map": "static/js/main.7371ebc2.js.map" 6 | } -------------------------------------------------------------------------------- /OpenCLGA/ui/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /OpenCLGA/ui/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/favicon-16x16.png -------------------------------------------------------------------------------- /OpenCLGA/ui/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/favicon-32x32.png -------------------------------------------------------------------------------- /OpenCLGA/ui/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/favicon-96x96.png -------------------------------------------------------------------------------- /OpenCLGA/ui/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/favicon.ico -------------------------------------------------------------------------------- /OpenCLGA/ui/index.html: -------------------------------------------------------------------------------- 1 | OpenCLGA UI
-------------------------------------------------------------------------------- /OpenCLGA/ui/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /OpenCLGA/ui/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/ms-icon-144x144.png -------------------------------------------------------------------------------- /OpenCLGA/ui/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/ms-icon-150x150.png -------------------------------------------------------------------------------- /OpenCLGA/ui/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/ms-icon-310x310.png -------------------------------------------------------------------------------- /OpenCLGA/ui/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/OpenCLGA/ui/ms-icon-70x70.png -------------------------------------------------------------------------------- /OpenCLGA/ui/static/css/main.5da4bf40.css: -------------------------------------------------------------------------------- 1 | .app-header{background-color:#222;padding:20px;color:#fff;text-align:center}.app-container{font-size:large}.app.loading:before{z-index:1000;background-color:rgba(0,0,0,.34)}.app.loading.connecting:after,.app.loading:before{content:" ";position:fixed;top:0;left:0;bottom:0;right:0}.app.loading.connecting:after{z-index:1010;background-image:url("https://openclipart.org/download/231263/cherry-blossom-spinner.svg");background-size:33%;background-position:50%;background-repeat:no-repeat}.fixedDataTableCellGroupLayout_cellGroup{-webkit-backface-visibility:hidden;backface-visibility:hidden;left:0;overflow:hidden;position:absolute;top:0;white-space:nowrap}.fixedDataTableCellGroupLayout_cellGroup>.public_fixedDataTableCell_main{display:inline-block;vertical-align:top;white-space:normal}.fixedDataTableCellGroupLayout_cellGroupWrapper{position:absolute;top:0}.fixedDataTableCellLayout_main{border-right-style:solid;border-width:0 1px 0 0;box-sizing:border-box;display:block;overflow:hidden;position:absolute;white-space:normal}.fixedDataTableCellLayout_lastChild{border-width:0 1px 1px 0}.fixedDataTableCellLayout_alignRight{text-align:right}.fixedDataTableCellLayout_alignCenter{text-align:center}.fixedDataTableCellLayout_wrap1{display:table}.fixedDataTableCellLayout_wrap2{display:table-row}.fixedDataTableCellLayout_wrap3{display:table-cell;vertical-align:middle}.fixedDataTableCellLayout_columnResizerContainer{position:absolute;right:0;width:6px;z-index:1}.fixedDataTableCellLayout_columnResizerContainer:hover{cursor:ew-resize}.fixedDataTableCellLayout_columnResizerContainer:hover .fixedDataTableCellLayout_columnResizerKnob{visibility:visible}.fixedDataTableCellLayout_columnResizerKnob{position:absolute;right:0;visibility:hidden;width:4px}.fixedDataTableColumnResizerLineLayout_mouseArea{cursor:ew-resize;position:absolute;right:-5px;width:12px}.fixedDataTableColumnResizerLineLayout_main{border-right-style:solid;border-right-width:1px;box-sizing:border-box;position:absolute;z-index:10}.fixedDataTableColumnResizerLineLayout_hiddenElem,body[dir=rtl] .fixedDataTableColumnResizerLineLayout_main{display:none!important}.fixedDataTableLayout_main{border-style:solid;border-width:1px;box-sizing:border-box;overflow:hidden;position:relative}.fixedDataTableLayout_hasBottomBorder,.fixedDataTableLayout_header{border-bottom-style:solid;border-bottom-width:1px}.fixedDataTableLayout_footer .public_fixedDataTableCell_main{border-top-style:solid;border-top-width:1px}.fixedDataTableLayout_bottomShadow,.fixedDataTableLayout_topShadow{height:4px;left:0;position:absolute;right:0;z-index:1}.fixedDataTableLayout_bottomShadow{margin-top:-4px}.fixedDataTableLayout_rowsContainer{overflow:hidden;position:relative}.fixedDataTableLayout_horizontalScrollbar{bottom:0;position:absolute}.fixedDataTableRowLayout_main{box-sizing:border-box;overflow:hidden;position:absolute;top:0}.fixedDataTableRowLayout_body{left:0;position:absolute;top:0}.fixedDataTableRowLayout_fixedColumnsDivider{-webkit-backface-visibility:hidden;backface-visibility:hidden;border-left-style:solid;border-left-width:1px;left:0;position:absolute;top:0;width:0}.fixedDataTableRowLayout_columnsShadow{width:4px}.fixedDataTableRowLayout_rowWrapper{position:absolute;top:0}.ScrollbarLayout_main{box-sizing:border-box;outline:none;overflow:hidden;position:absolute;transition-duration:.25s;transition-timing-function:ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ScrollbarLayout_mainVertical{bottom:0;right:0;top:0;transition-property:background-color width;width:15px}.ScrollbarLayout_mainVertical.public_Scrollbar_mainActive,.ScrollbarLayout_mainVertical:hover{width:17px}.ScrollbarLayout_mainHorizontal{bottom:0;height:15px;left:0;transition-property:background-color height}.ScrollbarLayout_mainHorizontal.public_Scrollbar_mainActive,.ScrollbarLayout_mainHorizontal:hover{height:17px}.ScrollbarLayout_face{left:0;overflow:hidden;position:absolute;z-index:1}.ScrollbarLayout_face:after{border-radius:6px;content:"";display:block;position:absolute;transition:background-color .25s ease}.ScrollbarLayout_faceHorizontal{bottom:0;left:0;top:0}.ScrollbarLayout_faceHorizontal:after{bottom:4px;left:0;top:4px;width:100%}.ScrollbarLayout_faceVertical{left:0;right:0;top:0}.ScrollbarLayout_faceVertical:after{height:100%;left:4px;right:4px;top:0}.public_fixedDataTable_hasBottomBorder,.public_fixedDataTable_header,.public_fixedDataTable_main{border-color:#d3d3d3}.public_fixedDataTable_header .public_fixedDataTableCell_main{font-weight:700}.public_fixedDataTable_header,.public_fixedDataTable_header .public_fixedDataTableCell_main{background-color:#f6f7f8;background-image:linear-gradient(#fff,#efefef)}.public_fixedDataTable_footer .public_fixedDataTableCell_main{background-color:#f6f7f8;border-color:#d3d3d3}.public_fixedDataTable_topShadow{background:0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAECAYAAABP2FU6AAAAF0lEQVR4AWPUkNeSBhHCjJoK2twgFisAFagCCp3pJlAAAAAASUVORK5CYII=) repeat-x}.public_fixedDataTable_bottomShadow{background:0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAECAYAAABP2FU6AAAAHElEQVQI12MwNjZmZdAT1+Nm0JDWEGZQk1GTBgAWkwIeAEp52AAAAABJRU5ErkJggg==) repeat-x}.public_fixedDataTable_horizontalScrollbar .public_Scrollbar_mainHorizontal{background-color:#fff}.public_fixedDataTableCell_main{background-color:#fff;border-color:#d3d3d3}.public_fixedDataTableCell_highlighted{background-color:#f4f4f4}.public_fixedDataTableCell_cellContent{padding:8px}.public_fixedDataTableCell_columnResizerKnob{background-color:#0284ff}.public_fixedDataTableColumnResizerLine_main{border-color:#0284ff}.public_fixedDataTableRow_main{background-color:#fff}.public_fixedDataTableRow_highlighted,.public_fixedDataTableRow_highlighted .public_fixedDataTableCell_main{background-color:#f6f7f8}.public_fixedDataTableRow_fixedColumnsDivider{border-color:#d3d3d3}.public_fixedDataTableRow_columnsShadow{background:0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAFklEQVQIHWPSkNeSBmJhTQVtbiDNCgASagIIuJX8OgAAAABJRU5ErkJggg==) repeat-y}.public_Scrollbar_main.public_Scrollbar_mainActive,.public_Scrollbar_main:hover{background-color:hsla(0,0%,100%,.8)}.public_Scrollbar_mainOpaque,.public_Scrollbar_mainOpaque.public_Scrollbar_mainActive,.public_Scrollbar_mainOpaque:hover{background-color:#fff}.public_Scrollbar_face:after{background-color:#c2c2c2}.public_Scrollbar_faceActive:after,.public_Scrollbar_main:hover .public_Scrollbar_face:after,.public_Scrollbar_mainActive .public_Scrollbar_face:after{background-color:#7d7d7d}body,html{margin:0;padding:0;font-family:sans-serif}.panel{width:calc(100% - 60px);margin-top:10px;margin-left:30px;margin-right:30px}.row{text-align:left}.row .control-label{margin-top:5px}.row .checkbox,.row .radio,.row .react-numeric-input{margin-top:5px;margin-bottom:10px;margin-right:10px}.row .react-numeric-input{margin-right:10px}.row .checkbox label,.row .radio label{min-width:90px;font-weight:700}.labeled-info-row{margin-left:20px;margin-right:20px;padding:5px 10px}.labeled-info-row .row{margin-left:0;margin-right:0}.labeled-info-row .info-row{margin-left:10px;margin-right:10px;font-size:x-large;text-transform:capitalize}.react-bs-table{background-color:#fff}.crossover-row .crossover-number,.elitism-mode-row .elitism-mode-number,.generations-row .generations-count-number,.generations-row .generations-time-number,.mutation-row .mutation-number,.population-row .population-number,.repopulating-row .repopulating-number{text-align:right}.elitism-mode-row .react-numeric-input,.repopulating-row .dropdown,.repopulating-row .react-numeric-input{margin-left:20px;margin-right:20px}.elitism-mode-row .react-numeric-input,.elitism-mode-row div,.repopulating-row .react-numeric-input,.repopulating-row div{display:inline-block;margin-top:0;margin-bottom:0}.elitism-mode-row{margin-top:20px}@-moz-document url-prefix(){.elitism-mode-row .react-numeric-input,.repopulating-row .react-numeric-input{top:5px}}.status-label-row.labeled-info-row{float:left;width:200px;border:2px solid green;border-radius:4px;box-shadow:2px 2px 4px #050}.status-label-row.prepared .info-row,.status-label-row.preparing .info-row,.status-label-row.restoring .info-row,.status-label-row.waiting .info-row{color:blue}.status-label-row.running .info-row{color:green}.status-label-row.paused .info-row,.status-label-row.pausing .info-row,.status-label-row.saving .info-row{color:#556b2f}.status-label-row.stopped .info-row,.status-label-row.stopping .info-row{color:#8b0000}.control-buttons{float:right;text-align:right;height:60px;margin:5px 10px;width:calc(100% - 270px)}.control-buttons .btn{height:60px;margin-left:10px;font-size:large}.control-buttons .btn:first-child{margin-left:0}@media screen and (max-width:768px){.control-buttons,.status-label-row{float:none;width:auto}.control-buttons{text-align:center;margin-top:20px}}.grid-text-cell{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding:0 8px}.widgets-panel-row{margin:10px 30px 0} 2 | /*# sourceMappingURL=main.5da4bf40.css.map*/ -------------------------------------------------------------------------------- /OpenCLGA/ui/static/css/main.5da4bf40.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"static/css/main.5da4bf40.css","sourceRoot":""} -------------------------------------------------------------------------------- /OpenCLGA/utilities/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ["generaltaskthread", "httpwebsocketserver", "socketserverclient"] 2 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/generaltaskthread/__init__.py: -------------------------------------------------------------------------------- 1 | from .generaltaskthread import TaskThread, Task 2 | from .logger import Logger 3 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/generaltaskthread/generaltaskthread.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Event, Lock, current_thread 2 | from .logger import Logger 3 | 4 | class Task(Logger): 5 | __id = 0 6 | def __init__(self, *args, **argd): 7 | Logger.__init__(self) 8 | Task.__id += 1 9 | self.__taskid = Task.__id 10 | 11 | def __getattr__(self, name): 12 | if name == 'taskid': 13 | return self.__taskid 14 | return None 15 | 16 | def run(self): 17 | raise NotImplementedError 18 | 19 | def get_current_thread_name(self): 20 | t = current_thread() 21 | return t.name 22 | 23 | class TaskThread(Thread): 24 | def __init__(self, name = 'Unknown'): 25 | Thread.__init__(self, name = name) 26 | self.__qlock = Lock() 27 | self.tasks = [] 28 | self.wati_for_task = Event() 29 | self.wati_for_stop = Event() 30 | # Dump msg 31 | self.debug = True 32 | 33 | def debug_log(self, msg, prefixname = False, postfixname = False): 34 | if self.debug: 35 | self.log(msg, prefixname, postfixname) 36 | 37 | def log(self, msg, prefixname = False, postfixname = False): 38 | pre = '[%s]'%(self.name) if prefixname else '' 39 | post = '[%s]'%(self.name) if postfixname else '' 40 | print(pre+msg+post) 41 | 42 | def start(self): 43 | Thread.start(self) 44 | 45 | def run(self): 46 | self.log(' TaskThread : running ...', prefixname = True) 47 | while True: 48 | # If there's not pending task, wait to avoid busy-looping. 49 | if len(self.tasks) == 0: 50 | self.wati_for_task.wait() 51 | 52 | # If stop() is called, remaining tasks won't be exectued ! 53 | if self.wati_for_stop.isSet(): 54 | break 55 | 56 | # Remove a pending task from the queue. 57 | self.__qlock.acquire() 58 | task = self.tasks.pop(0) 59 | self.__qlock.release() 60 | 61 | if task: 62 | self.debug_log(' TaskThread : start executing ... task (%d)'%(task.taskid), prefixname = True) 63 | task.run() 64 | self.log(' TaskThread : ending.', prefixname = True) 65 | 66 | def stop(self): 67 | self.log('stop ...', postfixname = True) 68 | if self.wati_for_stop: 69 | self.wati_for_stop.set() 70 | if self.wati_for_task: 71 | self.wati_for_task.set() 72 | self.log('going to join ...', postfixname = True) 73 | self.join() 74 | self.tasks.clear() 75 | self.wati_for_task = None 76 | self.wati_for_stop = None 77 | self.__qlock = None 78 | 79 | def addtask(self, task): 80 | self.debug_log('adding task(%d) to ...'%(task.taskid), postfixname = True) 81 | # TODO : Add priority re-order for tasks. 82 | self.__qlock.acquire() 83 | self.tasks.append(task) 84 | self.__qlock.release() 85 | self.wati_for_task.set() 86 | self.wati_for_task.clear() 87 | return task.taskid 88 | 89 | def canceltask(self, taskid): 90 | self.debug_log('canceling task(%d) in ...'%(taskid), postfixname = True) 91 | self.__qlock.acquire() 92 | task = list(filter(lambda x: x.taskid == taskid, self.tasks)) 93 | if len(task) == 1: 94 | self.tasks.remove(task[0]) 95 | self.debug_log('task(%d) canceled in ...'%(taskid), postfixname = True) 96 | self.__qlock.release() 97 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/generaltaskthread/logger.py: -------------------------------------------------------------------------------- 1 | def logi(msg): 2 | print('[INFO] ' + msg + '\033[m') 3 | def logv(msg): 4 | print('\033[1;34m[VERBOSE] ' + msg + '\033[m') 5 | def logw(msg): 6 | print('\033[1;36m[WARNING] ' + msg + '\033[m') 7 | def loge(msg): 8 | print('\033[1;31m[ERROR] ' + msg + '\033[m') 9 | 10 | class Logger(object): 11 | MSG_INFO = 0x01 12 | MSG_WARNING = 0x02 13 | MSG_ERROR = 0x04 14 | MSG_VERBOSE = 0x08 15 | MSG_ALL = MSG_INFO | MSG_WARNING | MSG_ERROR | MSG_VERBOSE 16 | def __init__(self): 17 | self.logger_level = Logger.MSG_ALL 18 | def info(self, msg): 19 | if self.logger_level & Logger.MSG_INFO: 20 | logi(msg) 21 | def warning(self, msg): 22 | if self.logger_level & Logger.MSG_WARNING: 23 | logw(msg) 24 | def error(self, msg): 25 | if self.logger_level & Logger.MSG_ERROR: 26 | loge(msg) 27 | def verbose(self, msg): 28 | if self.logger_level & Logger.MSG_VERBOSE: 29 | logv(msg) 30 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/httpwebsocketserver/ExampleWSServer.py: -------------------------------------------------------------------------------- 1 | #main program and imports for standalone purpose 2 | import sys 3 | import threading 4 | import ssl 5 | from base64 import b64encode 6 | 7 | VER = sys.version_info[0] 8 | if VER >= 3: 9 | from socketserver import ThreadingMixIn 10 | from http.server import HTTPServer 11 | from io import StringIO 12 | else: 13 | from SocketServer import ThreadingMixIn 14 | from BaseHTTPServer import HTTPServer 15 | from StringIO import StringIO 16 | 17 | from HTTPWebSocketsHandler import HTTPWebSocketsHandler 18 | 19 | if len(sys.argv) > 1: 20 | port = int(sys.argv[1]) 21 | else: 22 | port = 8000 23 | if len(sys.argv) > 2: 24 | secure = str(sys.argv[2]).lower()=='secure' 25 | else: 26 | secure = False 27 | if len(sys.argv) > 3: 28 | credentials = str(sys.argv[3]) 29 | else: 30 | credentials = '' 31 | 32 | class WSSimpleEcho(HTTPWebSocketsHandler): 33 | def on_ws_message(self, message): 34 | if message is None: 35 | message = '' 36 | # echo message back to client 37 | self.send_message(message) 38 | self.log_message('websocket received '%s'',str(message)) 39 | 40 | def on_ws_connected(self): 41 | self.log_message('%s','websocket connected') 42 | 43 | def on_ws_closed(self): 44 | self.log_message('%s','websocket closed') 45 | 46 | class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 47 | '''Handle requests in a separate thread.''' 48 | 49 | def _ws_main(): 50 | try: 51 | #Replace WSSimpleEcho with your own subclass of HTTPWebSocketHandler 52 | server = ThreadedHTTPServer(('', port), WSSimpleEcho) 53 | server.daemon_threads = True 54 | server.auth = b64encode(credentials.encode('ascii')) 55 | if secure: 56 | server.socket = ssl.wrap_socket (server.socket, certfile='./server.pem', server_side=True) 57 | print('started secure https server at port %d' % (port,)) 58 | else: 59 | print('started http server at port %d' % (port,)) 60 | server.serve_forever() 61 | except KeyboardInterrupt: 62 | print('^C received, shutting down server') 63 | server.socket.close() 64 | 65 | if __name__ == '__main__': 66 | _ws_main() 67 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/httpwebsocketserver/HTTPWebSocketsHandler.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The MIT License (MIT) 3 | 4 | Copyright (C) 2014, 2015 Seven Watt 5 | 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | ''' 13 | 14 | import sys 15 | import codecs 16 | import struct 17 | import errno, socket 18 | import threading 19 | import traceback 20 | import posixpath 21 | import os 22 | from urllib.parse import unquote 23 | from base64 import b64encode 24 | from hashlib import sha1 25 | 26 | from http.server import SimpleHTTPRequestHandler 27 | from io import StringIO 28 | from email.message import Message 29 | 30 | class WebSocketError(Exception): 31 | pass 32 | 33 | class RootedHTTPRequestHandler(SimpleHTTPRequestHandler): 34 | # PleaseThe implementation of RootedHTTPRequestHandler refers to: 35 | # http://louistiao.me/posts/python-simplehttpserver-recipe-serve-specific-directory/ 36 | def translate_path(self, path): 37 | path = posixpath.normpath(unquote(path)) 38 | words = path.split('/') 39 | words = filter(None, words) 40 | path = self.base_path 41 | for word in words: 42 | drive, word = os.path.splitdrive(word) 43 | head, word = os.path.split(word) 44 | if word in (os.curdir, os.pardir): 45 | continue 46 | path = os.path.join(path, word) 47 | print('trying to access {}'.format(path)) 48 | return path 49 | 50 | class HTTPWebSocketsHandler(RootedHTTPRequestHandler): 51 | _ws_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' 52 | _opcode_continu = 0x0 53 | _opcode_text = 0x1 54 | _opcode_binary = 0x2 55 | _opcode_close = 0x8 56 | _opcode_ping = 0x9 57 | _opcode_pong = 0xa 58 | 59 | mutex = threading.Lock() 60 | 61 | def on_ws_message(self, message): 62 | '''Override this handler to process incoming websocket messages.''' 63 | pass 64 | 65 | def on_ws_connected(self): 66 | '''Override this handler.''' 67 | pass 68 | 69 | def on_ws_closed(self): 70 | '''Override this handler.''' 71 | pass 72 | 73 | def send_message(self, message): 74 | self._send_message(self._opcode_text, message) 75 | 76 | def setup(self): 77 | SimpleHTTPRequestHandler.setup(self) 78 | self.connected = False 79 | 80 | # def finish(self): 81 | # #needed when wfile is used, or when self.close_connection is not used 82 | # # 83 | # #catch errors in SimpleHTTPRequestHandler.finish() after socket disappeared 84 | # #due to loss of network connection 85 | # try: 86 | # SimpleHTTPRequestHandler.finish(self) 87 | # except (socket.error, TypeError) as err: 88 | # self.log_message('finish(): Exception: in SimpleHTTPRequestHandler.finish(): %s' % str(err.args)) 89 | 90 | # def handle(self): 91 | # #needed when wfile is used, or when self.close_connection is not used 92 | # # 93 | # #catch errors in SimpleHTTPRequestHandler.handle() after socket disappeared 94 | # #due to loss of network connection 95 | # try: 96 | # SimpleHTTPRequestHandler.handle(self) 97 | # except (socket.error, TypeError) as err: 98 | # self.log_message('handle(): Exception: in SimpleHTTPRequestHandler.handle(): %s' % str(err.args)) 99 | 100 | def checkAuthentication(self): 101 | auth = self.headers.get('Authorization') 102 | if auth != 'Basic %s' % self.server.auth: 103 | self.send_response(401) 104 | self.send_header('WWW-Authenticate', 'Basic realm="Plugwise"') 105 | self.end_headers(); 106 | return False 107 | return True 108 | 109 | def do_GET(self): 110 | if self.server.auth and not self.checkAuthentication(): 111 | return 112 | if self.headers.get('Upgrade', None) == 'websocket': 113 | self._handshake() 114 | #This handler is in websocket mode now. 115 | #do_GET only returns after client close or socket error. 116 | self._read_messages() 117 | else: 118 | SimpleHTTPRequestHandler.do_GET(self) 119 | 120 | def _read_messages(self): 121 | while self.connected == True: 122 | try: 123 | self._read_next_message() 124 | except (socket.error, WebSocketError) as e: 125 | #websocket content error, time-out or disconnect. 126 | self.log_message('RCV: Close connection: Socket Error %s' % str(e.args)) 127 | self._ws_close() 128 | except Exception as err: 129 | #unexpected error in websocket connection. 130 | traceback.print_exc() 131 | self.log_error('RCV: Exception: in _read_messages: %s' % str(err.args)) 132 | self._ws_close() 133 | 134 | def _read_bytes(self, length): 135 | raw_data = self.rfile.read(length) 136 | return raw_data 137 | 138 | def _read_next_message(self): 139 | #self.rfile.read(n) is blocking. 140 | #it returns however immediately when the socket is closed. 141 | try: 142 | byte = self._read_bytes(1) 143 | self.opcode = ord(byte) & 0x0F 144 | length = ord(self._read_bytes(1)) & 0x7F 145 | if length == 126: 146 | length = struct.unpack('>H', self._read_bytes(2))[0] 147 | elif length == 127: 148 | length = struct.unpack('>Q', self._read_bytes(8))[0] 149 | masks = self._read_bytes(4) 150 | decoded = bytearray() 151 | datastream = self._read_bytes(length) 152 | for char in datastream: 153 | decoded.append(char ^ masks[len(decoded) % 4]) 154 | 155 | decoded = bytes(decoded) 156 | self._on_message(decoded) 157 | except (struct.error, TypeError) as e: 158 | traceback.print_exc() 159 | #catch exceptions from ord() and struct.unpack() 160 | if self.connected: 161 | raise WebSocketError('Websocket read aborted while listening') 162 | else: 163 | #the socket was closed while waiting for input 164 | self.log_error('RCV: _read_next_message aborted after closed connection') 165 | pass 166 | 167 | def _send_impl(self, msg): 168 | data = bytearray() 169 | if type(msg) == int: 170 | data = bytes([msg]) 171 | elif type(msg) == bytes: 172 | data = msg 173 | elif type(msg) == str: 174 | data = msg.encode() 175 | self.request.send(data) 176 | 177 | def _send_message(self, opcode, message): 178 | try: 179 | #use of self.wfile.write gives socket exception after socket is closed. Avoid. 180 | self._send_impl(0x80 + opcode) 181 | length = len(message) 182 | if length <= 125: 183 | self._send_impl(length) 184 | elif length >= 126 and length <= 65535: 185 | self._send_impl(126) 186 | self._send_impl(struct.pack('>H', length)) 187 | else: 188 | self._send_impl(127) 189 | self._send_impl(struct.pack('>Q', length)) 190 | if length > 0: 191 | self._send_impl(message) 192 | except socket.error as e: 193 | #websocket content error, time-out or disconnect. 194 | traceback.print_exc() 195 | self.log_message('SND: Close connection: Socket Error %s' % str(e.args)) 196 | self._ws_close() 197 | except Exception as err: 198 | #unexpected error in websocket connection. 199 | traceback.print_exc() 200 | self.log_error('SND: Exception: in _send_message: %s' % str(err.args)) 201 | self._ws_close() 202 | 203 | def _handshake(self): 204 | headers=self.headers 205 | if headers.get('Upgrade', None) != 'websocket': 206 | return 207 | key = headers['Sec-WebSocket-Key'] 208 | coded_ID = (key + self._ws_GUID).encode('ascii') 209 | hexed = sha1(coded_ID).hexdigest() 210 | hex_decoded = codecs.decode(hexed, 'hex_codec') 211 | digest = b64encode(hex_decoded).decode() 212 | self.send_response(101, 'Switching Protocols') 213 | self.send_header('Upgrade', 'websocket') 214 | self.send_header('Connection', 'Upgrade') 215 | self.send_header('Sec-WebSocket-Accept', digest) 216 | self.end_headers() 217 | self.connected = True 218 | #self.close_connection = 0 219 | self.on_ws_connected() 220 | 221 | def _ws_close(self): 222 | #avoid closing a single socket two time for send and receive. 223 | self.mutex.acquire() 224 | try: 225 | if self.connected: 226 | self.connected = False 227 | #Terminate BaseHTTPRequestHandler.handle() loop: 228 | self.close_connection = 1 229 | #send close and ignore exceptions. An error may already have occurred. 230 | try: 231 | self._send_close() 232 | except: 233 | pass 234 | self.on_ws_closed() 235 | else: 236 | self.log_message('_ws_close websocket in closed state. Ignore.') 237 | pass 238 | finally: 239 | self.mutex.release() 240 | 241 | def _on_message(self, message): 242 | #self.log_message('_on_message: opcode: %02X msg: %s' % (self.opcode, message)) 243 | 244 | # close 245 | if self.opcode == self._opcode_close: 246 | self.connected = False 247 | #Terminate BaseHTTPRequestHandler.handle() loop: 248 | self.close_connection = 1 249 | try: 250 | self._send_close() 251 | except: 252 | pass 253 | self.on_ws_closed() 254 | # ping 255 | elif self.opcode == self._opcode_ping: 256 | _send_message(self._opcode_pong, message) 257 | # pong 258 | elif self.opcode == self._opcode_pong: 259 | pass 260 | # data 261 | elif (self.opcode == self._opcode_continu or 262 | self.opcode == self._opcode_text or 263 | self.opcode == self._opcode_binary): 264 | self.on_ws_message(message) 265 | 266 | def _send_close(self): 267 | #Dedicated _send_close allows for catch all exception handling 268 | msg = bytearray() 269 | msg.append(0x80 + self._opcode_close) 270 | msg.append(0x00) 271 | self._send_impl(msg) 272 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/httpwebsocketserver/README.md: -------------------------------------------------------------------------------- 1 | # httpwebsockethandler 2 | Python combines HTTP and WebSocketServer with SSL support 3 | 4 | ##command line options 5 | 6 | ```shell 7 | #assume ExampleWSServer.py and HTTPWebSocketsHandler.py are in the current directory 8 | nohup python ExampleWSServer.py 8000 secure username:mysecret >>ws.log& 9 | ``` 10 | 11 | This uses SSL/https. Change username:mysecret in a username:password chosen by yourself. The websserver uses port 8000 by default, and can be changed by an optional parameter: 12 | 13 | `nohup python ExampleWSServer.py 8001 secure username:mysecret >>ws.log&` 14 | 15 | Providing a user:password is optional, as well as using SSL/https. When the website is only accessible within your LAN, then the server can be used as plain http, by omitting the secure parameter. The following parameter formats are valid: 16 | 17 | ```shell 18 | nohup python ExampleWSServer.py 8001 secure user:password >>ws.log& 19 | 20 | #no username and password requested 21 | nohup python ExampleWSServer.py 8000 secure >>ws.log& 22 | 23 | #plain http, with optional port 24 | nohup python ExampleWSServer.py 8002 >>ws.log& 25 | 26 | #plain http, default port 8000 27 | nohup python ExampleWSServer.py >>ws.log& 28 | ``` 29 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/httpwebsocketserver/__init__.py: -------------------------------------------------------------------------------- 1 | from .HTTPWebSocketsHandler import HTTPWebSocketsHandler 2 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/httpwebsocketserver/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebSocket Test 6 | 7 | 92 | 93 |
94 | 95 |
96 |

97 | 98 |

99 |

100 | 101 |

102 |

103 | 104 |

105 |

106 | 107 | 108 | 109 | 110 |

111 | Link to test non-ws message 112 | 113 |
114 | 115 | 116 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/httpwebsocketserver/websocket.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebSocket Test 6 | 7 | 86 | 87 |
88 | 89 |
90 |

91 | 92 |

93 |

94 | 95 |

96 |

97 | 98 |

99 |

100 | 101 | 102 | 103 | 104 |

105 | 106 | 107 |
108 | 109 | 110 | -------------------------------------------------------------------------------- /OpenCLGA/utilities/socketserverclient/__init__.py: -------------------------------------------------------------------------------- 1 | from .server_client import Client, Server, OP_MSG_BEGIN, OP_MSG_END 2 | -------------------------------------------------------------------------------- /OpenCLGA/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import random 3 | from math import pi, sqrt, asin, cos, sin, pow 4 | 5 | def get_local_IP(): 6 | import socket 7 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 8 | s.connect(('8.8.8.8', 1)) 9 | ip = s.getsockname()[0] 10 | s.close() 11 | return ip 12 | 13 | def get_testing_params(): 14 | return 20, 200, 5000 15 | 16 | def init_testing_rand_seed(): 17 | random.seed(119) 18 | 19 | def calc_linear_distance(x1, y1, x2, y2): 20 | return sqrt((x2 - x1)**2 + (y2 - y1)**2) 21 | 22 | def calc_spherical_distance(x1, y1, x2, y2): 23 | def rad(deg): 24 | return deg * pi / 180.0 25 | rad_x1 = rad(x1) 26 | rad_x2 = rad(x2) 27 | a = rad_x1 - rad_x2 28 | b = rad(y1) - rad(y2) 29 | s = 2 * asin(sqrt(pow(sin(a/2),2)+cos(rad_x1)*cos(rad_x2)*pow(sin(b/2),2))) 30 | s = s * 6378.137 31 | s = round( s * 10000 ) / 10000 32 | return s 33 | 34 | def plot_tsp_result(city_info, city_ids): 35 | import matplotlib.pyplot as plt 36 | x = [] 37 | y = [] 38 | for c_id in city_ids: 39 | x.append(city_info[c_id][0]) 40 | y.append(city_info[c_id][1]) 41 | x.append(x[0]) 42 | y.append(y[0]) 43 | 44 | plt.plot(x, y, 'ro-') 45 | plt.ylabel('y') 46 | plt.xlabel('x') 47 | plt.grid(True) 48 | plt.show() 49 | 50 | def plot_grouping_result(group_id_set, group_ids, city_info): 51 | assert len(group_id_set) != 0 52 | import matplotlib.pyplot as plt 53 | markers = ['p', '*', '+', 'x', 'd', 'o', 'v', 's', 'h'] 54 | colors = [(random.random(), random.random(), random.random()) for x in range(len(group_id_set))] 55 | while len(group_id_set) > 0: 56 | group_id = group_id_set.pop() 57 | clr = colors.pop() 58 | makr = markers[random.randint(0, len(markers)-1)] 59 | x = [] 60 | y = [] 61 | for idx, gid in enumerate(group_ids): 62 | if gid == group_id: 63 | x.append(city_info[idx][0]) 64 | y.append(city_info[idx][1]) 65 | plt.plot(x, y, color=clr, marker=makr) 66 | 67 | plt.ylabel('y') 68 | plt.xlabel('x') 69 | plt.grid(True) 70 | plt.show() 71 | 72 | def plot_ga_result(statistics): 73 | import matplotlib.pyplot as plt 74 | 75 | gen = [] 76 | bests = [] 77 | worsts = [] 78 | avgs = [] 79 | 80 | avg_time_per_gen = 0 81 | for key, value in statistics.items(): 82 | if key != 'avg_time_per_gen': 83 | gen.append(key) 84 | bests.append(value['best']) 85 | worsts.append(value['worst']) 86 | avgs.append(value['avg']) 87 | elif key == 'avg_time_per_gen': 88 | avg_time_per_gen = value 89 | 90 | arrow_idx = int(len(gen) * 0.7) 91 | arrow_x = gen[arrow_idx] 92 | arrow_y = bests[arrow_idx] 93 | plt.plot(gen, bests, 'g-') 94 | plt.annotate('best', xy=(arrow_x, arrow_y,)) 95 | 96 | arrow_y = worsts[arrow_idx] 97 | plt.plot(gen, worsts, 'r-') 98 | plt.annotate('worst', xy=(arrow_x, arrow_y)) 99 | 100 | arrow_y = avgs[arrow_idx] 101 | plt.plot(gen, avgs, 'b-') 102 | plt.annotate('avg', xy=(arrow_x, arrow_y)) 103 | 104 | plt.ylabel('Fitness') 105 | plt.xlabel('Generation') 106 | 107 | xmin, xmax, ymin, ymax = plt.axis() 108 | textX = abs(xmax - xmin) * 0.1 109 | textY = abs(ymax) * 0.95 110 | plt.text(textX, textY, 'avg time per gen: %f (sec.)'%(avg_time_per_gen)) 111 | plt.grid(True) 112 | plt.show() 113 | 114 | def calculate_estimated_kernel_usage(prog, ctx, kernel_name): 115 | try: 116 | import pyopencl as cl 117 | from pyopencl import context_info as ci 118 | from pyopencl import kernel_work_group_info as kwgi 119 | devices = ctx.get_info(ci.DEVICES) 120 | assert len(devices) == 1, 'Should only one device is used !' 121 | device = devices[0] 122 | # for name in kernel_names: 123 | kernel = cl.Kernel(prog, kernel_name) 124 | # gws = kernel.get_work_group_info(kwgi.GLOBAL_WORK_SIZE, device) 125 | lm = kernel.get_work_group_info(kwgi.LOCAL_MEM_SIZE, device) 126 | pm = kernel.get_work_group_info(kwgi.PRIVATE_MEM_SIZE, device) 127 | cwgs = kernel.get_work_group_info(kwgi.COMPILE_WORK_GROUP_SIZE, device) 128 | pwgsm = kernel.get_work_group_info(kwgi.PREFERRED_WORK_GROUP_SIZE_MULTIPLE, device) 129 | 130 | print('For kernel "{}" running on device {}:'.format(kernel.function_name, device.name)) 131 | # print('\t Max work size: {}'.format(gws)) 132 | print('\t Max work-group size: {}'.format(cwgs)) 133 | print('\t Recommended work-group multiple: {}'.format(pwgsm)) 134 | print('\t Local mem used: {} of {}'.format(lm, device.local_mem_size)) 135 | print('\t Private mem used: {}'.format(pm)) 136 | return cwgs, pwgsm, lm, pm 137 | except: 138 | import traceback 139 | traceback.print_exc() 140 | return None, None, None, None 141 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | 2 | Join us on `slack `_ (歡迎上 `slack `_ 交流 !!) 3 | =============== 4 | .. figure:: https://img.shields.io/badge/slack-n.n-pink.svg 5 | :target: https://pyopenclopt.slack.com/ 6 | 7 | 8 | OpenCLGA 9 | =============== 10 | OpenCLGA is a python library for running genetic algorithm among Open CL devices, like GPU, CPU, DSP, etc. In the best case, you can run your GA parallelly at all of your Open CL devices which give you the maximum computing power of your machine. In the worse case, which you only have CPU, you still can run the code at parallel CPU mode. 11 | 12 | We had implemented OpenCLGA at ocl_ga.py which encapsulate GA follow (population, crossover, mutation, fitness calculation). User could solve their problem by providing the fitness calculation function and run the code. 13 | 14 | Please note that OpenCLGA is implemented at Python 3.5 or above. It should work at Python 2.x but it is not guaranteed. 15 | 16 | 17 | Demo Video 18 | ============================== 19 | Taiwan Travel example: https://youtu.be/4pqmuV8RkMg 20 | 21 | Prerequisite: install PYOPENCL 22 | ============================== 23 | Option A. Please refer to https://wiki.tiker.net/PyOpenCL to find your OS or 24 | 25 | Option B. Install by ourself 26 | 27 | - Windows 10 (just to install all required stuff in a quick way) 28 | 29 | * Step 1. Install platform opencl graphic driver, e.g. Intel CPU or Intel HD Grahics (https://software.intel.com/en-us/intel-opencl), NVIDIA GPU Driver (https://developer.nvidia.com/opencl) 30 | 31 | * Step 2. Install the following `*.whl` for python from 32 | 33 | 1. http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy 34 | 35 | 2. http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopencl 36 | 37 | - Ubuntu 16.04 38 | 39 | * Step 1. Install platform OpenCL graphic driver, i.e. 40 | 41 | 1. Intel CPU or Intel HD Graphics. 42 | 43 | a. `OpenCL™ 2.0 GPU/CPU driver package(SRB_4.1) for Linux* (64-bit) `_ 44 | 45 | b. `Installation instructions. `_ 46 | 47 | 48 | 49 | * Step 2. Download `Intel SDK for Application (2016 R3)& ICDs `_ and install, if you have Intel devices : :: 50 | 51 | $> sudo apt-get install libnuma1 alien 52 | $> tar -xvf ./intel_sdk_for_opencl_2016_ubuntu_6.3.0.1904_x64.tgz 53 | $> cd ./intel_sdk_for_opencl_2016_ubuntu_6.3.0.1904_x64/rpm 54 | $> sudo alien opencl-2.1-intel-cpu-exp-6.3.0.1904-1.x86_64.rpm 55 | $> sudo dpkg -i opencl-2.1-intel-cpu-exp_6.3.0.1904-2_amd64.deb 56 | $> sudo apt-get install clinfo 57 | // To verify platform information from OpenCL 58 | $> clinfo 59 | 60 | You can verify the installed OpenCL driver is located in /opt/intel/ and the ICD loader is located in /etc/OpenCL/vendors. 61 | 62 | * Step 3. Create a virtual environment for pyopencl. :: 63 | 64 | // Make sure dependencies for building wheel is available on system. 65 | $> sudo apt-get install build-essential libssl-dev libffi-dev python-dev 66 | $> sudo apt-get install python3-pip python3-venv python3-tk ocl-icd-* 67 | $> python3 -m venv [NameOfEnv] 68 | $> source ./NameOfEnv/bin/activate 69 | $> pip3 install --upgrade pip 70 | $> pip3 install pyopencl 71 | 72 | * Step 4. Verification :: 73 | 74 | $> python3 75 | > import pyopencl as cl 76 | > cl.create_some_context() 77 | 78 | - Mac OS X 79 | 80 | * Step 1. 81 | Install Python3: since OpenCL drivers had already included in Mac OS X, we don't need to install any OpenCL driver by ourself. So, we can start from Python3. :: 82 | 83 | $> brew update 84 | $> brew install python3 85 | $> pip3 install virtualenv 86 | 87 | *Note that you may not need to install virtualenv if you already installed it with python 2.7.* 88 | 89 | * Step 2. Create a virtual environment for pyopencl: before install pyopencl, we may need to install XCode developer console tool with `xcode-select --install` command. If you already had it, you don't need to run it. :: 90 | 91 | $> python3 -m venv [NameOfEnv] 92 | $> source ./NameOfEnv/bin/activate 93 | $> pip3 install --upgrade pip 94 | $> pip3 install pycparser cffi numpy wheel 95 | $> pip3 install pyopencl 96 | 97 | 98 | * Step 3. Verification. :: 99 | 100 | $> python3 101 | > import pyopencl as cl 102 | > cl.create_some_context() 103 | 104 | Run OpenCLGA examples 105 | ============================== 106 | 1. Enter virtual env (optional): 107 | 108 | * For Windows with MinGW environment. :: 109 | 110 | $> source /Scripts/activate 111 | 112 | * For Linux/Mac OS X environment. :: 113 | 114 | $> source ./NameOfEnv/bin/activate 115 | 116 | 117 | 2. Download the code from `Github `_ or git clone the repository via the following command. :: 118 | 119 | $> git clone https://github.com/PyOCL/OpenCLGA.git 120 | 121 | 3. Install Extra package (optional) : 122 | 123 | * For Linux environment. :: 124 | 125 | // To make matplotlib display correctly. 126 | $> sudo apt-get install python3-tk 127 | 128 | 4. Execute the code. :: 129 | 130 | $> pip3 install git+git://github.com/PyOCL/OpenCLGA.git 131 | $> unzip OpenCLGA-master.zip 132 | $> cd OpenCLGA-master 133 | $> python3 examples/tsp/simple_tsp.py 134 | 135 | *NOTE : In external process mode, if "no device" exception happen during create_some_context(), Please set PYOPENCL_CTX=N (N is the device number you want by default) at first.* 136 | 137 | *NOTE : Since we didn't publish this project to pipa. We need to install this project with source, `pip3 install .`.* 138 | -------------------------------------------------------------------------------- /examples/algebra_expansion/expansion.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import random 4 | from OpenCLGA import OpenCLGA, SimpleChromosome, SimpleGene, utils 5 | 6 | def show_generation_info(index, data_dict): 7 | print('{0}\t\t==> {1}'.format(index, data_dict['best'])) 8 | 9 | ''' 10 | In this example, we are trying to find the expansion of an algebra: 11 | (X + Y)^10 = aX^10 + bX^9Y + cX^8Y^2 ... + iX^2Y^8 + jXY^9 + kY^10 12 | 13 | We have 11 unknown elements: a, b, c, d, e, f, g, h, i, j, k 14 | 15 | The correct answer is: 1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1 16 | 17 | The chromosome has 11 genes and each of them has value range from 0 to 252. The combination of this 18 | question is 252^11. That is huge enough for GA. To have different types of gene, we change the value 19 | range of each gene to different values, like: 20 | gene 1: 1 ~ 10 21 | gene 2: 1 ~ 20 22 | gene 3: 1 ~ 50 23 | gene 4: 1 ~ 150 24 | gene 5: 1 ~ 250 25 | gene 6: 1 ~ 300 26 | gene 7: 1 ~ 250 27 | gene 9: 1 ~ 150 28 | gene 9: 1 ~ 50 29 | gene 10: 1 ~ 20 30 | gene 11: 1 ~ 10 31 | 32 | The original problem space is: 260,259,114,966,540,661,762,818,048 33 | The current problem space is: 42,187,500,000,000,000,000 34 | ''' 35 | def run(num_chromosomes, generations): 36 | value_ranges = [10, 20, 50, 150, 250, 300, 250, 150, 50, 20, 10] 37 | 38 | sample = SimpleChromosome([SimpleGene(0, list(range(v))) for v in value_ranges]) 39 | 40 | algebra_path = os.path.dirname(os.path.abspath(__file__)) 41 | ocl_kernels = os.path.realpath(os.path.join(algebra_path, '..', '..', 'kernel')) 42 | algebra_kernels = os.path.join(algebra_path, 'kernel') 43 | 44 | f = open(os.path.join(algebra_kernels, 'expansion.cl'), 'r') 45 | fstr = ''.join(f.readlines()) 46 | f.close() 47 | 48 | import threading 49 | evt = threading.Event() 50 | evt.clear() 51 | def state_changed(state): 52 | if 'stopped' == state: 53 | evt.set() 54 | 55 | ga_cl = OpenCLGA({'sample_chromosome': sample, 56 | 'termination': { 'type': 'count', 57 | 'count': generations }, 58 | 'population': num_chromosomes, 59 | 'fitness_kernel_str': fstr, 60 | 'fitness_func': 'expansion_fitness', 61 | 'extra_include_path': [ocl_kernels], 62 | 'opt_for_max': 'min', 63 | 'generation_callback': show_generation_info}, 64 | action_callbacks = {'state' : state_changed}) 65 | 66 | ga_cl.prepare() 67 | 68 | prob_mutate = 0.1 69 | prob_cross = 0.8 70 | ga_cl.run(prob_mutate, prob_cross) 71 | evt.wait() 72 | 73 | utils.plot_ga_result(ga_cl.get_statistics()) 74 | print('run took', ga_cl.elapsed_time, 'seconds') 75 | best_chromosome, best_fitness, best_info = ga_cl.get_the_best() 76 | print('Best Fitness: %f'%(best_fitness)) 77 | print('Expansion of (x + y)^10 is: ' + ' '.join(str(g) for g in best_chromosome)) 78 | 79 | if __name__ == '__main__': 80 | run(num_chromosomes=10000, generations=500) 81 | -------------------------------------------------------------------------------- /examples/algebra_expansion/kernel/expansion.cl: -------------------------------------------------------------------------------- 1 | float expansion_calc_difference(global __SimpleChromosome* chromosome, 2 | int x, 3 | int y) 4 | { 5 | float xy = 0.0 + x + y; 6 | float expected = pown(xy, 10); 7 | float calculated = 0.0; 8 | 9 | for (int i = 0; i < 11; i++) { 10 | calculated += (*chromosome).genes[i] * pown((float)x, 10 - i) * pown((float)y, i); 11 | } 12 | return fabs(expected - calculated); 13 | } 14 | 15 | void expansion_fitness(global __SimpleChromosome* chromosome, 16 | global float* fitnesses, 17 | int chromosome_size, 18 | int chromosome_count) 19 | { 20 | float diff = 0.0; 21 | for (int x = 1; x < 10; x++) { 22 | for (int y = 1; y < 10; y++) { 23 | diff += expansion_calc_difference(chromosome, x, y); 24 | } 25 | } 26 | // We should divide to 1,000,000 to prevent overflow of python float. 27 | *fitnesses = diff / 1000000; 28 | } 29 | -------------------------------------------------------------------------------- /examples/grouping/grouping.cl: -------------------------------------------------------------------------------- 1 | 2 | float calc_linear_distance(float x1, float y1, float x2, float y2) 3 | { 4 | return sqrt(pown(x2 - x1, 2) + pown(y2 - y1, 2)); 5 | } 6 | 7 | void grouping_fitness(global __SimpleChromosome* chromosome, 8 | global float* fitnesses, 9 | int chromosome_size, 10 | int chromosome_count, 11 | global int* numOfGroups, 12 | global float* pointX, 13 | global float* pointY) 14 | { 15 | float dist = 0.0; 16 | int group = numOfGroups[0]; 17 | for (int i = 0; i < group; i++) { 18 | for (int j = 0; j < chromosome_size; j++) { 19 | for (int k = j+1; k < chromosome_size; k++) { 20 | // Calculate the sum of dist among all points in the same group. 21 | if (i == chromosome->genes[j] && i == chromosome->genes[k]) { 22 | dist += calc_linear_distance(pointX[j], 23 | pointY[j], 24 | pointX[k], 25 | pointY[k]); 26 | } 27 | } 28 | } 29 | } 30 | *fitnesses = dist; 31 | } 32 | -------------------------------------------------------------------------------- /examples/grouping/grouping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import random 4 | from OpenCLGA import SimpleGene, SimpleChromosome, ShufflerChromosome, utils, OpenCLGA 5 | 6 | def show_generation_info(index, data_dict): 7 | print('{0}\t\t==> {1}'.format(index, data_dict['best'])) 8 | 9 | def run(num_chromosomes, generations): 10 | random.seed() 11 | 12 | # The number of points randomly generated 13 | num_points = 100 14 | random.seed() 15 | point_ids = list(range(0, num_points)) 16 | point_info = {point_id: (random.random() * 100, random.random() * 100) for point_id in point_ids} 17 | pointX = [str(point_info[v][0]) for v in point_info]; 18 | pointY = [str(point_info[v][1]) for v in point_info] 19 | 20 | # The number of group you want to divide. 21 | numOfGroups = 10 22 | group_id_set = list(range(0, numOfGroups)) 23 | group_ids = [random.randint(0,numOfGroups-1) for x in range(num_points)] 24 | 25 | sample = SimpleChromosome([SimpleGene(groupd_id, group_id_set) for groupd_id in group_ids]) 26 | 27 | self_path = os.path.dirname(os.path.abspath(__file__)) 28 | f = open(os.path.join(self_path, 'grouping.cl'), 'r') 29 | fstr = ''.join(f.readlines()) 30 | f.close() 31 | 32 | import threading 33 | evt = threading.Event() 34 | evt.clear() 35 | def state_changed(state): 36 | if 'stopped' == state: 37 | evt.set() 38 | 39 | ga_cl = OpenCLGA({'sample_chromosome': sample, 40 | 'termination': { 'type': 'count', 41 | 'count': generations }, 42 | 'population': num_chromosomes, 43 | 'fitness_kernel_str': fstr, 44 | 'fitness_func': 'grouping_fitness', 45 | 'fitness_args': [{'t': 'int', 'v': numOfGroups, 'n': 'numOfGroups'}, 46 | {'t': 'float', 'v': pointX, 'n': 'x'}, 47 | {'t': 'float', 'v': pointY, 'n': 'y'}], 48 | 'opt_for_max': 'min', 49 | 'debug': True, 50 | 'generation_callback': show_generation_info}, 51 | action_callbacks = {'state' : state_changed}) 52 | 53 | ga_cl.prepare() 54 | 55 | prob_mutate = 0.1 56 | prob_cross = 0.8 57 | ga_cl.run(prob_mutate, prob_cross) 58 | evt.wait() 59 | 60 | print('run took', ga_cl.elapsed_time, 'seconds') 61 | best_chromosome, best_fitness, best_info = ga_cl.get_the_best() 62 | print(best_chromosome) 63 | utils.plot_grouping_result(group_id_set, best_chromosome, point_info) 64 | 65 | if __name__ == '__main__': 66 | run(num_chromosomes=2000, generations=2000) 67 | -------------------------------------------------------------------------------- /examples/scheduling - power station/power.cl: -------------------------------------------------------------------------------- 1 | 2 | void generate_powers_type1(int* quarters, int value, int power) { 3 | // for type 1 power station, it uses 2 quarters for maintainence. 4 | // no power generates if it is at quarter 1, 2 or quarter 4, 1 5 | quarters[0] += (value == 3 || value == 0 ? 0 : power); 6 | // no power generates if it is at quarter 1, 2 or quarter 2, 3 7 | quarters[1] += (value == 0 || value == 1 ? 0 : power); 8 | // no power generates if it is at quarter 2, 3 or quarter 3, 4 9 | quarters[2] += (value == 1 || value == 2 ? 0 : power); 10 | // no power generates if it is at quarter 3, 4 or quarter 4, 1 11 | quarters[3] += (value == 2 || value == 3 ? 0 : power); 12 | } 13 | 14 | void generate_powers_type2(int* quarters, int value, int power) { 15 | // for type 2 power station, it uses 1 quarters for maintainence. 16 | // no power generates if it is at quarter 1 17 | quarters[0] += (value == 0 ? 0 : power); 18 | // no power generates if it is at quarter 2 19 | quarters[1] += (value == 1 ? 0 : power); 20 | // no power generates if it is at quarter 3 21 | quarters[2] += (value == 2 ? 0 : power); 22 | // no power generates if it is at quarter 4 23 | quarters[3] += (value == 3 ? 0 : power); 24 | } 25 | 26 | void power_station_fitness(global __SimpleChromosome* chromosome, 27 | global float* fitnesses, 28 | int chromosome_size, 29 | int chromosome_count) 30 | { 31 | 32 | // Assume that we have two types power generators: 33 | // Type 1: this type needs two quarters for maintainence. 34 | // Type 2: this type needs 1 quarter for maintainence. 35 | // We have 2 type 1 generators and 5 type 2 generates. In a year, we need to 36 | // schedule a maintainence plan. With this plan, the power consumptions of 37 | // each quarters have to be satisfied, that is 89, 90, 65, 70. The question is 38 | // what plan you will choose.. 39 | 40 | // The power generated by all units. 41 | int CAPACITIES[] = {20, 15, 34, 50, 15, 15, 10}; 42 | // The maximum load of each quarter 43 | int LOADS[] = {-80, -90, -65, -70}; 44 | // calculate the power generation by unit 1 ~ 7 at each quarters. 45 | generate_powers_type1(LOADS, chromosome->genes[0], CAPACITIES[0]); 46 | generate_powers_type1(LOADS, chromosome->genes[1], CAPACITIES[1]); 47 | generate_powers_type2(LOADS, chromosome->genes[2], CAPACITIES[2]); 48 | generate_powers_type2(LOADS, chromosome->genes[3], CAPACITIES[3]); 49 | generate_powers_type2(LOADS, chromosome->genes[4], CAPACITIES[4]); 50 | generate_powers_type2(LOADS, chromosome->genes[5], CAPACITIES[5]); 51 | generate_powers_type2(LOADS, chromosome->genes[6], CAPACITIES[6]); 52 | // let 53 | *fitnesses = LOADS[0] < LOADS[1] ? LOADS[0] : LOADS[1]; 54 | 55 | if (LOADS[2] < LOADS[3] && LOADS[2] < *fitnesses) { 56 | *fitnesses = LOADS[2]; 57 | } else if (LOADS[3] < *fitnesses) { 58 | *fitnesses = LOADS[3]; 59 | } 60 | 61 | if (*fitnesses < 0) { 62 | *fitnesses = 0; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /examples/scheduling - power station/power.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import random 4 | from OpenCLGA import SimpleGene, SimpleChromosome, utils, OpenCLGA 5 | 6 | def show_generation_info(index, data_dict): 7 | print('{0}\t\t==> {1}'.format(index, data_dict['best'])) 8 | 9 | def run(num_chromosomes, generations): 10 | random.seed() 11 | 12 | type1 = ['q12', 'q23', 'q34', 'q41'] 13 | type2 = ['q1', 'q2', 'q3', 'q4'] 14 | 15 | sample = SimpleChromosome([SimpleGene('q12', type1, 'unit-1'), 16 | SimpleGene('q12', type1, 'unit-2'), 17 | SimpleGene('q1', type2, 'unit-3'), 18 | SimpleGene('q1', type2, 'unit-4'), 19 | SimpleGene('q1', type2, 'unit-5'), 20 | SimpleGene('q1', type2, 'unit-6'), 21 | SimpleGene('q1', type2, 'unit-7')]) 22 | 23 | self_path = os.path.dirname(os.path.abspath(__file__)) 24 | f = open(os.path.join(self_path, 'power.cl'), 'r') 25 | fstr = ''.join(f.readlines()) 26 | f.close() 27 | 28 | import threading 29 | evt = threading.Event() 30 | evt.clear() 31 | def state_changed(state): 32 | if 'stopped' == state: 33 | evt.set() 34 | 35 | ga_cl = OpenCLGA({'sample_chromosome': sample, 36 | 'termination': { 37 | 'type': 'count', 38 | 'count': generations 39 | }, 40 | 'population': num_chromosomes, 41 | 'fitness_kernel_str': fstr, 42 | 'fitness_func': 'power_station_fitness', 43 | 'opt_for_max': 'max', 44 | 'debug': True, 45 | 'generation_callback': show_generation_info}, 46 | action_callbacks = {'state' : state_changed}) 47 | 48 | ga_cl.prepare() 49 | 50 | prob_mutate = 0.05 51 | prob_cross = 0.8 52 | ga_cl.run(prob_mutate, prob_cross) 53 | evt.wait() 54 | 55 | utils.plot_ga_result(ga_cl.get_statistics()) 56 | print('run took', ga_cl.elapsed_time, 'seconds') 57 | best_chromosome, best_fitness, best_info = ga_cl.get_the_best() 58 | print('Best Fitness: %f'%(best_fitness)) 59 | print('1 ~ 7 units are maintained at: ' + ', '.join(str(g.dna) for g in best_info.genes)) 60 | 61 | if __name__ == '__main__': 62 | run(num_chromosomes=50, generations=100) 63 | -------------------------------------------------------------------------------- /examples/taiwan_travel/TW319_368Addresses.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/TW319_368Addresses.xlsx -------------------------------------------------------------------------------- /examples/taiwan_travel/kernel/taiwan_fitness.cl: -------------------------------------------------------------------------------- 1 | 2 | float calc_spherical_distance(float x1, float y1, float x2, float y2) 3 | { 4 | float rad_x1 = x1 * 3.141592653589793 / 180.0; 5 | float rad_x2 = x2 * 3.141592653589793 / 180.0; 6 | float a = rad_x1 - rad_x2; 7 | float b = y1 * 3.141592653589793 / 180.0 - y2 * 3.141592653589793 / 180.0; 8 | float s = 2.0 * asin(sqrt(pow(sin(a / 2), 2) + cos(rad_x1) * cos(rad_x2) * pow(sin(b / 2), 2))); 9 | s = s * 6378.137; 10 | return s; 11 | } 12 | 13 | float taiwan_calc_fitness(global __ShufflerChromosome* chromosome, 14 | int chromosome_size, 15 | global float* pointsX, 16 | global float* pointsY) 17 | { 18 | float dist = 0.0; 19 | for (int i = 0; i < chromosome_size - 1; i++) { 20 | dist += calc_spherical_distance(pointsX[chromosome->genes[i + 1]], 21 | pointsY[chromosome->genes[i + 1]], 22 | pointsX[chromosome->genes[i]], 23 | pointsY[chromosome->genes[i]]); 24 | } 25 | return dist + calc_spherical_distance(pointsX[chromosome->genes[0]], 26 | pointsY[chromosome->genes[0]], 27 | pointsX[chromosome->genes[chromosome_size - 1]], 28 | pointsY[chromosome->genes[chromosome_size - 1]]); 29 | } 30 | 31 | void taiwan_fitness(global __ShufflerChromosome* chromosome, 32 | global float* fitnesses, 33 | int chromosome_size, 34 | int chromosome_count, 35 | global float* pointsX, 36 | global float* pointsY) 37 | { 38 | *fitnesses = taiwan_calc_fitness(chromosome, chromosome_size, pointsX, pointsY); 39 | } 40 | 41 | void taiwan_fitness_swap(global __ShufflerChromosome* chromosome, int cp, int p1) 42 | { 43 | int temp_p = chromosome->genes[cp]; 44 | chromosome->genes[cp] = chromosome->genes[p1]; 45 | chromosome->genes[p1] = temp_p; 46 | } 47 | 48 | int improving_only_mutation_helper(global int* c, 49 | int idx, 50 | int chromosome_size, 51 | global float* pointsX, 52 | global float* pointsY) 53 | { 54 | global __ShufflerChromosome* chromosome = (global __ShufflerChromosome*) c; 55 | // We will search the one whose distance is shorter than original one 56 | int best_index = idx; 57 | float shortest = taiwan_calc_fitness(chromosome, chromosome_size, pointsX, pointsY); 58 | float current; 59 | 60 | for (int i = 0; i < chromosome_size - 1; i++) { 61 | if (i == idx) { 62 | continue; 63 | } 64 | taiwan_fitness_swap(chromosome, i, idx); 65 | current = taiwan_calc_fitness(chromosome, chromosome_size, pointsX, pointsY); 66 | taiwan_fitness_swap(chromosome, i, idx); 67 | if (current < shortest) { 68 | shortest = current; 69 | best_index = i; 70 | } 71 | } 72 | return best_index; 73 | } 74 | -------------------------------------------------------------------------------- /examples/taiwan_travel/taiwan_travel_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | if __name__ == '__main__': 3 | from OpenCLGA import start_ocl_ga_client 4 | start_ocl_ga_client('127.0.0.1', 12345) 5 | -------------------------------------------------------------------------------- /examples/taiwan_travel/taiwan_travel_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import sys 4 | import time 5 | import json 6 | import random 7 | import pickle 8 | import threading 9 | import traceback 10 | from OpenCLGA import SimpleGene, ShufflerChromosome, start_ocl_ga_server, utils, OpenCLGA 11 | from pathlib import Path 12 | 13 | def read_all_cities(file_name): 14 | file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), file_name) 15 | cities_text = Path(file_path).read_text(encoding='UTF-8') 16 | cities_groups = json.loads(cities_text); 17 | cities = [] 18 | city_info = {} 19 | city_infoX = [] 20 | city_infoY = [] 21 | for group in cities_groups.keys(): 22 | for city_key in cities_groups[group]: 23 | city = cities_groups[group][city_key] 24 | cities.append({'x': float(city['Longitude']), 'y': float(city['Latitude']), 25 | 'address': city['Address'], 'name': city['Name']}) 26 | 27 | # to sort cities is very important for save and restore becase the sequence of name in json 28 | # object is not the same. 29 | cities = sorted(cities, key=lambda city: -city['y']) 30 | 31 | for idx in range(len(cities)): 32 | city = cities[idx] 33 | city_id = idx 34 | city_info[city_id] = (float(city['x']), float(city['y'])) 35 | city_infoX.append(float(city['x'])) 36 | city_infoY.append(float(city['y'])) 37 | 38 | return cities, city_info, city_infoX, city_infoY 39 | 40 | def serializer(chromosome): 41 | return json.dumps(chromosome.dna) 42 | 43 | def get_taiwan_travel_info(): 44 | ''' 45 | NOTE : Config TaiwanTravel GA parameters in dictionary 'dict_info'. 46 | ''' 47 | cities, city_info, city_infoX, city_infoY = read_all_cities('TW319_368Addresses-no-far-islands.json') 48 | city_ids = list(range(len(cities))) 49 | random.seed() 50 | 51 | tsp_path = os.path.dirname(os.path.abspath(__file__)) 52 | tsp_kernels = os.path.join(tsp_path, 'kernel') 53 | 54 | sample = ShufflerChromosome([SimpleGene(v, cities) for v in city_ids]) 55 | f = open(os.path.join(tsp_kernels, 'taiwan_fitness.cl'), 'r') 56 | fstr = ''.join(f.readlines()) 57 | f.close() 58 | 59 | # It seems we don't need to use this helper if we enlarge the population size. Please 60 | # re-evaluate and remove or uncomment the following line: 61 | # sample.use_improving_only_mutation('improving_only_mutation_helper') 62 | dict_info = { 'sample_chromosome' : sample, 63 | 'termination' : { 'type' : 'count', 64 | 'count' : 100 }, 65 | 'population' : 10240, 66 | 'fitness_kernel_str' : fstr, 67 | 'fitness_func' : 'taiwan_fitness', 68 | 'fitness_args' : [{ 't' : 'float', 'v' : city_infoX, 'n' : 'x' }, 69 | { 't' : 'float', 'v' : city_infoY, 'n' : 'y' }], 70 | 'opt_for_max' : 'min', 71 | 'saved_filename' : 'test%d%d.pickle', 72 | 'prob_mutation' : 0.1, 73 | 'prob_crossover' : 0.8, 74 | 'extinction' : { 'type' : 'best_avg', 75 | 'diff' : 1, 76 | 'ratio' : 0.9 }, 77 | 'elitism_mode' : { 'every' : 2, 'interval' : 10, 'compress' : False }, 78 | 'serializer': serializer} 79 | return dict_info 80 | 81 | lines_input = '' 82 | def get_input(): 83 | data = None 84 | try: 85 | time.sleep(0.01) 86 | if sys.platform in ['linux', 'darwin']: 87 | import select 88 | if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): 89 | data = sys.stdin.readline().rstrip() 90 | elif sys.platform == 'win32': 91 | global lines_input 92 | import msvcrt 93 | if msvcrt.kbhit(): 94 | data = msvcrt.getch().decode('utf-8') 95 | if data == '\r': 96 | # Enter is pressed 97 | data = lines_input 98 | lines_input = '' 99 | else: 100 | print(data) 101 | lines_input += data 102 | data = None 103 | else: 104 | pass 105 | except KeyboardInterrupt: 106 | data = 'exit' 107 | return data 108 | 109 | def show_generation_info(index, data_dict): 110 | msg = '{0}\t\t==> {1}'.format(index, data_dict['best']) 111 | print(msg) 112 | 113 | def start_ocl_ga_local(info): 114 | info['saved_filename'] = info['saved_filename']%(0, 0) 115 | info['generation_callback'] = show_generation_info 116 | prob_mutation = info['prob_mutation'] 117 | prob_crossover = info['prob_crossover'] 118 | 119 | ga_target = OpenCLGA(info) 120 | ga_target.prepare() 121 | try: 122 | print('Press run + to run') 123 | print('Press pause + to pause') 124 | print('Press restore + to restore') 125 | print('Press save + to save') 126 | print('Press stop + to stop') 127 | print('Press get_st + to get statistics information') 128 | print('Press get_best + to get best information') 129 | print('Press ctrl + c to exit') 130 | while True: 131 | user_input = get_input() 132 | if user_input == 'pause': 133 | ga_target.pause() 134 | elif user_input == 'run': 135 | ga_target.run(prob_mutation, prob_crossover) 136 | elif user_input == 'stop': 137 | ga_target.stop() 138 | elif user_input == 'get_st': 139 | st = ga_target.get_statistics() 140 | utils.plot_ga_result(st) 141 | elif user_input == 'get_best': 142 | best_chromosome, best_fitness, best_info = ga_target.get_the_best() 143 | cities, city_info, city_infoX, city_infoY = read_all_cities('TW319_368Addresses-no-far-islands.json') 144 | utils.plot_tsp_result(city_info, best_chromosome) 145 | elif user_input == 'exit': 146 | break 147 | elif user_input == 'save': 148 | ga_target.save() 149 | elif user_input == 'restore': 150 | ga_target.restore() 151 | except KeyboardInterrupt: 152 | traceback.print_exc() 153 | 154 | def start_tt_server(): 155 | print('Press 1 + to run as a OCL GA Server for remote clients.') 156 | print('Press 2 + to run Taiwan Travel OCL GA L-O-C-A-L-L-Y.') 157 | 158 | best = None 159 | city_info = None 160 | statistics = None 161 | def callback_from_client(info): 162 | nonlocal statistics, best, city_info 163 | if 'best' in info: 164 | cities = info['best'].dna 165 | best = list(range(len(cities))) 166 | city_info = [(float(c['x']), float(c['y'])) for c in cities] 167 | if 'statistics' in info: 168 | statistics = info['statistics'] 169 | pass 170 | 171 | tt_info = get_taiwan_travel_info() 172 | while True: 173 | user_input = get_input() 174 | if user_input == '1': 175 | ui = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'ui') 176 | start_ocl_ga_server(tt_info, 12345, { 'message' : callback_from_client }, ui) 177 | break 178 | elif user_input == '2': 179 | start_ocl_ga_local(tt_info) 180 | break 181 | elif user_input == 'exit': 182 | break 183 | 184 | if best and city_info: 185 | utils.plot_tsp_result(city_info, best) 186 | if statistics: 187 | utils.plot_ga_result(statistics) 188 | 189 | if __name__ == '__main__': 190 | start_tt_server() 191 | -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/android-icon-144x144.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/android-icon-192x192.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/android-icon-36x36.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/android-icon-48x48.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/android-icon-72x72.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/android-icon-96x96.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-114x114.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-120x120.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-144x144.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-152x152.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-180x180.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-57x57.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-60x60.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-72x72.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-76x76.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon-precomposed.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/apple-icon.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.css": "static/css/main.10448cc5.css", 3 | "main.css.map": "static/css/main.10448cc5.css.map", 4 | "main.js": "static/js/main.0b7ca193.js", 5 | "main.js.map": "static/js/main.0b7ca193.js.map" 6 | } -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/favicon-16x16.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/favicon-32x32.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/favicon-96x96.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/favicon.ico -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/index.html: -------------------------------------------------------------------------------- 1 | OpenCLGA UI
-------------------------------------------------------------------------------- /examples/taiwan_travel/ui/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/ms-icon-144x144.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/ms-icon-150x150.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/ms-icon-310x310.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyOCL/OpenCLGA/8192a337d5317795b5d4f1d5c9b76299bf4c4df4/examples/taiwan_travel/ui/ms-icon-70x70.png -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/static/css/main.10448cc5.css: -------------------------------------------------------------------------------- 1 | .app-header{background-color:#222;padding:20px;color:#fff;text-align:center}.app-container{font-size:large}.app.loading:before{z-index:1000;background-color:rgba(0,0,0,.34)}.app.loading.connecting:after,.app.loading:before{content:" ";position:fixed;top:0;left:0;bottom:0;right:0}.app.loading.connecting:after{z-index:1010;background-image:url("https://openclipart.org/download/231263/cherry-blossom-spinner.svg");background-size:33%;background-position:50%;background-repeat:no-repeat}.fixedDataTableCellGroupLayout_cellGroup{-webkit-backface-visibility:hidden;backface-visibility:hidden;left:0;overflow:hidden;position:absolute;top:0;white-space:nowrap}.fixedDataTableCellGroupLayout_cellGroup>.public_fixedDataTableCell_main{display:inline-block;vertical-align:top;white-space:normal}.fixedDataTableCellGroupLayout_cellGroupWrapper{position:absolute;top:0}.fixedDataTableCellLayout_main{border-right-style:solid;border-width:0 1px 0 0;box-sizing:border-box;display:block;overflow:hidden;position:absolute;white-space:normal}.fixedDataTableCellLayout_lastChild{border-width:0 1px 1px 0}.fixedDataTableCellLayout_alignRight{text-align:right}.fixedDataTableCellLayout_alignCenter{text-align:center}.fixedDataTableCellLayout_wrap1{display:table}.fixedDataTableCellLayout_wrap2{display:table-row}.fixedDataTableCellLayout_wrap3{display:table-cell;vertical-align:middle}.fixedDataTableCellLayout_columnResizerContainer{position:absolute;right:0;width:6px;z-index:1}.fixedDataTableCellLayout_columnResizerContainer:hover{cursor:ew-resize}.fixedDataTableCellLayout_columnResizerContainer:hover .fixedDataTableCellLayout_columnResizerKnob{visibility:visible}.fixedDataTableCellLayout_columnResizerKnob{position:absolute;right:0;visibility:hidden;width:4px}.fixedDataTableColumnResizerLineLayout_mouseArea{cursor:ew-resize;position:absolute;right:-5px;width:12px}.fixedDataTableColumnResizerLineLayout_main{border-right-style:solid;border-right-width:1px;box-sizing:border-box;position:absolute;z-index:10}.fixedDataTableColumnResizerLineLayout_hiddenElem,body[dir=rtl] .fixedDataTableColumnResizerLineLayout_main{display:none!important}.fixedDataTableLayout_main{border-style:solid;border-width:1px;box-sizing:border-box;overflow:hidden;position:relative}.fixedDataTableLayout_hasBottomBorder,.fixedDataTableLayout_header{border-bottom-style:solid;border-bottom-width:1px}.fixedDataTableLayout_footer .public_fixedDataTableCell_main{border-top-style:solid;border-top-width:1px}.fixedDataTableLayout_bottomShadow,.fixedDataTableLayout_topShadow{height:4px;left:0;position:absolute;right:0;z-index:1}.fixedDataTableLayout_bottomShadow{margin-top:-4px}.fixedDataTableLayout_rowsContainer{overflow:hidden;position:relative}.fixedDataTableLayout_horizontalScrollbar{bottom:0;position:absolute}.fixedDataTableRowLayout_main{box-sizing:border-box;overflow:hidden;position:absolute;top:0}.fixedDataTableRowLayout_body{left:0;position:absolute;top:0}.fixedDataTableRowLayout_fixedColumnsDivider{-webkit-backface-visibility:hidden;backface-visibility:hidden;border-left-style:solid;border-left-width:1px;left:0;position:absolute;top:0;width:0}.fixedDataTableRowLayout_columnsShadow{width:4px}.fixedDataTableRowLayout_rowWrapper{position:absolute;top:0}.ScrollbarLayout_main{box-sizing:border-box;outline:none;overflow:hidden;position:absolute;transition-duration:.25s;transition-timing-function:ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ScrollbarLayout_mainVertical{bottom:0;right:0;top:0;transition-property:background-color width;width:15px}.ScrollbarLayout_mainVertical.public_Scrollbar_mainActive,.ScrollbarLayout_mainVertical:hover{width:17px}.ScrollbarLayout_mainHorizontal{bottom:0;height:15px;left:0;transition-property:background-color height}.ScrollbarLayout_mainHorizontal.public_Scrollbar_mainActive,.ScrollbarLayout_mainHorizontal:hover{height:17px}.ScrollbarLayout_face{left:0;overflow:hidden;position:absolute;z-index:1}.ScrollbarLayout_face:after{border-radius:6px;content:"";display:block;position:absolute;transition:background-color .25s ease}.ScrollbarLayout_faceHorizontal{bottom:0;left:0;top:0}.ScrollbarLayout_faceHorizontal:after{bottom:4px;left:0;top:4px;width:100%}.ScrollbarLayout_faceVertical{left:0;right:0;top:0}.ScrollbarLayout_faceVertical:after{height:100%;left:4px;right:4px;top:0}.public_fixedDataTable_hasBottomBorder,.public_fixedDataTable_header,.public_fixedDataTable_main{border-color:#d3d3d3}.public_fixedDataTable_header .public_fixedDataTableCell_main{font-weight:700}.public_fixedDataTable_header,.public_fixedDataTable_header .public_fixedDataTableCell_main{background-color:#f6f7f8;background-image:linear-gradient(#fff,#efefef)}.public_fixedDataTable_footer .public_fixedDataTableCell_main{background-color:#f6f7f8;border-color:#d3d3d3}.public_fixedDataTable_topShadow{background:0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAECAYAAABP2FU6AAAAF0lEQVR4AWPUkNeSBhHCjJoK2twgFisAFagCCp3pJlAAAAAASUVORK5CYII=) repeat-x}.public_fixedDataTable_bottomShadow{background:0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAECAYAAABP2FU6AAAAHElEQVQI12MwNjZmZdAT1+Nm0JDWEGZQk1GTBgAWkwIeAEp52AAAAABJRU5ErkJggg==) repeat-x}.public_fixedDataTable_horizontalScrollbar .public_Scrollbar_mainHorizontal{background-color:#fff}.public_fixedDataTableCell_main{background-color:#fff;border-color:#d3d3d3}.public_fixedDataTableCell_highlighted{background-color:#f4f4f4}.public_fixedDataTableCell_cellContent{padding:8px}.public_fixedDataTableCell_columnResizerKnob{background-color:#0284ff}.public_fixedDataTableColumnResizerLine_main{border-color:#0284ff}.public_fixedDataTableRow_main{background-color:#fff}.public_fixedDataTableRow_highlighted,.public_fixedDataTableRow_highlighted .public_fixedDataTableCell_main{background-color:#f6f7f8}.public_fixedDataTableRow_fixedColumnsDivider{border-color:#d3d3d3}.public_fixedDataTableRow_columnsShadow{background:0 0 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAFklEQVQIHWPSkNeSBmJhTQVtbiDNCgASagIIuJX8OgAAAABJRU5ErkJggg==) repeat-y}.public_Scrollbar_main.public_Scrollbar_mainActive,.public_Scrollbar_main:hover{background-color:hsla(0,0%,100%,.8)}.public_Scrollbar_mainOpaque,.public_Scrollbar_mainOpaque.public_Scrollbar_mainActive,.public_Scrollbar_mainOpaque:hover{background-color:#fff}.public_Scrollbar_face:after{background-color:#c2c2c2}.public_Scrollbar_faceActive:after,.public_Scrollbar_main:hover .public_Scrollbar_face:after,.public_Scrollbar_mainActive .public_Scrollbar_face:after{background-color:#7d7d7d}body,html{margin:0;padding:0;font-family:sans-serif}.panel{width:calc(100% - 60px);margin-top:10px;margin-left:30px;margin-right:30px}.row{text-align:left}.row .control-label{margin-top:5px}.row .checkbox,.row .radio,.row .react-numeric-input{margin-top:5px;margin-bottom:10px;margin-right:10px}.row .react-numeric-input{margin-right:10px}.row .checkbox label,.row .radio label{min-width:90px;font-weight:700}.labeled-info-row{margin-left:20px;margin-right:20px;padding:5px 10px}.labeled-info-row .row{margin-left:0;margin-right:0}.labeled-info-row .info-row{margin-left:10px;margin-right:10px;font-size:x-large;text-transform:capitalize}.react-bs-table{background-color:#fff}.crossover-row .crossover-number,.elitism-mode-row .elitism-mode-number,.generations-row .generations-count-number,.generations-row .generations-time-number,.mutation-row .mutation-number,.population-row .population-number,.repopulating-row .repopulating-number{text-align:right}.elitism-mode-row .react-numeric-input,.repopulating-row .dropdown,.repopulating-row .react-numeric-input{margin-left:20px;margin-right:20px}.elitism-mode-row .react-numeric-input,.elitism-mode-row div,.repopulating-row .react-numeric-input,.repopulating-row div{display:inline-block;margin-top:0;margin-bottom:0}.elitism-mode-row{margin-top:20px}@-moz-document url-prefix(){.elitism-mode-row .react-numeric-input,.repopulating-row .react-numeric-input{top:5px}}.status-label-row.labeled-info-row{float:left;width:200px;border:2px solid green;border-radius:4px;box-shadow:2px 2px 4px #050}.status-label-row.prepared .info-row,.status-label-row.preparing .info-row,.status-label-row.restoring .info-row,.status-label-row.waiting .info-row{color:blue}.status-label-row.running .info-row{color:green}.status-label-row.paused .info-row,.status-label-row.pausing .info-row,.status-label-row.saving .info-row{color:#556b2f}.status-label-row.stopped .info-row,.status-label-row.stopping .info-row{color:#8b0000}.control-buttons{float:right;text-align:right;height:60px;margin:5px 10px;width:calc(100% - 270px)}.control-buttons .btn{height:60px;margin-left:10px;font-size:large}.control-buttons .btn:first-child{margin-left:0}@media screen and (max-width:768px){.control-buttons,.status-label-row{float:none;width:auto}.control-buttons{text-align:center;margin-top:20px}}.grid-text-cell{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding:0 8px}.widgets-panel-row{margin:10px 30px 0}.map{width:100%;height:600px} 2 | /*# sourceMappingURL=main.10448cc5.css.map*/ -------------------------------------------------------------------------------- /examples/taiwan_travel/ui/static/css/main.10448cc5.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"static/css/main.10448cc5.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples/tsp/kernel/simple_tsp.cl: -------------------------------------------------------------------------------- 1 | 2 | float calc_linear_distance(float x1, float y1, float x2, float y2) 3 | { 4 | return sqrt(pown(x2 - x1, 2) + pown(y2 - y1, 2)); 5 | } 6 | 7 | void simple_tsp_fitness(global __ShufflerChromosome* chromosome, 8 | global float* fitnesses, 9 | int chromosome_size, 10 | int chromosome_count, 11 | global float* pointsX, 12 | global float* pointsY) 13 | { 14 | float dist = 0.0; 15 | for (int i = 0; i < chromosome_size-1; i++) { 16 | dist += calc_linear_distance(pointsX[chromosome->genes[i + 1]], 17 | pointsY[chromosome->genes[i + 1]], 18 | pointsX[chromosome->genes[i]], 19 | pointsY[chromosome->genes[i]]); 20 | } 21 | dist += calc_linear_distance(pointsX[chromosome->genes[0]], 22 | pointsY[chromosome->genes[0]], 23 | pointsX[chromosome->genes[chromosome_size - 1]], 24 | pointsY[chromosome->genes[chromosome_size - 1]]); 25 | *fitnesses = dist; 26 | } 27 | -------------------------------------------------------------------------------- /examples/tsp/simple_tsp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import random 4 | from OpenCLGA import SimpleGene, ShufflerChromosome, utils, OpenCLGA 5 | 6 | def show_generation_info(index, data_dict): 7 | print('{0}\t\t==> {1}'.format(index, data_dict['best'])) 8 | 9 | def run(num_chromosomes, generations): 10 | num_cities = 20 11 | random.seed() 12 | city_ids = list(range(0, num_cities)) 13 | city_info = {city_id: (random.random() * 100, random.random() * 100) for city_id in city_ids} 14 | 15 | sample = ShufflerChromosome([SimpleGene(v, city_ids) for v in city_ids]) 16 | 17 | tsp_path = os.path.dirname(os.path.abspath(__file__)) 18 | tsp_kernels = os.path.join(tsp_path, 'kernel') 19 | 20 | f = open(os.path.join(tsp_kernels, 'simple_tsp.cl'), 'r') 21 | fstr = ''.join(f.readlines()) 22 | f.close() 23 | 24 | pointX = [str(city_info[v][0]) for v in city_info]; 25 | pointY = [str(city_info[v][1]) for v in city_info] 26 | 27 | import threading 28 | evt = threading.Event() 29 | evt.clear() 30 | def state_changed(state): 31 | if 'stopped' == state: 32 | evt.set() 33 | 34 | tsp_ga_cl = OpenCLGA({'sample_chromosome': sample, 35 | 'termination': { 36 | 'type': 'count', 37 | 'count': generations 38 | }, 39 | 'population': num_chromosomes, 40 | 'fitness_kernel_str': fstr, 41 | 'fitness_func': 'simple_tsp_fitness', 42 | 'fitness_args': [{'t': 'float', 'v': pointX, 'n': 'x'}, 43 | {'t': 'float', 'v': pointY, 'n': 'y'}], 44 | 'opt_for_max': 'min', 45 | 'debug': True, 46 | 'generation_callback': show_generation_info}, 47 | action_callbacks = {'state' : state_changed}) 48 | 49 | tsp_ga_cl.prepare() 50 | 51 | prob_mutate = 0.1 52 | prob_cross = 0.8 53 | tsp_ga_cl.run(prob_mutate, prob_cross) 54 | evt.wait() 55 | 56 | utils.plot_ga_result(tsp_ga_cl.get_statistics()) 57 | print('run took', tsp_ga_cl.elapsed_time, 'seconds') 58 | best_chromosome, best_fitness, best_info = tsp_ga_cl.get_the_best() 59 | print('Best Fitness: %f'%(best_fitness)) 60 | print('Shortest Path: ' + ' => '.join(str(g) for g in best_chromosome)) 61 | utils.plot_tsp_result(city_info, best_chromosome) 62 | 63 | if __name__ == '__main__': 64 | run(num_chromosomes=4000, generations=1000) 65 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | import sys 4 | from setuptools import setup, find_packages 5 | 6 | # We intend to support Python 3.5+, let's get rid of 2.x ! 7 | if (sys.version_info[0], sys.version_info[1]) <= (3, 4): 8 | sys.exit('Sorry, only Python 3.5+ is supported') 9 | 10 | package_files_paths = [] 11 | def package_files(directory): 12 | global package_files_paths 13 | for (path, directories, filenames) in os.walk(directory): 14 | for filename in filenames: 15 | if filename == '.gitignore': 16 | continue 17 | print(filename) 18 | package_files_paths.append(os.path.join('..', path, filename)) 19 | 20 | package_files('OpenCLGA/ui') 21 | package_files('OpenCLGA/kernel') 22 | 23 | setup(name='OpenCLGA', 24 | version='0.1', 25 | description='Run a general purpose genetic algorithm on top of pyopencl.', 26 | url='https://github.com/PyOCL/OpenCLGA.git', 27 | author='John Hu(胡訓誠), Kilik Kuo(郭彥廷)', 28 | author_email='im@john.hu, kilik.kuo@gmail.com', 29 | license='MIT', 30 | include_package_data=True, 31 | packages=find_packages(), 32 | package_data={ 33 | 'OpenCLGA': package_files_paths, 34 | }, 35 | install_requires=[ 36 | 'pybind11', 37 | 'matplotlib', 38 | 'numpy', 39 | 'pyopencl' 40 | ], 41 | zip_safe=False) 42 | --------------------------------------------------------------------------------