├── .gitignore ├── LICENSE.md ├── README.md ├── assets ├── djibouti.txt ├── qatar.txt ├── uruguay.txt └── western_sahara.txt ├── diagrams ├── d_0.png ├── d_1000.png ├── d_500.png ├── d_e.png ├── d_l.png ├── d_s.png ├── q_0.png ├── q_2500.png ├── q_5000.png ├── q_e.png ├── q_l.png ├── q_s.png ├── u_0.png ├── u_10000.png ├── u_5000.png ├── u_e.png ├── u_l.png ├── u_s.png ├── uruguay.gif ├── w_0.png ├── w_250.png ├── w_500.png ├── w_e.png ├── w_l.png └── w_s.png ├── report.tex └── src ├── decay.py ├── distances.py ├── helper.py ├── neighborhood.py └── som.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/python 2 | 3 | ### Python ### 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *,cover 49 | .hypothesis/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # dotenv 82 | .env 83 | 84 | # virtualenv 85 | .venv/ 86 | venv/ 87 | ENV/ 88 | 89 | # Spyder project settings 90 | .spyderproject 91 | 92 | # Rope project settings 93 | .ropeproject 94 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Diego Vicente & Leonard Kleinhans 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Self-Organizing Maps for Travelling Salesman Problem 2 | 3 | ## Introduction 4 | 5 | Self-organizing maps (SOM) or Kohonen maps are a type of artificial neural network (ANN) that mixes in an interesting way the concepts of competitive and cooperative neural networks. A SOM behaves as a typical competitive ANN, where the neurons fight for a case. The interesting twist added by Kohonen is that **when a neurons wins a case, the prize is shared with its neighbors**. Typically, the neighborhood is bigger at the beginning of the training, and it shrinks in order to let the system converge to a solution. 6 | 7 | ## Applying SOM to TSP 8 | 9 | One of the most interesting applications of this technique is applying it to the [Travelling Salesman Problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem), in which we can use a coordinate map and trace a route using the neurons in the ANN. By defining weight vectors as positions in the map, we can iterate the cities and treat each one as a case that can be won by a single neuron. The neuron that wins the case gets it weight vector updated to be closer to the city, but also its neighbors get updated. The neurons are placed in a 2D space, but they are only aware of a single dimension in their internal ANN, so their behavior is like an elastic ring that will eventually fit all the cities in the shortest distance possible. 10 | 11 | ![Kohonen Maps in Uruguay](diagrams/uruguay.gif) 12 | 13 | The method will rarely find the optimal route among the cities, and it is quite sensitive to changing the parameters, but it usually lays more than acceptable results taking into account the time consumed. 14 | 15 | In the repository you can find the source code to execute it (in Python 3) as well as the necessary maps in the `assets/` folder (already trimmed to be used in the code). The maps used have been extracted from the TSP page in [University of Waterloo](http://www.math.uwaterloo.ca/tsp/world/countries.html). There is also a `diagrams/` folder that contains all the execution snapshots that had to be included in the report (present as well as a `.tex` file). 16 | 17 | --- 18 | 19 | The code present in this repository was delivered as Project 3 in the [IT3105 Artificial Intelligence Programming](https://www.ntnu.edu/studies/courses/IT3105/2016/1) course in the Norwegian University of Science and Technology the course 2016-2017. The code was developed by [Leonard Kleinhans](https://github.com/leo-labs) and [Diego Vicente](https://github.com/DiegoVicen). The code is licensed under MIT License. 20 | -------------------------------------------------------------------------------- /assets/djibouti.txt: -------------------------------------------------------------------------------- 1 | 1 11003.611100 42102.500000 2 | 2 11108.611100 42373.888900 3 | 3 11133.333300 42885.833300 4 | 4 11155.833300 42712.500000 5 | 5 11183.333300 42933.333300 6 | 6 11297.500000 42853.333300 7 | 7 11310.277800 42929.444400 8 | 8 11416.666700 42983.333300 9 | 9 11423.888900 43000.277800 10 | 10 11438.333300 42057.222200 11 | 11 11461.111100 43252.777800 12 | 12 11485.555600 43187.222200 13 | 13 11503.055600 42855.277800 14 | 14 11511.388900 42106.388900 15 | 15 11522.222200 42841.944400 16 | 16 11569.444400 43136.666700 17 | 17 11583.333300 43150.000000 18 | 18 11595.000000 43148.055600 19 | 19 11600.000000 43150.000000 20 | 20 11690.555600 42686.666700 21 | 21 11715.833300 41836.111100 22 | 22 11751.111100 42814.444400 23 | 23 11770.277800 42651.944400 24 | 24 11785.277800 42884.444400 25 | 25 11822.777800 42673.611100 26 | 26 11846.944400 42660.555600 27 | 27 11963.055600 43290.555600 28 | 28 11973.055600 43026.111100 29 | 29 12058.333300 42195.555600 30 | 30 12149.444400 42477.500000 31 | 31 12286.944400 43355.555600 32 | 32 12300.000000 42433.333300 33 | 33 12355.833300 43156.388900 34 | 34 12363.333300 43189.166700 35 | 35 12372.777800 42711.388900 36 | 36 12386.666700 43334.722200 37 | 37 12421.666700 42895.555600 38 | 38 12645.000000 42973.333300 39 | -------------------------------------------------------------------------------- /assets/qatar.txt: -------------------------------------------------------------------------------- 1 | 1 24748.3333 50840.0000 2 | 2 24758.8889 51211.9444 3 | 3 24827.2222 51394.7222 4 | 4 24904.4444 51175.0000 5 | 5 24996.1111 51548.8889 6 | 6 25010.0000 51039.4444 7 | 7 25030.8333 51275.2778 8 | 8 25067.7778 51077.5000 9 | 9 25100.0000 51516.6667 10 | 10 25103.3333 51521.6667 11 | 11 25121.9444 51218.3333 12 | 12 25150.8333 51537.7778 13 | 13 25158.3333 51163.6111 14 | 14 25162.2222 51220.8333 15 | 15 25167.7778 51606.9444 16 | 16 25168.8889 51086.3889 17 | 17 25173.8889 51269.4444 18 | 18 25210.8333 51394.1667 19 | 19 25211.3889 51619.1667 20 | 20 25214.1667 50807.2222 21 | 21 25214.4444 51378.8889 22 | 22 25223.3333 51451.6667 23 | 23 25224.1667 51174.4444 24 | 24 25233.3333 51333.3333 25 | 25 25234.1667 51203.0556 26 | 26 25235.5556 51330.0000 27 | 27 25235.5556 51495.5556 28 | 28 25242.7778 51428.8889 29 | 29 25243.0556 51452.5000 30 | 30 25252.5000 51559.1667 31 | 31 25253.8889 51535.2778 32 | 32 25253.8889 51549.7222 33 | 33 25256.9444 51398.8889 34 | 34 25263.6111 51516.3889 35 | 35 25265.8333 51545.2778 36 | 36 25266.6667 50969.1667 37 | 37 25266.6667 51483.3333 38 | 38 25270.5556 51532.7778 39 | 39 25270.8333 51505.8333 40 | 40 25270.8333 51523.0556 41 | 41 25275.8333 51533.6111 42 | 42 25277.2222 51547.7778 43 | 43 25278.3333 51525.5556 44 | 44 25278.3333 51541.3889 45 | 45 25279.1667 51445.5556 46 | 46 25281.1111 51535.0000 47 | 47 25281.3889 51512.5000 48 | 48 25283.3333 51533.3333 49 | 49 25283.6111 51546.6667 50 | 50 25284.7222 51555.2778 51 | 51 25286.1111 51504.1667 52 | 52 25286.1111 51534.1667 53 | 53 25286.6667 51533.3333 54 | 54 25287.5000 51537.7778 55 | 55 25288.0556 51546.6667 56 | 56 25290.8333 51528.3333 57 | 57 25291.9444 51424.4444 58 | 58 25292.5000 51520.8333 59 | 59 25298.6111 51001.6667 60 | 60 25300.8333 51394.4444 61 | 61 25306.9444 51507.7778 62 | 62 25311.9444 51003.0556 63 | 63 25313.8889 50883.3333 64 | 64 25315.2778 51438.6111 65 | 65 25316.6667 50766.6667 66 | 66 25320.5556 51495.5556 67 | 67 25322.5000 51507.7778 68 | 68 25325.2778 51470.0000 69 | 69 25326.6667 51350.2778 70 | 70 25337.5000 51425.0000 71 | 71 25339.1667 51173.3333 72 | 72 25340.5556 51293.6111 73 | 73 25341.9444 51507.5000 74 | 74 25358.8889 51333.6111 75 | 75 25363.6111 51281.1111 76 | 76 25368.6111 51226.3889 77 | 77 25374.4444 51436.6667 78 | 78 25377.7778 51294.7222 79 | 79 25396.9444 51422.5000 80 | 80 25400.0000 51183.3333 81 | 81 25400.0000 51425.0000 82 | 82 25404.7222 51073.0556 83 | 83 25416.9444 51403.8889 84 | 84 25416.9444 51457.7778 85 | 85 25419.4444 50793.6111 86 | 86 25429.7222 50785.8333 87 | 87 25433.3333 51220.0000 88 | 88 25440.8333 51378.0556 89 | 89 25444.4444 50958.3333 90 | 90 25451.3889 50925.0000 91 | 91 25459.1667 51316.6667 92 | 92 25469.7222 51397.5000 93 | 93 25478.0556 51362.5000 94 | 94 25480.5556 50938.8889 95 | 95 25483.3333 51383.3333 96 | 96 25490.5556 51373.6111 97 | 97 25492.2222 51400.2778 98 | 98 25495.0000 50846.6667 99 | 99 25495.0000 50965.2778 100 | 100 25497.5000 51485.2778 101 | 101 25500.8333 50980.5556 102 | 102 25510.5556 51242.2222 103 | 103 25531.9444 51304.4444 104 | 104 25533.3333 50977.2222 105 | 105 25538.8889 51408.3333 106 | 106 25545.8333 51387.5000 107 | 107 25549.7222 51431.9444 108 | 108 25550.0000 51433.3333 109 | 109 25560.2778 51158.6111 110 | 110 25566.9444 51484.7222 111 | 111 25567.5000 50958.8889 112 | 112 25574.7222 51486.3889 113 | 113 25585.5556 51151.3889 114 | 114 25609.4444 51092.2222 115 | 115 25610.2778 51475.2778 116 | 116 25622.5000 51454.4444 117 | 117 25645.8333 51450.0000 118 | 118 25650.0000 51372.2222 119 | 119 25666.9444 51174.4444 120 | 120 25683.8889 51505.8333 121 | 121 25686.3889 51468.8889 122 | 122 25696.1111 51260.8333 123 | 123 25700.8333 51584.7222 124 | 124 25708.3333 51591.6667 125 | 125 25716.6667 51050.0000 126 | 126 25717.5000 51057.7778 127 | 127 25723.0556 51004.1667 128 | 128 25734.7222 51547.5000 129 | 129 25751.1111 51449.1667 130 | 130 25751.9444 50920.8333 131 | 131 25758.3333 51395.8333 132 | 132 25765.2778 51019.7222 133 | 133 25772.2222 51483.3333 134 | 134 25775.8333 51023.0556 135 | 135 25779.1667 51449.7222 136 | 136 25793.3333 51409.4444 137 | 137 25808.3333 51060.5556 138 | 138 25816.6667 51133.3333 139 | 139 25823.6111 51152.5000 140 | 140 25826.6667 51043.8889 141 | 141 25829.7222 51245.2778 142 | 142 25833.3333 51072.2222 143 | 143 25839.1667 51465.2778 144 | 144 25847.7778 51205.8333 145 | 145 25850.0000 51033.3333 146 | 146 25856.6667 51083.3333 147 | 147 25857.5000 51298.8889 148 | 148 25857.5000 51441.3889 149 | 149 25866.6667 51066.6667 150 | 150 25867.7778 51205.5556 151 | 151 25871.9444 51354.7222 152 | 152 25872.5000 51258.3333 153 | 153 25880.8333 51221.3889 154 | 154 25883.0556 51185.2778 155 | 155 25888.0556 51386.3889 156 | 156 25900.0000 51000.0000 157 | 157 25904.1667 51201.6667 158 | 158 25928.3333 51337.5000 159 | 159 25937.5000 51313.3333 160 | 160 25944.7222 51456.3889 161 | 161 25950.0000 51066.6667 162 | 162 25951.6667 51349.7222 163 | 163 25957.7778 51075.2778 164 | 164 25958.3333 51099.4444 165 | 165 25966.6667 51283.3333 166 | 166 25983.3333 51400.0000 167 | 167 25983.6111 51328.0556 168 | 168 26000.2778 51294.4444 169 | 169 26008.6111 51083.6111 170 | 170 26016.6667 51333.3333 171 | 171 26021.6667 51366.9444 172 | 172 26033.3333 51116.6667 173 | 173 26033.3333 51166.6667 174 | 174 26033.6111 51163.8889 175 | 175 26033.6111 51200.2778 176 | 176 26048.8889 51056.9444 177 | 177 26050.0000 51250.0000 178 | 178 26050.2778 51297.5000 179 | 179 26050.5556 51135.8333 180 | 180 26055.0000 51316.1111 181 | 181 26067.2222 51258.6111 182 | 182 26074.7222 51083.6111 183 | 183 26076.6667 51166.9444 184 | 184 26077.2222 51222.2222 185 | 185 26078.0556 51361.6667 186 | 186 26083.6111 51147.2222 187 | 187 26099.7222 51161.1111 188 | 188 26108.0556 51244.7222 189 | 189 26116.6667 51216.6667 190 | 190 26123.6111 51169.1667 191 | 191 26123.6111 51222.7778 192 | 192 26133.3333 51216.6667 193 | 193 26133.3333 51300.0000 194 | 194 26150.2778 51108.0556 195 | -------------------------------------------------------------------------------- /assets/uruguay.txt: -------------------------------------------------------------------------------- 1 | 1 30133.3333 57633.3333 2 | 2 30166.6667 57100.0000 3 | 3 30233.3333 57583.3333 4 | 4 30250.0000 56850.0000 5 | 5 30250.0000 56950.0000 6 | 6 30250.0000 57583.3333 7 | 7 30300.0000 56966.6667 8 | 8 30316.6667 56816.6667 9 | 9 30400.0000 56466.6667 10 | 10 30400.0000 56783.3333 11 | 11 30433.3333 57433.3333 12 | 12 30466.6667 56550.0000 13 | 13 30483.3333 56516.6667 14 | 14 30500.0000 56450.0000 15 | 15 30500.0000 56666.6667 16 | 16 30550.0000 57866.6667 17 | 17 30566.6667 56883.3333 18 | 18 30600.0000 57683.3333 19 | 19 30616.6667 56900.0000 20 | 20 30633.3333 56166.6667 21 | 21 30683.3333 57033.3333 22 | 22 30683.3333 57516.6667 23 | 23 30716.6667 56600.0000 24 | 24 30733.3333 56733.3333 25 | 25 30733.3333 57316.6667 26 | 26 30750.0000 56750.0000 27 | 27 30783.3333 57783.3333 28 | 28 30833.3333 56750.0000 29 | 29 30866.6667 56366.6667 30 | 30 30900.0000 55516.6667 31 | 31 30916.6667 56300.0000 32 | 32 30933.3333 55483.3333 33 | 33 30933.3333 55550.0000 34 | 34 30950.0000 56650.0000 35 | 35 30966.6667 55550.0000 36 | 36 30966.6667 57533.3333 37 | 37 31000.0000 55683.3333 38 | 38 31000.0000 56250.0000 39 | 39 31016.6667 56566.6667 40 | 40 31033.3333 56600.0000 41 | 41 31033.3333 56883.3333 42 | 42 31083.3333 56016.6667 43 | 43 31083.3333 56516.6667 44 | 44 31083.3333 57016.6667 45 | 45 31083.3333 57516.6667 46 | 46 31083.3333 57600.0000 47 | 47 31083.3333 57833.3333 48 | 48 31100.0000 55666.6667 49 | 49 31100.0000 55983.3333 50 | 50 31100.0000 57016.6667 51 | 51 31116.6667 56466.6667 52 | 52 31166.6667 55750.0000 53 | 53 31166.6667 57000.0000 54 | 54 31166.6667 57083.3333 55 | 55 31183.3333 56283.3333 56 | 56 31183.3333 56933.3333 57 | 57 31200.0000 55750.0000 58 | 58 31200.0000 57233.3333 59 | 59 31216.6667 55666.6667 60 | 60 31216.6667 56316.6667 61 | 61 31233.3333 55633.3333 62 | 62 31233.3333 55883.3333 63 | 63 31233.3333 57116.6667 64 | 64 31250.0000 55333.3333 65 | 65 31250.0000 55950.0000 66 | 66 31250.0000 56833.3333 67 | 67 31250.0000 57166.6667 68 | 68 31250.0000 57200.0000 69 | 69 31283.3333 56433.3333 70 | 70 31300.0000 55866.6667 71 | 71 31300.0000 56016.6667 72 | 72 31300.0000 57066.6667 73 | 73 31300.0000 57100.0000 74 | 74 31300.0000 57133.3333 75 | 75 31300.0000 57150.0000 76 | 76 31300.0000 57200.0000 77 | 77 31300.0000 57700.0000 78 | 78 31316.6667 55200.0000 79 | 79 31333.3333 57800.0000 80 | 80 31333.3333 57833.3333 81 | 81 31333.3333 57883.3333 82 | 82 31350.0000 55383.3333 83 | 83 31350.0000 56633.3333 84 | 84 31350.0000 57783.3333 85 | 85 31350.0000 57800.0000 86 | 86 31350.0000 57983.3333 87 | 87 31366.6667 55083.3333 88 | 88 31366.6667 55666.6667 89 | 89 31366.6667 55850.0000 90 | 90 31383.3333 55866.6667 91 | 91 31383.3333 57966.6667 92 | 92 31400.0000 56366.6667 93 | 93 31400.0000 57783.3333 94 | 94 31416.6667 54916.6667 95 | 95 31416.6667 56683.3333 96 | 96 31433.3333 55233.3333 97 | 97 31450.0000 55416.6667 98 | 98 31450.0000 56383.3333 99 | 99 31466.6667 55166.6667 100 | 100 31466.6667 56833.3333 101 | 101 31483.3333 54833.3333 102 | 102 31500.0000 54716.6667 103 | 103 31500.0000 55166.6667 104 | 104 31500.0000 56033.3333 105 | 105 31500.0000 57116.6667 106 | 106 31516.6667 54966.6667 107 | 107 31516.6667 55766.6667 108 | 108 31516.6667 55966.6667 109 | 109 31516.6667 57533.3333 110 | 110 31516.6667 57583.3333 111 | 111 31533.3333 55583.3333 112 | 112 31533.3333 55833.3333 113 | 113 31533.3333 56050.0000 114 | 114 31550.0000 55550.0000 115 | 115 31550.0000 57950.0000 116 | 116 31566.6667 54550.0000 117 | 117 31583.3333 55466.6667 118 | 118 31583.3333 57616.6667 119 | 119 31600.0000 55850.0000 120 | 120 31600.0000 56750.0000 121 | 121 31616.6667 56816.6667 122 | 122 31633.3333 55000.0000 123 | 123 31633.3333 56916.6667 124 | 124 31650.0000 56833.3333 125 | 125 31666.6667 56166.6667 126 | 126 31666.6667 56633.3333 127 | 127 31666.6667 57916.6667 128 | 128 31683.3333 54650.0000 129 | 129 31683.3333 54766.6667 130 | 130 31683.3333 55433.3333 131 | 131 31683.3333 55950.0000 132 | 132 31683.3333 56133.3333 133 | 133 31683.3333 57683.3333 134 | 134 31700.0000 56100.0000 135 | 135 31716.6667 55333.3333 136 | 136 31733.3333 54416.6667 137 | 137 31733.3333 55983.3333 138 | 138 31750.0000 55016.6667 139 | 139 31750.0000 55466.6667 140 | 140 31750.0000 56066.6667 141 | 141 31766.6667 54800.0000 142 | 142 31766.6667 56016.6667 143 | 143 31766.6667 56250.0000 144 | 144 31783.3333 54333.3333 145 | 145 31783.3333 54750.0000 146 | 146 31783.3333 55150.0000 147 | 147 31783.3333 56250.0000 148 | 148 31800.0000 54716.6667 149 | 149 31800.0000 55333.3333 150 | 150 31800.0000 55700.0000 151 | 151 31800.0000 56133.3333 152 | 152 31816.6667 54666.6667 153 | 153 31816.6667 55183.3333 154 | 154 31816.6667 55216.6667 155 | 155 31816.6667 55500.0000 156 | 156 31816.6667 55916.6667 157 | 157 31816.6667 55966.6667 158 | 158 31833.3333 54166.6667 159 | 159 31833.3333 55766.6667 160 | 160 31833.3333 55933.3333 161 | 161 31833.3333 55983.3333 162 | 162 31833.3333 57250.0000 163 | 163 31850.0000 56000.0000 164 | 164 31866.6667 54200.0000 165 | 165 31866.6667 57283.3333 166 | 166 31883.3333 55433.3333 167 | 167 31883.3333 55966.6667 168 | 168 31883.3333 56000.0000 169 | 169 31883.3333 57333.3333 170 | 170 31883.3333 57483.3333 171 | 171 31883.3333 57516.6667 172 | 172 31900.0000 54150.0000 173 | 173 31900.0000 54783.3333 174 | 174 31900.0000 55133.3333 175 | 175 31900.0000 55466.6667 176 | 176 31900.0000 55883.3333 177 | 177 31916.6667 54733.3333 178 | 178 31916.6667 55933.3333 179 | 179 31916.6667 56016.6667 180 | 180 31916.6667 57250.0000 181 | 181 31916.6667 57716.6667 182 | 182 31950.0000 57883.3333 183 | 183 31966.6667 55050.0000 184 | 184 31966.6667 57516.6667 185 | 185 31983.3333 54166.6667 186 | 186 31983.3333 55683.3333 187 | 187 31983.3333 57416.6667 188 | 188 32000.0000 54133.3333 189 | 189 32000.0000 55483.3333 190 | 190 32000.0000 57166.6667 191 | 191 32000.0000 57300.0000 192 | 192 32000.0000 57583.3333 193 | 193 32016.6667 54200.0000 194 | 194 32016.6667 55066.6667 195 | 195 32016.6667 57333.3333 196 | 196 32016.6667 57466.6667 197 | 197 32033.3333 54183.3333 198 | 198 32033.3333 54566.6667 199 | 199 32033.3333 55666.6667 200 | 200 32033.3333 55783.3333 201 | 201 32050.0000 54633.3333 202 | 202 32050.0000 54866.6667 203 | 203 32050.0000 55383.3333 204 | 204 32066.6667 53766.6667 205 | 205 32066.6667 56350.0000 206 | 206 32083.3333 54250.0000 207 | 207 32083.3333 55650.0000 208 | 208 32083.3333 56866.6667 209 | 209 32083.3333 57916.6667 210 | 210 32100.0000 53750.0000 211 | 211 32100.0000 54866.6667 212 | 212 32100.0000 57416.6667 213 | 213 32100.0000 57816.6667 214 | 214 32116.6667 54066.6667 215 | 215 32116.6667 57566.6667 216 | 216 32150.0000 54200.0000 217 | 217 32150.0000 54883.3333 218 | 218 32150.0000 54950.0000 219 | 219 32150.0000 55050.0000 220 | 220 32150.0000 56116.6667 221 | 221 32166.6667 53750.0000 222 | 222 32166.6667 54116.6667 223 | 223 32166.6667 55016.6667 224 | 224 32166.6667 55950.0000 225 | 225 32183.3333 55033.3333 226 | 226 32183.3333 55283.3333 227 | 227 32183.3333 56066.6667 228 | 228 32200.0000 54066.6667 229 | 229 32200.0000 58000.0000 230 | 230 32216.6667 55600.0000 231 | 231 32216.6667 56016.6667 232 | 232 32233.3333 54983.3333 233 | 233 32233.3333 55733.3333 234 | 234 32233.3333 56500.0000 235 | 235 32250.0000 55750.0000 236 | 236 32250.0000 56516.6667 237 | 237 32250.0000 57300.0000 238 | 238 32266.6667 54916.6667 239 | 239 32266.6667 55900.0000 240 | 240 32283.3333 58050.0000 241 | 241 32300.0000 55333.3333 242 | 242 32321.3889 58075.5556 243 | 243 32333.3333 55883.3333 244 | 244 32333.3333 55966.6667 245 | 245 32333.3333 57050.0000 246 | 246 32333.3333 57800.0000 247 | 247 32333.3333 57933.3333 248 | 248 32333.3333 58133.3333 249 | 249 32350.0000 53833.3333 250 | 250 32350.0000 54133.3333 251 | 251 32350.0000 55833.3333 252 | 252 32350.0000 56550.0000 253 | 253 32350.0000 57200.0000 254 | 254 32366.6667 54183.3333 255 | 255 32366.6667 54766.6667 256 | 256 32366.6667 57850.0000 257 | 257 32366.6667 57983.3333 258 | 258 32383.3333 54350.0000 259 | 259 32383.3333 54666.6667 260 | 260 32383.3333 55066.6667 261 | 261 32383.3333 56683.3333 262 | 262 32383.3333 57500.0000 263 | 263 32383.3333 57600.0000 264 | 264 32400.0000 55350.0000 265 | 265 32400.0000 56716.6667 266 | 266 32400.0000 56900.0000 267 | 267 32416.6667 56166.6667 268 | 268 32416.6667 56333.3333 269 | 269 32416.6667 57383.3333 270 | 270 32416.6667 57583.3333 271 | 271 32416.6667 58150.0000 272 | 272 32433.3333 56350.0000 273 | 273 32450.0000 55033.3333 274 | 274 32450.0000 56033.3333 275 | 275 32466.6667 54316.6667 276 | 276 32466.6667 55233.3333 277 | 277 32466.6667 56166.6667 278 | 278 32483.3333 53516.6667 279 | 279 32483.3333 53716.6667 280 | 280 32483.3333 56350.0000 281 | 281 32483.3333 57750.0000 282 | 282 32500.0000 54016.6667 283 | 283 32500.0000 54416.6667 284 | 284 32500.0000 56033.3333 285 | 285 32516.6667 53483.3333 286 | 286 32516.6667 54533.3333 287 | 287 32516.6667 54583.3333 288 | 288 32516.6667 54683.3333 289 | 289 32516.6667 57750.0000 290 | 290 32533.3333 54566.6667 291 | 291 32533.3333 55500.0000 292 | 292 32533.3333 57133.3333 293 | 293 32566.6667 53416.6667 294 | 294 32566.6667 56883.3333 295 | 295 32566.6667 57366.6667 296 | 296 32566.6667 57483.3333 297 | 297 32583.3333 53383.3333 298 | 298 32600.0000 55583.3333 299 | 299 32616.6667 54600.0000 300 | 300 32616.6667 55833.3333 301 | 301 32616.6667 56483.3333 302 | 302 32633.3333 53300.0000 303 | 303 32633.3333 53900.0000 304 | 304 32633.3333 55116.6667 305 | 305 32633.3333 56350.0000 306 | 306 32633.3333 56750.0000 307 | 307 32650.0000 54250.0000 308 | 308 32650.0000 54450.0000 309 | 309 32666.6667 53616.6667 310 | 310 32666.6667 55450.0000 311 | 311 32683.3333 54633.3333 312 | 312 32683.3333 56883.3333 313 | 313 32683.3333 57633.3333 314 | 314 32683.3333 58133.3333 315 | 315 32700.0000 53966.6667 316 | 316 32716.6667 55600.0000 317 | 317 32716.6667 57466.6667 318 | 318 32750.0000 53483.3333 319 | 319 32750.0000 53733.3333 320 | 320 32750.0000 54400.0000 321 | 321 32750.0000 55650.0000 322 | 322 32750.0000 57750.0000 323 | 323 32766.6667 55433.3333 324 | 324 32766.6667 55633.3333 325 | 325 32766.6667 57783.3333 326 | 326 32766.6667 57883.3333 327 | 327 32783.3333 53833.3333 328 | 328 32783.3333 55900.0000 329 | 329 32800.0000 55800.0000 330 | 330 32800.0000 56416.6667 331 | 331 32800.0000 57050.0000 332 | 332 32816.6667 56516.6667 333 | 333 32833.3333 54766.6667 334 | 334 32833.3333 55483.3333 335 | 335 32833.3333 56183.3333 336 | 336 32833.3333 56433.3333 337 | 337 32833.3333 57716.6667 338 | 338 32850.0000 57683.3333 339 | 339 32866.6667 55916.6667 340 | 340 32866.6667 56466.6667 341 | 341 32883.3333 55416.6667 342 | 342 32883.3333 55516.6667 343 | 343 32883.3333 56800.0000 344 | 344 32900.0000 55233.3333 345 | 345 32900.0000 56083.3333 346 | 346 32900.0000 56133.3333 347 | 347 32916.6667 54966.6667 348 | 348 32916.6667 57733.3333 349 | 349 32933.3333 53950.0000 350 | 350 32933.3333 54266.6667 351 | 351 32933.3333 55516.6667 352 | 352 32933.3333 57116.6667 353 | 353 32933.3333 57650.0000 354 | 354 32950.0000 54216.6667 355 | 355 32966.6667 55400.0000 356 | 356 32983.3333 54583.3333 357 | 357 32983.3333 58050.0000 358 | 358 33000.0000 53633.3333 359 | 359 33000.0000 55133.3333 360 | 360 33000.0000 55783.3333 361 | 361 33016.6667 53700.0000 362 | 362 33016.6667 53950.0000 363 | 363 33016.6667 55050.0000 364 | 364 33016.6667 56483.3333 365 | 365 33033.3333 57000.0000 366 | 366 33050.0000 54066.6667 367 | 367 33050.0000 54150.0000 368 | 368 33050.0000 56483.3333 369 | 369 33066.6667 55850.0000 370 | 370 33083.3333 55966.6667 371 | 371 33083.3333 56183.3333 372 | 372 33083.3333 57433.3333 373 | 373 33100.0000 55133.3333 374 | 374 33100.0000 57633.3333 375 | 375 33100.0000 57733.3333 376 | 376 33116.6667 54816.6667 377 | 377 33116.6667 54833.3333 378 | 378 33116.6667 55983.3333 379 | 379 33132.5000 58295.5556 380 | 380 33133.3333 54933.3333 381 | 381 33133.3333 57150.0000 382 | 382 33150.0000 54150.0000 383 | 383 33166.6667 54966.6667 384 | 384 33166.6667 57583.3333 385 | 385 33183.3333 53900.0000 386 | 386 33183.3333 55700.0000 387 | 387 33183.3333 57466.6667 388 | 388 33200.0000 53800.0000 389 | 389 33200.0000 54750.0000 390 | 390 33200.0000 56783.3333 391 | 391 33216.6667 54383.3333 392 | 392 33216.6667 56683.3333 393 | 393 33233.3333 53850.0000 394 | 394 33233.3333 54383.3333 395 | 395 33233.3333 57133.3333 396 | 396 33250.0000 53900.0000 397 | 397 33250.0000 53916.6667 398 | 398 33250.0000 54016.6667 399 | 399 33250.0000 54333.3333 400 | 400 33250.0000 56016.6667 401 | 401 33250.0000 57333.3333 402 | 402 33255.8333 58019.1667 403 | 403 33266.6667 53783.3333 404 | 404 33266.6667 54416.6667 405 | 405 33266.6667 55100.0000 406 | 406 33266.6667 55116.6667 407 | 407 33283.3333 53933.3333 408 | 408 33300.0000 56350.0000 409 | 409 33333.3333 54783.3333 410 | 410 33333.3333 56466.6667 411 | 411 33333.3333 56933.3333 412 | 412 33333.3333 57950.0000 413 | 413 33350.0000 55616.6667 414 | 414 33350.0000 55633.3333 415 | 415 33366.6667 53666.6667 416 | 416 33366.6667 56483.3333 417 | 417 33383.3333 55083.3333 418 | 418 33383.3333 56416.6667 419 | 419 33383.3333 57550.0000 420 | 420 33400.0000 54683.3333 421 | 421 33400.0000 58316.6667 422 | 422 33413.0556 56500.5556 423 | 423 33416.6667 55633.3333 424 | 424 33416.6667 57066.6667 425 | 425 33450.0000 54533.3333 426 | 426 33450.0000 57733.3333 427 | 427 33466.6667 54200.0000 428 | 428 33466.6667 54650.0000 429 | 429 33466.6667 54666.6667 430 | 430 33466.6667 55116.6667 431 | 431 33466.6667 55200.0000 432 | 432 33466.6667 55616.6667 433 | 433 33483.3333 55150.0000 434 | 434 33483.3333 55566.6667 435 | 435 33483.3333 56150.0000 436 | 436 33483.3333 56483.3333 437 | 437 33500.0000 55216.6667 438 | 438 33500.0000 56750.0000 439 | 439 33500.0000 56866.6667 440 | 440 33516.6667 53783.3333 441 | 441 33516.6667 54916.6667 442 | 442 33516.6667 56400.0000 443 | 443 33516.6667 57833.3333 444 | 444 33533.3333 54433.3333 445 | 445 33533.3333 54600.0000 446 | 446 33533.3333 56900.0000 447 | 447 33533.3333 56933.3333 448 | 448 33538.8889 56888.6111 449 | 449 33544.1667 58197.2222 450 | 450 33550.0000 55666.6667 451 | 451 33550.0000 56900.0000 452 | 452 33566.6667 53850.0000 453 | 453 33583.3333 57300.0000 454 | 454 33583.3333 57583.3333 455 | 455 33583.3333 58083.3333 456 | 456 33600.0000 54316.6667 457 | 457 33600.0000 55333.3333 458 | 458 33600.0000 56350.0000 459 | 459 33600.0000 57133.3333 460 | 460 33600.0000 57983.3333 461 | 461 33616.6667 53716.6667 462 | 462 33616.6667 57633.3333 463 | 463 33616.6667 58283.3333 464 | 464 33650.0000 53800.0000 465 | 465 33650.0000 57533.3333 466 | 466 33666.6667 54200.0000 467 | 467 33683.3333 53450.0000 468 | 468 33683.3333 53550.0000 469 | 469 33683.3333 54650.0000 470 | 470 33683.3333 57566.6667 471 | 471 33716.6667 54533.3333 472 | 472 33716.6667 58083.3333 473 | 473 33716.6667 58266.6667 474 | 474 33733.3333 54750.0000 475 | 475 33733.3333 56333.3333 476 | 476 33733.3333 57833.3333 477 | 477 33750.0000 55283.3333 478 | 478 33750.0000 56466.6667 479 | 479 33750.0000 57483.3333 480 | 480 33750.0000 57616.6667 481 | 481 33766.6667 58350.0000 482 | 482 33800.0000 54000.0000 483 | 483 33800.0000 58250.0000 484 | 484 33816.6667 55550.0000 485 | 485 33816.6667 57550.0000 486 | 486 33833.3333 56300.0000 487 | 487 33850.0000 55166.6667 488 | 488 33850.0000 56883.3333 489 | 489 33850.0000 57016.6667 490 | 490 33850.0000 57683.3333 491 | 491 33866.6667 55550.0000 492 | 492 33866.6667 57000.0000 493 | 493 33866.6667 57516.6667 494 | 494 33866.6667 57616.6667 495 | 495 33883.3333 53500.0000 496 | 496 33883.3333 54716.6667 497 | 497 33883.3333 56450.0000 498 | 498 33883.3333 57383.3333 499 | 499 33883.3333 57400.0000 500 | 500 33883.3333 57666.6667 501 | 501 33883.3333 58416.6667 502 | 502 33900.0000 55150.0000 503 | 503 33900.0000 56833.3333 504 | 504 33916.6667 57783.3333 505 | 505 33933.3333 55266.6667 506 | 506 33933.3333 55683.3333 507 | 507 33933.3333 56250.0000 508 | 508 33933.3333 57466.6667 509 | 509 33933.3333 58166.6667 510 | 510 33950.0000 55850.0000 511 | 511 33950.0000 56750.0000 512 | 512 33950.0000 57900.0000 513 | 513 33950.0000 58233.3333 514 | 514 33966.6667 57100.0000 515 | 515 33966.6667 58283.3333 516 | 516 33983.3333 53983.3333 517 | 517 33983.3333 57900.0000 518 | 518 33983.3333 58150.0000 519 | 519 33983.3333 58250.0000 520 | 520 33989.1667 58285.5556 521 | 521 34000.0000 55666.6667 522 | 522 34000.0000 58250.0000 523 | 523 34016.6667 57650.0000 524 | 524 34033.3333 54283.3333 525 | 525 34033.3333 55650.0000 526 | 526 34033.3333 57833.3333 527 | 527 34033.3333 58133.3333 528 | 528 34050.0000 54783.3333 529 | 529 34050.0000 55883.3333 530 | 530 34050.0000 56200.0000 531 | 531 34066.6667 53933.3333 532 | 532 34066.6667 54500.0000 533 | 533 34066.6667 56300.0000 534 | 534 34066.6667 56383.3333 535 | 535 34066.6667 57350.0000 536 | 536 34066.6667 57716.6667 537 | 537 34083.3333 57383.3333 538 | 538 34095.5556 56214.1667 539 | 539 34100.0000 58000.0000 540 | 540 34116.6667 53950.0000 541 | 541 34133.3333 56400.0000 542 | 542 34150.0000 56950.0000 543 | 543 34152.2222 58012.5000 544 | 544 34153.0556 58176.6667 545 | 545 34166.6667 53833.3333 546 | 546 34166.6667 53850.0000 547 | 547 34166.6667 54666.6667 548 | 548 34166.6667 56683.3333 549 | 549 34183.3333 53783.3333 550 | 550 34183.3333 55733.3333 551 | 551 34183.3333 57933.3333 552 | 552 34189.1667 56339.4444 553 | 553 34200.0000 53933.3333 554 | 554 34200.0000 54750.0000 555 | 555 34200.0000 56216.6667 556 | 556 34200.0000 56983.3333 557 | 557 34200.0000 57100.0000 558 | 558 34200.0000 57783.3333 559 | 559 34200.0000 57866.6667 560 | 560 34216.6667 57000.0000 561 | 561 34233.3333 55733.3333 562 | 562 34233.3333 56866.6667 563 | 563 34250.0000 55933.3333 564 | 564 34250.0000 56683.3333 565 | 565 34266.6667 53933.3333 566 | 566 34266.6667 54316.6667 567 | 567 34266.6667 57450.0000 568 | 568 34283.3333 54983.3333 569 | 569 34283.3333 55233.3333 570 | 570 34283.3333 56216.6667 571 | 571 34283.3333 56916.6667 572 | 572 34283.3333 57616.6667 573 | 573 34290.5556 56388.8889 574 | 574 34300.0000 55966.6667 575 | 575 34300.0000 57233.3333 576 | 576 34300.0000 57733.3333 577 | 577 34316.6667 56800.0000 578 | 578 34316.6667 57000.0000 579 | 579 34316.6667 57216.6667 580 | 580 34316.6667 57350.0000 581 | 581 34319.1667 56805.2778 582 | 582 34333.3333 55450.0000 583 | 583 34333.3333 55650.0000 584 | 584 34333.3333 57233.3333 585 | 585 34333.3333 57716.6667 586 | 586 34337.5000 56713.6111 587 | 587 34350.0000 55766.6667 588 | 588 34350.0000 56650.0000 589 | 589 34350.0000 57300.0000 590 | 590 34350.0000 57433.3333 591 | 591 34350.0000 57850.0000 592 | 592 34351.6667 56398.3333 593 | 593 34366.6667 53766.6667 594 | 594 34366.6667 53833.3333 595 | 595 34366.6667 54066.6667 596 | 596 34366.6667 55166.6667 597 | 597 34366.6667 55516.6667 598 | 598 34366.6667 55783.3333 599 | 599 34366.6667 56400.0000 600 | 600 34366.6667 57050.0000 601 | 601 34366.6667 57066.6667 602 | 602 34366.6667 57566.6667 603 | 603 34370.0000 55225.0000 604 | 604 34382.7778 56541.6667 605 | 605 34383.3333 56283.3333 606 | 606 34383.3333 56383.3333 607 | 607 34383.3333 56766.6667 608 | 608 34400.0000 53783.3333 609 | 609 34400.0000 56333.3333 610 | 610 34400.0000 56533.3333 611 | 611 34400.0000 57166.6667 612 | 612 34400.0000 57333.3333 613 | 613 34400.0000 57666.6667 614 | 614 34400.0000 57883.3333 615 | 615 34411.6667 56402.2222 616 | 616 34416.6667 56466.6667 617 | 617 34416.6667 57283.3333 618 | 618 34416.6667 57733.3333 619 | 619 34419.7222 56422.5000 620 | 620 34433.3333 55983.3333 621 | 621 34433.3333 57416.6667 622 | 622 34433.3333 57716.6667 623 | 623 34433.3333 57883.3333 624 | 624 34442.2222 56443.6111 625 | 625 34449.7222 56079.1667 626 | 626 34450.0000 55783.3333 627 | 627 34450.0000 56166.6667 628 | 628 34450.0000 56250.0000 629 | 629 34450.0000 56283.3333 630 | 630 34450.0000 57600.0000 631 | 631 34453.3333 56390.5556 632 | 632 34466.6667 57716.6667 633 | 633 34466.6667 57850.0000 634 | 634 34483.3333 54333.3333 635 | 635 34483.3333 55633.3333 636 | 636 34483.3333 55650.0000 637 | 637 34483.3333 56850.0000 638 | 638 34497.5000 56037.2222 639 | 639 34500.0000 55583.3333 640 | 640 34500.0000 56383.3333 641 | 641 34516.6667 55250.0000 642 | 642 34519.7222 56798.8889 643 | 643 34521.9444 56393.6111 644 | 644 34522.7778 56277.7778 645 | 645 34533.3333 56300.0000 646 | 646 34533.3333 56316.6667 647 | 647 34550.0000 55883.3333 648 | 648 34566.6667 55700.0000 649 | 649 34583.3333 55833.3333 650 | 650 34583.8889 56699.4444 651 | 651 34589.4444 56252.7778 652 | 652 34600.0000 54550.0000 653 | 653 34600.0000 55483.3333 654 | 654 34600.0000 56133.3333 655 | 655 34605.0000 56356.3889 656 | 656 34633.3333 55616.6667 657 | 657 34633.3333 55966.6667 658 | 658 34633.3333 56333.3333 659 | 659 34633.3333 56619.1667 660 | 660 34646.9444 56062.7778 661 | 661 34650.0000 55233.3333 662 | 662 34650.0000 55866.6667 663 | 663 34650.0000 56600.0000 664 | 664 34650.0000 56716.6667 665 | 665 34650.0000 56750.0000 666 | 666 34665.0000 56219.4444 667 | 667 34666.6667 54166.6667 668 | 668 34666.6667 55266.6667 669 | 669 34666.6667 56000.0000 670 | 670 34683.3333 55683.3333 671 | 671 34683.3333 56733.3333 672 | 672 34698.3333 56217.5000 673 | 673 34700.0000 55900.0000 674 | 674 34715.2778 56073.3333 675 | 675 34716.6667 55416.6667 676 | 676 34716.6667 55533.3333 677 | 677 34716.6667 55950.0000 678 | 678 34726.3889 56220.0000 679 | 679 34733.3333 55266.6667 680 | 680 34733.3333 55716.6667 681 | 681 34733.6111 56036.6667 682 | 682 34742.2222 56098.3333 683 | 683 34750.0000 55333.3333 684 | 684 34750.0000 55683.3333 685 | 685 34761.6667 56223.6111 686 | 686 34762.5000 56020.5556 687 | 687 34763.3333 56385.2778 688 | 688 34764.1667 56213.8889 689 | 689 34766.6667 55750.0000 690 | 690 34781.1111 56053.3333 691 | 691 34790.2778 56350.0000 692 | 692 34800.0000 54916.6667 693 | 693 34800.0000 55233.3333 694 | 694 34800.0000 55366.6667 695 | 695 34800.0000 56216.6667 696 | 696 34800.0000 56233.3333 697 | 697 34801.6667 56334.1667 698 | 698 34803.0556 56085.8333 699 | 699 34813.0556 56044.7222 700 | 700 34816.6667 56100.0000 701 | 701 34816.6667 56183.3333 702 | 702 34828.6111 56139.4444 703 | 703 34833.3333 56116.6667 704 | 704 34833.3333 56216.6667 705 | 705 34833.3333 56233.3333 706 | 706 34850.0000 56083.3333 707 | 707 34850.0000 56116.6667 708 | 708 34850.0000 56216.6667 709 | 709 34850.0000 56233.3333 710 | 710 34858.0556 56170.8333 711 | 711 34860.2778 56052.2222 712 | 712 34866.6667 54866.6667 713 | 713 34866.6667 56166.6667 714 | 714 34870.5556 56133.6111 715 | 715 34875.0000 56258.8889 716 | 716 34877.2222 56029.7222 717 | 717 34883.3333 56150.0000 718 | 718 34883.3333 56183.3333 719 | 719 34883.3333 56200.0000 720 | 720 34883.3333 56216.6667 721 | 721 34883.3333 56233.3333 722 | 722 34885.2778 56060.5556 723 | 723 34900.0000 54950.0000 724 | 724 34900.0000 55283.3333 725 | 725 34900.0000 56100.0000 726 | 726 34900.0000 56133.3333 727 | 727 34900.0000 56150.0000 728 | 728 34900.0000 56183.3333 729 | 729 34905.0000 56168.3333 730 | 730 34905.2778 56194.4444 731 | 731 34908.3333 56208.3333 732 | 732 34909.7222 56152.2222 733 | 733 34922.7778 56159.7222 734 | 734 34966.6667 54950.0000 735 | -------------------------------------------------------------------------------- /assets/western_sahara.txt: -------------------------------------------------------------------------------- 1 | 1 20833.3333 17100.0000 2 | 2 20900.0000 17066.6667 3 | 3 21300.0000 13016.6667 4 | 4 21600.0000 14150.0000 5 | 5 21600.0000 14966.6667 6 | 6 21600.0000 16500.0000 7 | 7 22183.3333 13133.3333 8 | 8 22583.3333 14300.0000 9 | 9 22683.3333 12716.6667 10 | 10 23616.6667 15866.6667 11 | 11 23700.0000 15933.3333 12 | 12 23883.3333 14533.3333 13 | 13 24166.6667 13250.0000 14 | 14 25149.1667 12365.8333 15 | 15 26133.3333 14500.0000 16 | 16 26150.0000 10550.0000 17 | 17 26283.3333 12766.6667 18 | 18 26433.3333 13433.3333 19 | 19 26550.0000 13850.0000 20 | 20 26733.3333 11683.3333 21 | 21 27026.1111 13051.9444 22 | 22 27096.1111 13415.8333 23 | 23 27153.6111 13203.3333 24 | 24 27166.6667 9833.3333 25 | 25 27233.3333 10450.0000 26 | 26 27233.3333 11783.3333 27 | 27 27266.6667 10383.3333 28 | 28 27433.3333 12400.0000 29 | 29 27462.5000 12992.2222 30 | -------------------------------------------------------------------------------- /diagrams/d_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/d_0.png -------------------------------------------------------------------------------- /diagrams/d_1000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/d_1000.png -------------------------------------------------------------------------------- /diagrams/d_500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/d_500.png -------------------------------------------------------------------------------- /diagrams/d_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/d_e.png -------------------------------------------------------------------------------- /diagrams/d_l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/d_l.png -------------------------------------------------------------------------------- /diagrams/d_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/d_s.png -------------------------------------------------------------------------------- /diagrams/q_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/q_0.png -------------------------------------------------------------------------------- /diagrams/q_2500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/q_2500.png -------------------------------------------------------------------------------- /diagrams/q_5000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/q_5000.png -------------------------------------------------------------------------------- /diagrams/q_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/q_e.png -------------------------------------------------------------------------------- /diagrams/q_l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/q_l.png -------------------------------------------------------------------------------- /diagrams/q_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/q_s.png -------------------------------------------------------------------------------- /diagrams/u_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/u_0.png -------------------------------------------------------------------------------- /diagrams/u_10000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/u_10000.png -------------------------------------------------------------------------------- /diagrams/u_5000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/u_5000.png -------------------------------------------------------------------------------- /diagrams/u_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/u_e.png -------------------------------------------------------------------------------- /diagrams/u_l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/u_l.png -------------------------------------------------------------------------------- /diagrams/u_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/u_s.png -------------------------------------------------------------------------------- /diagrams/uruguay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/uruguay.gif -------------------------------------------------------------------------------- /diagrams/w_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/w_0.png -------------------------------------------------------------------------------- /diagrams/w_250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/w_250.png -------------------------------------------------------------------------------- /diagrams/w_500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/w_500.png -------------------------------------------------------------------------------- /diagrams/w_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/w_e.png -------------------------------------------------------------------------------- /diagrams/w_l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/w_l.png -------------------------------------------------------------------------------- /diagrams/w_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego-vicente/ntnu-som/f28a218b7f30627c8e767b2308b5b40773785387/diagrams/w_s.png -------------------------------------------------------------------------------- /report.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | 3 | \usepackage{amsfonts} 4 | \usepackage[utf8]{inputenc} 5 | \usepackage{graphicx} 6 | \usepackage{wrapfig} 7 | \usepackage[english]{babel} 8 | \usepackage{listings} 9 | \usepackage{indentfirst} 10 | \usepackage{multirow} 11 | \usepackage{subcaption} 12 | 13 | \usepackage[a4paper, left=3cm, right=3cm, top=3cm]{geometry} 14 | 15 | \graphicspath{{diagrams/}} 16 | 17 | \begin{document} 18 | 19 | \begin{center} 20 | \Huge\textbf{Using Self-Organizing Maps to solve Travelling Salesman 21 | Problem}\\ 22 | \vspace{1cm} 23 | \large\textsc{Maximilian Leonard Kleinhans \& Diego Vicente Martín} 24 | \end{center} 25 | 26 | \section{System Overview} 27 | 28 | The goal of this system is to use Self-Organizing Maps to solve the Travelling 29 | Salesman Problem. To achieve that, we will create a population of neurons that 30 | is spatially distributed on a ring structure and as the algorithm progresses, 31 | neurons are pulled towards the cities. By defining a 1D neighborhood in this 2D 32 | space, we will make sure that the population behaves as an elastic ring that 33 | stretches until it occupies all the cities, while it tries to keep the perimeter 34 | as short as possible. Once we achieve it, we only have to traverse the cities 35 | following the ring to obtain a TSP solution.\\ 36 | 37 | The main component of the system is located in \texttt{som.py}: First we scale 38 | down the data, so that for each city coordinate $ c= (x, y) ~ 0 \le x,y \le 1$ 39 | holds true. Further is here the main execution loop located. In each iteration, 40 | we pick a random city. Then we compute the best matching unit, that is closest 41 | neuron to this city. That neuron, and its neighborhood, will be updated 42 | following the formula: 43 | 44 | $$ 45 | w_v(s+1) \; \leftarrow \; 46 | w_v(s) + \alpha (s) \cdot \eta (u, v, s) \cdot (D(t) - w_v) 47 | $$ 48 | 49 | Where $s$ is the iteration in which the neuron $w_u$ has been chosen as the 50 | winner of the city $D(t)$, and the formula is used to update all the neurons 51 | $w_v$ located in its neighborhood. The parameters in the formula are the 52 | learning rate $\alpha(s)$, the neighborhood function $\eta(u, v, s)$. We also 53 | have to remark that those last parameters decay over time. These weights 54 | associated to each vector are initialized in our system to random values that 55 | will be easily corrected through the first iterations, there is no point in 56 | wasting time or computations in finding different ways to initialize the 57 | network.\\ 58 | 59 | To achieve decaying, we will use different types of decay functions, that are 60 | represented in the \texttt{decay.py} file: static decay (that maintains the same 61 | value for that parameter through all the iterations), linear decay (that linearly 62 | decreases the value of the parameter), or exponential decay (that exponentially 63 | decays the value of the parameter). For convenience, these parameters have been 64 | implemented as classes that can be passed to the computation methods.\\ 65 | 66 | The calculation of a TSP solution from a list of neuron is done as described in 67 | chapter 4 in the compendium. That is, for each city we select the closest neuron 68 | and then define the city order through the order of the selected neurons.\\ 69 | 70 | Also relevant to the system is to notice that we have implemented two different 71 | neighborhood functions: \texttt{bubble}, constant in the while neighborhood, 0 72 | elsewhere and \text{gaussian}, that creates a Gaussian distribution around the 73 | winner. Both implementations can be find in the file 74 | \texttt{neighborhood.py}.\\ 75 | 76 | Apart from these computation files, we also have implemented helper methods for 77 | reading data sets from files and managing user input in \texttt{helper.py}. 78 | Furthermore also methods for plotting and saving snapshots of the system at 79 | different moments of the execution, to see how the system gets to a certain 80 | solution.\\ 81 | 82 | \section{Tuning the System} 83 | 84 | Once the system was implemented, we still had to work with it to get good 85 | results. Different combinations of parameters lay different results, 86 | and we had to be comprehensive when testing for parameters.\\ 87 | 88 | As a general conclusion, static decay is generally not a good decay approach to 89 | use. By keeping the parameters with a static value during all the execution is 90 | much harder to make the system converge into a solution. It is still possible to 91 | get decent results, but overall it is not worth to use static decay. If, in the 92 | other hand, we use linear, we can see the system converging much better to a 93 | certain solution: in the beginning the system tries different strategies to then 94 | focus on fixing the small details of the chosen one. More or less the same 95 | approach can be seen with exponential, but thanks to its nature it is able to 96 | stabilize much faster than linear. That's why, overall, the best decay strategy 97 | to use is exponential although linear can also lay great results (specially when 98 | applied to the learning rate alone). Another conclusion we can make is, that 99 | with increasing number of cities linear performs worse and in case of the 100 | \texttt{uruguay} data set with 734 cities we could not get decent results using 101 | linear decay.\\ 102 | 103 | Regarding neighborhood functions, the one that lays the best result is the 104 | Gaussian function. Although bubble does not lay bad results, we can see how 105 | Gaussian moves the network in a much softer fashion, due to its gradient to the 106 | edges versus the 1 or 0 values or bubble. Nevertheless bubble is much faster to 107 | compute and for increasing number of cities it might be more suitable in terms 108 | of runtime.\\ 109 | 110 | Other parameters to be tuned are the initial value of learning rates and 111 | neighbourhood size, although that depends on great part on the data set and the 112 | decay function we are going to use: static will need lower values and we will be 113 | able to use higher values at the beginning if we use a decay strategy. We also 114 | have to think about the size of the population of neurons. As a general rule, we 115 | will need more neurons than cities so we can model the path through all the 116 | cities in the map. As we have been able to test, the optimal size of the 117 | population to get a network with a proper size is about 4-8 times greater than 118 | the city population of the data set.\\ 119 | 120 | \newpage 121 | 122 | By doing this tuning, we came to the conclusion that these were the best parameters for each of the decay strategies: 123 | 124 | \begin{table}[ht] 125 | \begin{center} 126 | \begin{tabular}{| p{1.8cm}| c | c | c | c | c | c | c |} 127 | \hline 128 | Map & Decay & Neurons & $N$ 129 | & $\alpha_0$ (decay) & $r_0$ (decay)& TSP Dist.\\ 130 | \hline 131 | \hline 132 | \multirow{3}{*}{\textbf{\parbox{1.7cm}{Western Sahara}}} 133 | & Static & 174 & 5000 & 0.3 & 5 & 34814.67 \\ 134 | & Linear & 232 & 500 & 0.7 (0.001) & 23 (0.04) & 27620.78 \\ 135 | & Exponential & 232 & 500 & 0.7 (0.999) & 23 (0.995)& 27601.17 \\ 136 | \hline 137 | \multirow{3}{*}{\textbf{Djibouti}} 138 | & Static & 356 & 5000 & 0.2 & 10 & 7692.15\\ 139 | & Linear & 712 & 5000 & 0.7 (0.0001)& 71 (0.014)& 6659.91 \\ 140 | & Exponential & 712 & 1000 & 0.7 (0.999)& 71 (0.995)& 6659.91 \\ 141 | \hline 142 | \multirow{3}{*}{\textbf{Qatar}} 143 | & Static & 1164 & 5000 & 0.4 & 50 & 14678.38 \\ 144 | & Linear & 1552 & 10000 & 0.7 (0.000065) & 155 (0.015) &10284.41 \\ 145 | & Exponential & 1552 & 5000 & 0.9 (0.9999)& 155 (0.997)& 10195.32 \\ 146 | \hline 147 | \multirow{3}{*}{\textbf{Uruguay}} 148 | & Static & 5872 & 10000 & 0.4 & 500 & 357201.05 \\ 149 | & Linear & 5872 & 10000 & 0.9 (0.000089)& 587 (0.055)& 141536.50 \\ 150 | & Exponential & 5872 & 10000 & 0.7 (0.9999)& 587 (0.999) & 86819.03 \\ 151 | \hline 152 | \end{tabular} 153 | \end{center} 154 | \caption{Chosen parameters and results for TSP-SOM - $N$ is the number of iterations, $a_0$ the initial learning rate, $r_0$ the initial radius} 155 | \label{tab:params} 156 | \end{table} 157 | 158 | In figures \ref{fig:sahara}, \ref{fig:djibouti}, \ref{fig:qatar} and \ref{fig:uruguay} are the TSP paths with different decay functions shown. The algorithm was executed with parameters shown in table \ref{tab:params}. Red dots illustrate cities and green dots neuron positions. We can see, that we consistently could obtain the best results with exponential decay, followed by linear. Apparently when not using exponential decay the algorithm is not able to refine the path in the end, resulting in inferior solutions. \\ 159 | Finally are in figures \ref{fig:bsahara}, \ref{fig:bdjibouti}, \ref{fig:bqatar} and \ref{fig:buruguay} the best runs illustrates, at the beginning in the middle and the final result of each run. 160 | 161 | \begin{figure} 162 | \centering 163 | \begin{subfigure}{.33\textwidth} 164 | \centering 165 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true, 166 | width=\linewidth]{w_s.png} 167 | \caption{Static decay} 168 | \label{fig:ws} 169 | \end{subfigure}% 170 | \begin{subfigure}{.33\textwidth} 171 | \centering 172 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true,width=\linewidth]{w_l.png} 173 | \caption{Linear decay} 174 | \label{fig:wl} 175 | \end{subfigure} 176 | \begin{subfigure}{.33\textwidth} 177 | \centering 178 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true,width=\linewidth]{w_e.png} 179 | \caption{Exponential decay} 180 | \label{fig:we} 181 | \end{subfigure} 182 | \caption{Results on \texttt{western\_sahara}} 183 | \label{fig:sahara} 184 | \end{figure} 185 | 186 | \begin{figure} 187 | \centering 188 | \begin{subfigure}{.33\textwidth} 189 | \centering 190 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true, 191 | width=\linewidth]{d_s.png} 192 | \caption{Static decay} 193 | \end{subfigure}% 194 | \begin{subfigure}{.33\textwidth} 195 | \centering 196 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true,width=\linewidth]{d_l.png} 197 | \caption{Linear decay} 198 | \end{subfigure} 199 | \begin{subfigure}{.33\textwidth} 200 | \centering 201 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true,width=\linewidth]{d_e.png} 202 | \caption{Exponential decay} 203 | \end{subfigure} 204 | \caption{Results on \texttt{djibouti}} 205 | \label{fig:djibouti} 206 | \end{figure} 207 | 208 | \begin{figure} 209 | \centering 210 | \begin{subfigure}{.33\textwidth} 211 | \centering 212 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true, 213 | width=\linewidth]{q_s.png} 214 | \caption{Static decay} 215 | \end{subfigure}% 216 | \begin{subfigure}{.33\textwidth} 217 | \centering 218 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true,width=\linewidth]{q_l.png} 219 | \caption{Linear decay} 220 | \end{subfigure} 221 | \begin{subfigure}{.33\textwidth} 222 | \centering 223 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true,width=\linewidth]{q_e.png} 224 | \caption{Exponential decay} 225 | \end{subfigure} 226 | \caption{Results on \texttt{qatar}} 227 | \label{fig:qatar} 228 | \end{figure} 229 | 230 | \begin{figure} 231 | \centering 232 | \begin{subfigure}{.33\textwidth} 233 | \centering 234 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true, 235 | width=\linewidth]{u_s.png} 236 | \caption{Static decay} 237 | \end{subfigure}% 238 | \begin{subfigure}{.33\textwidth} 239 | \centering 240 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true,width=\linewidth]{u_l.png} 241 | \caption{Linear decay} 242 | \end{subfigure} 243 | \begin{subfigure}{.33\textwidth} 244 | \centering 245 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true,width=\linewidth]{u_e.png} 246 | \caption{Exponential decay} 247 | \end{subfigure} 248 | \caption{Results on \texttt{uruguay}} 249 | \label{fig:uruguay} 250 | \end{figure} 251 | 252 | \begin{figure} 253 | \centering 254 | \begin{subfigure}{.33\textwidth} 255 | \centering 256 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true, 257 | width=\linewidth]{w_0.png} 258 | \caption{Initial state} 259 | \end{subfigure}% 260 | \begin{subfigure}{.33\textwidth} 261 | \centering 262 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true,width=\linewidth]{w_250.png} 263 | \caption{After 250 iterations} 264 | \end{subfigure} 265 | \begin{subfigure}{.33\textwidth} 266 | \centering 267 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true,width=\linewidth]{w_500.png} 268 | \caption{After 500 iterations} 269 | \end{subfigure} 270 | \caption{Best results on \texttt{western\_sahara} with exponential decay} 271 | \label{fig:bsahara} 272 | \end{figure} 273 | 274 | \begin{figure} 275 | \centering 276 | \begin{subfigure}{.33\textwidth} 277 | \centering 278 | \includegraphics[trim={4cm 1cm 4cm 1cm}, clip=true, 279 | width=\linewidth]{d_0.png} 280 | \caption{Initial state} 281 | \end{subfigure}% 282 | \begin{subfigure}{.33\textwidth} 283 | \centering 284 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true,width=\linewidth]{d_500.png} 285 | \caption{After 500 iterations} 286 | \end{subfigure} 287 | \begin{subfigure}{.33\textwidth} 288 | \centering 289 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true,width=\linewidth]{d_1000.png} 290 | \caption{After 1000 iterations} 291 | \end{subfigure} 292 | \caption{Best results on \texttt{djibouti} with exponential decay} 293 | \label{fig:bdjibouti} 294 | \end{figure} 295 | 296 | \begin{figure} 297 | \centering 298 | \begin{subfigure}{.33\textwidth} 299 | \centering 300 | \includegraphics[trim={3cm 1.5cm 3cm 1.5cm}, clip=true, 301 | width=\linewidth]{q_0.png} 302 | \caption{Initial state} 303 | \end{subfigure}% 304 | \begin{subfigure}{.33\textwidth} 305 | \centering 306 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true,width=\linewidth]{q_2500.png} 307 | \caption{After 2500 iterations} 308 | \end{subfigure} 309 | \begin{subfigure}{.33\textwidth} 310 | \centering 311 | \includegraphics[trim={6cm 2cm 6cm 2cm}, clip=true,width=\linewidth]{q_5000.png} 312 | \caption{After 5000 iterations} 313 | \end{subfigure} 314 | \caption{Best results on \texttt{qatar} with exponential decay} 315 | \label{fig:bqatar} 316 | \end{figure} 317 | 318 | \begin{figure} 319 | \centering 320 | \begin{subfigure}{.33\textwidth} 321 | \centering 322 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true, 323 | width=\linewidth]{u_0.png} 324 | \caption{Initial state} 325 | \end{subfigure}% 326 | \begin{subfigure}{.33\textwidth} 327 | \centering 328 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true,width=\linewidth]{u_5000.png} 329 | \caption{After 5000 iterations} 330 | \end{subfigure} 331 | \begin{subfigure}{.33\textwidth} 332 | \centering 333 | \includegraphics[trim={4cm 2cm 4cm 2cm}, clip=true,width=\linewidth]{u_10000.png} 334 | \caption{After 10000 iterations} 335 | \end{subfigure} 336 | \caption{Best results on \texttt{uruguay} with exponential decay} 337 | \label{fig:buruguay} 338 | \end{figure} 339 | 340 | \end{document} 341 | -------------------------------------------------------------------------------- /src/decay.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | 4 | class DecayFunction(metaclass=abc.ABCMeta): 5 | """ 6 | Base class for decay functions, implemented with a strategy design pattern 7 | """ 8 | def __init__(self, init_value): 9 | self._value = init_value 10 | 11 | @property 12 | def value(self): 13 | return self._value 14 | 15 | @abc.abstractmethod 16 | def decay(self): 17 | pass 18 | 19 | 20 | class StaticDecay(DecayFunction): 21 | """ 22 | Not really a decay function. But since asked for, implemented as one. 23 | """ 24 | def decay(self): 25 | pass 26 | 27 | 28 | class LinearDecay(DecayFunction): 29 | """ 30 | Decaying with a constant rate 31 | """ 32 | def __init__(self, start_value, rate): 33 | self.rate = rate 34 | super().__init__(start_value) 35 | 36 | def decay(self): 37 | self._value -= self.rate 38 | 39 | 40 | class ExponentialDecay(DecayFunction): 41 | """ 42 | Decaying exponential. 43 | """ 44 | def __init__(self, start_value, rate): 45 | self.rate = rate 46 | super().__init__(start_value) 47 | 48 | def decay(self): 49 | self._value *= self.rate 50 | -------------------------------------------------------------------------------- /src/distances.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def manhattan_distance_2d(x, y): 5 | return abs(x[0] - y[0]) + abs(x[1] - y[1]) 6 | 7 | 8 | def euclidean_distance_2d(x, y): 9 | return math.sqrt(pow(y[0]-x[0],2) + pow(y[1]-x[1],2)) 10 | 11 | 12 | def euclidean_distance_1d(x, y): 13 | return abs(x-y) 14 | 15 | 16 | def euclidean_distance_1d_circular(n, i, j): 17 | """ 18 | Calculates 1d distance of integers i and j in a circle of n elements. 19 | :param n: Circle length 20 | :param i: Start element 21 | :param j: Target element 22 | :return: Minimal distance 23 | """ 24 | d = euclidean_distance_1d(i, j) 25 | return min(d, n-d) 26 | -------------------------------------------------------------------------------- /src/helper.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import os 3 | from decay import StaticDecay, LinearDecay, ExponentialDecay 4 | from neighborhood import gaussian, bubble 5 | 6 | DEFAULTS_EXP = {'uruguay': ('uruguay', 8, 10000, 1000, 500, bubble, 7 | ExponentialDecay(0.7, 0.9999), 8 | ExponentialDecay(734*8/10, 0.999)), 9 | 'western_sahara': ('western_sahara', 8, 500, 50, 50, gaussian, 10 | ExponentialDecay(0.7, 0.999), 11 | ExponentialDecay(29*8/10, 0.995)), 12 | 'qatar': ('qatar', 8, 5000, 500, 500, gaussian, 13 | ExponentialDecay(0.9, 0.9999), 14 | ExponentialDecay(194*8/10, 0.997)), 15 | 'djibouti': ('djibouti', 8, 1000, 50, 50, gaussian, 16 | ExponentialDecay(0.7, 0.999), 17 | ExponentialDecay(89*8/10, 0.995))} 18 | 19 | DEFAULTS_LIN = {'uruguay': ('uruguay', 8, 10000, 1000, 500, gaussian, 20 | LinearDecay(0.9, 0.000089), 21 | LinearDecay(734*8/10, 0.055)), 22 | 'western_sahara': ('western_sahara', 8, 500, 50, 50, gaussian, 23 | LinearDecay(0.7, 0.001), 24 | LinearDecay(29*8/10, 0.04)), 25 | 'qatar': ('qatar', 8, 10000, 500, 500, gaussian, 26 | LinearDecay(0.7, 0.000065), 27 | LinearDecay(194*8/10, 0.015)), 28 | 'djibouti': ('djibouti', 8, 5000, 50, 50, gaussian, 29 | LinearDecay(0.7, 0.0001), 30 | LinearDecay(89*8/10, 0.014))} 31 | 32 | DEFAULT_STA = {'uruguay': ('uruguay', 8, 10000, 1000, 200, gaussian, 33 | StaticDecay(0.4), 34 | StaticDecay(500)), 35 | 'western_sahara': ('western_sahara', 6, 5000, 1000, 200, gaussian, 36 | StaticDecay(0.3), 37 | StaticDecay(5)), 38 | 'qatar': ('qatar', 6, 5000, 1000, 200, gaussian, 39 | StaticDecay(0.4), 40 | StaticDecay(50)), 41 | 'djibouti': ('djibouti', 4, 5000, 1000, 200, gaussian, 42 | StaticDecay(0.2), 43 | StaticDecay(10))} 44 | 45 | plt.figure() 46 | 47 | 48 | def plot_map(cities, neurons, iteration): 49 | """ 50 | Generates the required map of cities and neurons at a given moment and 51 | stores the result in a png image. The map contains all the cities 52 | represented as red dots and all the neurons as green, crossed by a line 53 | dots. The method plots the iteration in which the snapshot was taken. 54 | :param cities: the cities to be plotted, passed as a list of (x, y) 55 | coordinates 56 | :param neurons: the cities to be plotted, passed as a list of (x, y) 57 | coordinates 58 | :param iteration: the iterations when the snapshot is taken 59 | :return: returns nothing 60 | """ 61 | plt.scatter(*zip(*cities), color='red', s=3) 62 | plt.scatter(*zip(*neurons), color='green', s=2) 63 | 64 | plt.plot(*zip(*(neurons+[neurons[0]])), color='darkgreen') 65 | 66 | # Invert x axis to match representation at 67 | # http://www.math.uwaterloo.ca/tsp/world/countries.html 68 | plt.gca().invert_xaxis() 69 | plt.gca().set_aspect('equal', adjustable='datalim') 70 | 71 | plt.title('Iteration #{:06d}'.format(iteration)) 72 | plt.axis('off') 73 | plt.savefig('results/{}.png'.format(iteration)) 74 | plt.clf() 75 | 76 | 77 | def read_data(filename): 78 | """ 79 | Reads and parses data from a txt file with a map data. The format that the 80 | function expects is the one followed in the uwaterloo TSP web archive 81 | (math.uwaterloo.ca/tsp/world/countries.html), ignoring the first 82 | description lines that have to be manually removed. The method searches for 83 | the filename in the assets folder. 84 | :param filename: the path to the file to be parsed 85 | :return: the cities as a list of (x, y) coordinates 86 | """ 87 | cities = [] 88 | 89 | path = 'assets/{}.txt'.format(filename) 90 | with open(path, 'r') as f: 91 | for line in f: 92 | city = list(map(float, line.split()[1:])) 93 | cities.append((city[1], city[0])) 94 | 95 | return cities 96 | 97 | 98 | def get_input(): 99 | """ 100 | Gets the input from the user line or launches the default values 101 | :return data_set: list of cities as (x,y) coordinates 102 | :return n_neurons: number of neurons per city in the data_set 103 | :return iterations: number of iterations to be executed 104 | :return learning_rate: learning rate to be used 105 | :return radius: radius of neurons to be used 106 | """ 107 | data_sets = {'w': 'western_sahara', 'q': 'qatar', 'u': 'uruguay', 108 | 'd': 'djibouti'} 109 | 110 | set_id = input('Data set [w/q/u/d]: ') or 'w' 111 | data_set = data_sets[set_id] 112 | 113 | if not os.path.isfile('assets/{}.txt'.format(data_set)): 114 | exit("Did not find this data set file!") 115 | 116 | use_defaults = input('Do you want to use default parameters? (y/n) ') == 'y' 117 | 118 | if use_defaults: 119 | decay = input('What kind of decay? [s/l/e]') or 'e' 120 | if decay == 'e': 121 | return DEFAULTS_EXP[data_set] 122 | if decay == 'l': 123 | return DEFAULTS_LIN[data_set] 124 | if decay == 's': 125 | return DEFAULT_STA[data_set] 126 | # Comprehensive input 127 | n_neurons = int(input('How many neurons per city? (8)') or 8) 128 | iterations = int(input('How many iterations (500)?') or 500) 129 | learning_rate = get_input_decay('learning rate') 130 | radius = get_input_decay('radius') 131 | k = int(input('After how many iterations print current TSP distance? (1000)') or 1000) 132 | plot_k = int(input('After how many iterations generate plot? (200)') or 200) 133 | 134 | neighborhood = input('Choose neighborhood function: [g/b]') or 'b' 135 | if neighborhood == 'b': 136 | neighborhood = bubble 137 | elif neighborhood == 'g': 138 | neighborhood = gaussian 139 | else: 140 | exit('Not a valid neighborhood!') 141 | 142 | return data_set, n_neurons, iterations, k, plot_k, neighborhood, learning_rate, radius 143 | 144 | def get_input_decay(name): 145 | """ 146 | Generates the appropriate decay function for a given variable. The decays 147 | that can be generated are static (no decay over time), linear and 148 | exponential. 149 | :param name: name of the variable that will be generated 150 | :return: decay function for the variable with appropriate parameters 151 | """ 152 | decay = input('What kind of decay for {}? [s/l/e]'.format(name)) or 'e' 153 | if decay == 's': 154 | value = float(input('Static value: ')) 155 | return StaticDecay(value) 156 | if decay == 'l': 157 | value = float(input('Start value: ')) 158 | rate = float(input('Rate:')) 159 | return LinearDecay(value, rate) 160 | if decay == 'e': 161 | value = float(input('Start value: ')) 162 | rate = float(input('Rate:')) 163 | return ExponentialDecay(value, rate) 164 | exit('Not a valid option!') 165 | -------------------------------------------------------------------------------- /src/neighborhood.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def gaussian(d, sigma): 5 | p = sigma**2 6 | if p == 0: 7 | return 0 8 | return math.exp(-d**2/(2*p)) 9 | 10 | 11 | def bubble(d, sigma): 12 | if d <= sigma: 13 | return 1 14 | return 0 15 | -------------------------------------------------------------------------------- /src/som.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from helper import read_data, plot_map, get_input 4 | from distances import euclidean_distance_2d, euclidean_distance_1d_circular 5 | 6 | import random 7 | from operator import itemgetter 8 | from functools import partial 9 | 10 | 11 | def main(): 12 | data_set, n_neurons, iterations, k, plot_k, neighborhood, learning_rate\ 13 | , radius = get_input() 14 | cities = read_data(data_set) 15 | scaling, cities = normalize(cities) 16 | 17 | neuron_count = len(cities) * n_neurons 18 | neurons = init_neurons(neuron_count) 19 | 20 | # TODO maybe distance param? 21 | som(neurons, cities, iterations, k, plot_k, neighborhood, learning_rate, radius, 22 | scaling) 23 | 24 | 25 | def init_neurons(count): 26 | """ 27 | Initialize the weights of the neurons 28 | :param count: number of neurons to initialize 29 | :return: list of neurons as weight vectors (x,y) 30 | """ 31 | return [[random.uniform(0.0, 1.0), 32 | random.uniform(0.0, 1.0)] for i in range(count)] 33 | 34 | 35 | def som(neurons, cities, iterations, k, plot_k, neighborhood, learning_rate, 36 | radius, scaling): 37 | """ 38 | Main SOM loop to be executed. 39 | :param neurons: list of neurons as weight vectors (x,y) 40 | :param cities: list of cities as (x,y) coordinates 41 | :param iterations: number of iterations to perform 42 | :param k: lapse of iterations between printing execution data 43 | :param plot_k: lapse of iterations between saving the map images 44 | :param neighborhood: type of neighborhood to use in the execution 45 | :param learning_rate: learning rate to be used 46 | :param radius: radius of neurons to be used 47 | :param scaling: scale used when normalizing the data 48 | :return: returns nothing 49 | """ 50 | for i in range(0, iterations+1): 51 | if i % k == 0: 52 | print('#', i, '\t\tTSP-distance: ', 53 | calculate_tsp(cities, neurons)*scaling) 54 | if i % plot_k == 0: 55 | plot_map(cities, neurons, i) 56 | if i == iterations: 57 | break 58 | som_iteration(neurons, cities, neighborhood, learning_rate, radius) 59 | 60 | 61 | def som_iteration(neurons, cities, neighborhood, learning_rate, radius): 62 | """ 63 | Performs a single SOM iteration with a given set of parameters 64 | :param neurons: list of neurons as weight vectors (x,y) 65 | :param cities: list of cities as (x,y) coordinates 66 | :param neighborhood: type of neighborhood to use in the execution 67 | :param learning_rate: learning rate to be used 68 | :param radius: radius of neurons to be used 69 | :return: returns nothing 70 | """ 71 | # Pick a random city 72 | city = cities[random.randint(0, len(cities)-1)] 73 | # Choose the winner neuron 74 | winner_index, winner = compute_winner(city, neurons, euclidean_distance_2d) 75 | distance = partial(euclidean_distance_1d_circular, len(neurons)) 76 | 77 | # Update the weights of the neuron and its neighbourhood 78 | for neuron_index, neuron in enumerate(neurons): 79 | d = distance(neuron_index, winner_index) 80 | nf = neighborhood(d, radius.value) 81 | neuron[0] += learning_rate.value * nf * (city[0] - neuron[0]) 82 | neuron[1] += learning_rate.value * nf * (city[1] - neuron[1]) 83 | 84 | learning_rate.decay() 85 | radius.decay() 86 | 87 | 88 | def compute_winner(city, neurons, distance): 89 | """ 90 | Computes the closest neuron to a given city with a given distance 91 | :param city: coordinates (x,y) of the city to be associated to the winner 92 | :param neurons: list of neurons as weight vectors (x,y) 93 | :param distance: type of distance to be used for the computations 94 | :return winner_index: index of the chosen neuron in the neuron list 95 | :return winner: closest neuron to city 96 | """ 97 | return min([(i, distance(city, neuron)) for i, 98 | neuron in enumerate(neurons)], key=itemgetter(1)) 99 | 100 | 101 | def normalize(cities): 102 | """ 103 | Normalize list of city coordinates 104 | :param cities: list of tuples, containing x and y coordinate 105 | :return: normalized list of city coordinates 106 | """ 107 | max_x = max(cities,key=itemgetter(0))[0] 108 | max_y = max(cities,key=itemgetter(1))[1] 109 | m = max(max_x, max_y) 110 | 111 | return m, [(x/m, y/m) for (x, y) in cities] 112 | 113 | 114 | def calculate_tsp(cities, neurons): 115 | """ 116 | Computes the Travelling Salesman distance to travel all the cities using a 117 | list of neurons 118 | :param cities: list of tuples, containing x and y coordinate 119 | :param neurons: list of neurons as weight vectors (x,y) 120 | :return: the distance to travel through cities using neurons 121 | """ 122 | city_neurons = {} 123 | for city_idx, city in enumerate(cities): 124 | # find nearest neuron 125 | idx, _ = compute_winner(city, neurons, euclidean_distance_2d) 126 | if idx not in city_neurons: 127 | city_neurons[idx] = [city] 128 | else: 129 | city_neurons[idx].append(city) 130 | 131 | # order cities according to neuron order 132 | tsp_order = [] 133 | for neuron_idx in range(len(neurons)): 134 | if neuron_idx in city_neurons: 135 | tsp_order += city_neurons[neuron_idx] 136 | 137 | # calculate tsp distance for tsp_order 138 | tsp_distance = euclidean_distance_2d(tsp_order[0], tsp_order[-1]) 139 | for idx in range(len(tsp_order)-1): 140 | tsp_distance += euclidean_distance_2d(tsp_order[idx], 141 | tsp_order[idx + 1]) 142 | 143 | return tsp_distance 144 | 145 | 146 | if __name__ == '__main__': main() 147 | --------------------------------------------------------------------------------