├── .github └── workflows │ └── superlinter.yml ├── .gitignore ├── 2021-22 ├── 6-friends.ipynb ├── bricks.ipynb ├── connect-four.ipynb ├── contrib │ └── sudoku-leonardo.ipynb ├── links │ └── suggested-readings.md ├── multiple-knapsack.ipynb ├── one-max.ipynb ├── project │ └── hanabi │ │ ├── GameData.py │ │ ├── LICENSE │ │ ├── README.md │ │ ├── client.py │ │ ├── constants.py │ │ ├── game.py │ │ └── server.py ├── pyproject.toml ├── rastrigin.ipynb ├── set-covering.ipynb ├── sudoku.ipynb ├── table-top.ipynb ├── tic-tac-toe.ipynb ├── tic-tac-toe_rl.py └── tsp.ipynb ├── 2022-23 ├── 4-friends.ipynb ├── 8-puzzle.ipynb ├── README.md ├── diversity.ipynb ├── gx_utils.py ├── lab1_set-covering.ipynb ├── lab2_set-covering+ea.ipynb ├── lab3_nim-not-working.ipynb ├── lab3_nim.ipynb ├── min-sum.ipynb ├── one-max.ipynb ├── poetry.lock ├── pyproject.toml ├── quarto │ ├── main.py │ ├── quarto │ │ ├── __init__.py │ │ ├── objects.py │ │ └── objects2.py │ └── x.ipynb ├── spare.ipynb ├── test-function.ipynb ├── test-problems.ipynb └── tic-tac-toe.ipynb ├── 2023-24 ├── 4-friends.ipynb ├── Halloween.ipynb ├── Lab1.txt ├── contrib │ ├── A_star_stochastic.ipynb │ ├── GAs_visualization_tool │ │ ├── README.md │ │ ├── himmelblaus.png │ │ ├── pop_evolution.gif │ │ └── population_evolution.ipynb │ ├── Halloween.ipynb │ ├── Prooving the non-solvability of the friends’ problem.pdf │ ├── README.md │ ├── Search_Problems_Classes.py │ ├── Set_Covering.ipynb │ └── pizza_pub │ │ ├── README.md │ │ ├── __init__.py │ │ ├── main.py │ │ ├── state.py │ │ ├── student_group.py │ │ └── test │ │ ├── test_state.py │ │ └── test_student_group.py ├── gx_utils.py ├── lab10-gx.ipynb ├── lab10.ipynb ├── lab9.ipynb ├── lab9_lib.py ├── poetry.lock ├── pull-request.txt ├── pyproject.toml ├── quixo │ ├── game.py │ ├── main.py │ └── requirements.txt ├── rastrigin.ipynb ├── set-covering_ea.ipynb ├── set-covering_path-search.ipynb └── set-covering_single-state.ipynb ├── 2024-25 ├── 1-max.ipynb ├── 6-friends.ipynb ├── 8-puzzle.ipynb ├── cities │ ├── china.csv │ ├── italy.csv │ ├── russia.csv │ ├── us.csv │ └── vanuatu.csv ├── contrib │ └── poetry_installation_guide │ │ ├── README.md │ │ └── imgs │ │ ├── p1.png │ │ ├── p2.png │ │ ├── p3.png │ │ ├── p4.png │ │ ├── p5.png │ │ └── p6.png ├── golang-demos │ ├── .gitignore │ └── shortest-path │ │ ├── go.mod │ │ ├── go.sum │ │ ├── graph │ │ └── graph.go │ │ ├── main.go │ │ ├── randy │ │ └── rand.go │ │ ├── solvers │ │ ├── branch-n-bound.go │ │ ├── greedy.go │ │ ├── queue.go │ │ ├── tree-search.go │ │ └── util.go │ │ └── viz │ │ ├── colors.go │ │ └── visual.go ├── gx_utils.py ├── min-sum.ipynb ├── multiple-knapsack.ipynb ├── n-puzzle.ipynb ├── poetry.lock ├── project-work │ ├── d3584.py │ ├── data │ │ ├── problem_0.npz │ │ ├── problem_1.npz │ │ ├── problem_2.npz │ │ ├── problem_3.npz │ │ ├── problem_4.npz │ │ ├── problem_5.npz │ │ ├── problem_6.npz │ │ ├── problem_7.npz │ │ └── problem_8.npz │ └── src │ │ └── README.md ├── pyproject.toml ├── rl-1.ipynb ├── rl-2.ipynb ├── set-cover 1.1.ipynb ├── set-cover 1.2.ipynb ├── set-cover.ipynb ├── set-cover_ea.ipynb ├── set-cover_gs1.ipynb ├── set-covering_showdown.csv ├── set-covering_showdown.ipynb ├── shortest-path.ipynb ├── symreg │ ├── d3584.py │ ├── demo-gxgp.ipynb │ ├── gxgp │ │ ├── __init__.py │ │ ├── draw.py │ │ ├── gp_common.py │ │ ├── gp_dag.py │ │ ├── gp_tree.py │ │ ├── node.py │ │ ├── random.py │ │ └── utils.py │ ├── symreg.ipynb │ └── symreg_user.ipynb ├── table-top.ipynb ├── takeover.ipynb └── tsp.ipynb ├── LICENSE.md └── README.md /.github/workflows/superlinter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################# 3 | ################################# 4 | ## Super Linter GitHub Actions ## 5 | ################################# 6 | ################################# 7 | name: Lint Code Base 8 | 9 | # 10 | # Documentation: 11 | # https://help.github.com/en/articles/workflow-syntax-for-github-actions 12 | # 13 | 14 | ############################# 15 | # Start the job on all push # 16 | ############################# 17 | on: 18 | push: 19 | branches-ignore: [master, main] 20 | # Remove the line above to run when pushing to master 21 | pull_request: 22 | branches: [master, main] 23 | 24 | ############### 25 | # Set the Job # 26 | ############### 27 | jobs: 28 | build: 29 | # Name the Job 30 | name: Lint Code Base 31 | # Set the agent to run on 32 | runs-on: ubuntu-latest 33 | 34 | ################## 35 | # Load all steps # 36 | ################## 37 | steps: 38 | ########################## 39 | # Checkout the code base # 40 | ########################## 41 | - name: Checkout Code 42 | uses: actions/checkout@v2 43 | with: 44 | # Full git history is needed to get a proper list of changed files within `super-linter` 45 | fetch-depth: 0 46 | 47 | ################################ 48 | # Run Linter against code base # 49 | ################################ 50 | - name: Lint Code Base 51 | uses: github/super-linter@v4 52 | env: 53 | VALIDATE_ALL_CODEBASE: false 54 | DEFAULT_BRANCH: master 55 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | 140 | # GX Files 141 | .DS_Store 142 | .idea 143 | .vscode 144 | -------------------------------------------------------------------------------- /2021-22/connect-four.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2021 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see 'LICENCE.md' for details." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# Connect 4" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "from collections import Counter\n", 26 | "import numpy as np" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "NUM_COLUMNS = 7\n", 36 | "COLUMN_HEIGHT = 6\n", 37 | "FOUR = 4\n", 38 | "\n", 39 | "# Board can be initiatilized with `board = np.zeros((NUM_COLUMNS, COLUMN_HEIGHT), dtype=np.byte)`\n", 40 | "# Notez Bien: Connect 4 \"columns\" are actually NumPy \"rows\"" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "## Basic Functions" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 3, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "def valid_moves(board):\n", 57 | " \"\"\"Returns columns where a disc may be played\"\"\"\n", 58 | " return [n for n in range(NUM_COLUMNS) if board[n, COLUMN_HEIGHT - 1] == 0]\n", 59 | "\n", 60 | "\n", 61 | "def play(board, column, player):\n", 62 | " \"\"\"Updates `board` as `player` drops a disc in `column`\"\"\"\n", 63 | " (index,) = next((i for i, v in np.ndenumerate(board[column]) if v == 0))\n", 64 | " board[column, index] = player\n", 65 | "\n", 66 | "\n", 67 | "def take_back(board, column):\n", 68 | " \"\"\"Updates `board` removing top disc from `column`\"\"\"\n", 69 | " (index,) = [i for i, v in np.ndenumerate(board[column]) if v != 0][-1]\n", 70 | " board[column, index] = 0\n", 71 | "\n", 72 | "\n", 73 | "def four_in_a_row(board, player):\n", 74 | " \"\"\"Checks if `player` has a 4-piece line\"\"\"\n", 75 | " return (\n", 76 | " any(\n", 77 | " all(board[c, r] == player)\n", 78 | " for c in range(NUM_COLUMNS)\n", 79 | " for r in (list(range(n, n + FOUR)) for n in range(COLUMN_HEIGHT - FOUR + 1))\n", 80 | " )\n", 81 | " or any(\n", 82 | " all(board[c, r] == player)\n", 83 | " for r in range(COLUMN_HEIGHT)\n", 84 | " for c in (list(range(n, n + FOUR)) for n in range(NUM_COLUMNS - FOUR + 1))\n", 85 | " )\n", 86 | " or any(\n", 87 | " np.all(board[diag] == player)\n", 88 | " for diag in (\n", 89 | " (range(ro, ro + FOUR), range(co, co + FOUR))\n", 90 | " for ro in range(0, NUM_COLUMNS - FOUR + 1)\n", 91 | " for co in range(0, COLUMN_HEIGHT - FOUR + 1)\n", 92 | " )\n", 93 | " )\n", 94 | " or any(\n", 95 | " np.all(board[diag] == player)\n", 96 | " for diag in (\n", 97 | " (range(ro, ro + FOUR), range(co + FOUR - 1, co - 1, -1))\n", 98 | " for ro in range(0, NUM_COLUMNS - FOUR + 1)\n", 99 | " for co in range(0, COLUMN_HEIGHT - FOUR + 1)\n", 100 | " )\n", 101 | " )\n", 102 | " )" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "## Montecarlo Evaluation" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 4, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "def _mc(board, player):\n", 119 | " p = -player\n", 120 | " while valid_moves(board):\n", 121 | " p = -p\n", 122 | " c = np.random.choice(valid_moves(board))\n", 123 | " play(board, c, p)\n", 124 | " if four_in_a_row(board, p):\n", 125 | " return p\n", 126 | " return 0\n", 127 | "\n", 128 | "\n", 129 | "def montecarlo(board, player):\n", 130 | " montecarlo_samples = 100\n", 131 | " cnt = Counter(_mc(np.copy(board), player) for _ in range(montecarlo_samples))\n", 132 | " return (cnt[1] - cnt[-1]) / montecarlo_samples\n", 133 | "\n", 134 | "\n", 135 | "def eval_board(board, player):\n", 136 | " if four_in_a_row(board, 1):\n", 137 | " # Alice won\n", 138 | " return 1\n", 139 | " elif four_in_a_row(board, -1):\n", 140 | " # Bob won\n", 141 | " return -1\n", 142 | " else:\n", 143 | " # Not terminal, let's simulate...\n", 144 | " return montecarlo(board, player)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "## Example" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 9, 157 | "metadata": {}, 158 | "outputs": [ 159 | { 160 | "name": "stdout", 161 | "output_type": "stream", 162 | "text": [ 163 | "[[-1 -1 0 0 0 0]\n", 164 | " [ 0 0 0 0 0 0]\n", 165 | " [ 0 0 0 0 0 0]\n", 166 | " [ 1 0 0 0 0 0]\n", 167 | " [ 1 0 0 0 0 0]\n", 168 | " [ 1 0 0 0 0 0]\n", 169 | " [ 0 0 0 0 0 0]]\n" 170 | ] 171 | }, 172 | { 173 | "data": { 174 | "text/plain": [ 175 | "0.78" 176 | ] 177 | }, 178 | "execution_count": 9, 179 | "metadata": {}, 180 | "output_type": "execute_result" 181 | } 182 | ], 183 | "source": [ 184 | "board = board = np.zeros((NUM_COLUMNS, COLUMN_HEIGHT), dtype=np.byte)\n", 185 | "play(board, 3, 1)\n", 186 | "play(board, 0, -1)\n", 187 | "play(board, 4, 1)\n", 188 | "play(board, 0, -1)\n", 189 | "play(board, 5, 1)\n", 190 | "print(board)\n", 191 | "eval_board(board, 1)" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": null, 197 | "metadata": {}, 198 | "outputs": [], 199 | "source": [] 200 | } 201 | ], 202 | "metadata": { 203 | "interpreter": { 204 | "hash": "371627151b0642f6c185c280fa16312776bda89bbb063ce0f2d8135c657194f4" 205 | }, 206 | "kernelspec": { 207 | "display_name": "Python 3.8.2 64-bit ('ci2021': conda)", 208 | "name": "python3" 209 | }, 210 | "language_info": { 211 | "codemirror_mode": { 212 | "name": "ipython", 213 | "version": 3 214 | }, 215 | "file_extension": ".py", 216 | "mimetype": "text/x-python", 217 | "name": "python", 218 | "nbconvert_exporter": "python", 219 | "pygments_lexer": "ipython3", 220 | "version": "3.8.2" 221 | }, 222 | "orig_nbformat": 4 223 | }, 224 | "nbformat": 4, 225 | "nbformat_minor": 2 226 | } 227 | -------------------------------------------------------------------------------- /2021-22/links/suggested-readings.md: -------------------------------------------------------------------------------- 1 | # SPARE SUGGESTED READINGS AND LINKS 2 | 3 | * Mark Halpern. *No Ghost in the Machine* (2020); https://theamericanscholar.org/no-ghost-in-the-machine/ 4 | * Gary Marcus. *The Next Decade in AI: Four Steps Towards Robust Artificial Intelligence* (2021); https://arxiv.org/abs/2002.06177 5 | -------------------------------------------------------------------------------- /2021-22/project/hanabi/README.md: -------------------------------------------------------------------------------- 1 | # Computational Intelligence 2021-2022 2 | 3 | Exam of computational intelligence 2021 - 2022. It requires teaching the client to play the game of Hanabi (rules can be found [here](https://www.spillehulen.dk/media/102616/hanabi-card-game-rules.pdf)). 4 | 5 | ## Server 6 | 7 | The server accepts passing objects provided in GameData.py back and forth to the clients. 8 | Each object has a ```serialize()``` and a ```deserialize(data: str)``` method that must be used to pass the data between server and client. 9 | 10 | Watch out! I'd suggest to keep everything in the same folder, since serialization looks dependent on the import path (thanks Paolo Rabino for letting me know). 11 | 12 | Server closes when no client is connected. 13 | 14 | To start the server: 15 | 16 | ```bash 17 | python server.py 18 | ``` 19 | 20 | Arguments: 21 | 22 | + minNumPlayers, __optional__: game does not start until a minimum number of player has been reached. Default = 2 23 | 24 | 25 | Commands for server: 26 | 27 | + exit: exit from the server 28 | 29 | ## Client 30 | 31 | To start the server: 32 | 33 | ```bash 34 | python client.py 35 | ``` 36 | 37 | Arguments: 38 | 39 | + IP: IP address of the server (for localhost: 127.0.0.1) 40 | + port: server TCP port (default: 1024) 41 | + PlayerName: the name of the player 42 | 43 | Commands for client: 44 | 45 | + exit: exit from the game 46 | + ready: set your status to ready (lobby only) 47 | + show: show cards 48 | + hint \ \: 49 | + type: 'color' or 'value' 50 | + destinatary: name of the person you want to ask the hint to 51 | + discard \: discard the card *num* (\[0-4]) from your hand 52 | -------------------------------------------------------------------------------- /2021-22/project/hanabi/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from sys import argv, stdout 4 | from threading import Thread 5 | import GameData 6 | import socket 7 | from constants import * 8 | import os 9 | 10 | 11 | if len(argv) < 4: 12 | print("You need the player name to start the game.") 13 | #exit(-1) 14 | playerName = "Test" # For debug 15 | ip = HOST 16 | port = PORT 17 | else: 18 | playerName = argv[3] 19 | ip = argv[1] 20 | port = int(argv[2]) 21 | 22 | run = True 23 | 24 | statuses = ["Lobby", "Game", "GameHint"] 25 | 26 | status = statuses[0] 27 | 28 | hintState = ("", "") 29 | 30 | def manageInput(): 31 | global run 32 | global status 33 | while run: 34 | command = input() 35 | # Choose data to send 36 | if command == "exit": 37 | run = False 38 | os._exit(0) 39 | elif command == "ready" and status == statuses[0]: 40 | s.send(GameData.ClientPlayerStartRequest(playerName).serialize()) 41 | elif command == "show" and status == statuses[1]: 42 | s.send(GameData.ClientGetGameStateRequest(playerName).serialize()) 43 | elif command.split(" ")[0] == "discard" and status == statuses[1]: 44 | try: 45 | cardStr = command.split(" ") 46 | cardOrder = int(cardStr[1]) 47 | s.send(GameData.ClientPlayerDiscardCardRequest(playerName, cardOrder).serialize()) 48 | except: 49 | print("Maybe you wanted to type 'discard '?") 50 | continue 51 | elif command.split(" ")[0] == "play" and status == statuses[1]: 52 | try: 53 | cardStr = command.split(" ") 54 | cardOrder = int(cardStr[1]) 55 | s.send(GameData.ClientPlayerPlayCardRequest(playerName, cardOrder).serialize()) 56 | except: 57 | print("Maybe you wanted to type 'play '?") 58 | continue 59 | elif command.split(" ")[0] == "hint" and status == statuses[1]: 60 | try: 61 | destination = command.split(" ")[2] 62 | t = command.split(" ")[1].lower() 63 | if t != "colour" and t != "color" and t != "value": 64 | print("Error: type can be 'color' or 'value'") 65 | continue 66 | value = command.split(" ")[3].lower() 67 | if t == "value": 68 | value = int(value) 69 | if int(value) > 5 or int(value) < 1: 70 | print("Error: card values can range from 1 to 5") 71 | continue 72 | else: 73 | if value not in ["green", "red", "blue", "yellow", "white"]: 74 | print("Error: card color can only be green, red, blue, yellow or white") 75 | continue 76 | s.send(GameData.ClientHintData(playerName, destination, t, value).serialize()) 77 | except: 78 | print("Maybe you wanted to type 'hint '?") 79 | continue 80 | elif command == "": 81 | print("[" + playerName + " - " + status + "]: ", end="") 82 | else: 83 | print("Unknown command: " + command) 84 | continue 85 | stdout.flush() 86 | 87 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 88 | request = GameData.ClientPlayerAddData(playerName) 89 | s.connect((HOST, PORT)) 90 | s.send(request.serialize()) 91 | data = s.recv(DATASIZE) 92 | data = GameData.GameData.deserialize(data) 93 | if type(data) is GameData.ServerPlayerConnectionOk: 94 | print("Connection accepted by the server. Welcome " + playerName) 95 | print("[" + playerName + " - " + status + "]: ", end="") 96 | Thread(target=manageInput).start() 97 | while run: 98 | dataOk = False 99 | data = s.recv(DATASIZE) 100 | if not data: 101 | continue 102 | data = GameData.GameData.deserialize(data) 103 | if type(data) is GameData.ServerPlayerStartRequestAccepted: 104 | dataOk = True 105 | print("Ready: " + str(data.acceptedStartRequests) + "/" + str(data.connectedPlayers) + " players") 106 | data = s.recv(DATASIZE) 107 | data = GameData.GameData.deserialize(data) 108 | if type(data) is GameData.ServerStartGameData: 109 | dataOk = True 110 | print("Game start!") 111 | s.send(GameData.ClientPlayerReadyData(playerName).serialize()) 112 | status = statuses[1] 113 | if type(data) is GameData.ServerGameStateData: 114 | dataOk = True 115 | print("Current player: " + data.currentPlayer) 116 | print("Player hands: ") 117 | for p in data.players: 118 | print(p.toClientString()) 119 | print("Cards in your hand: " + str(data.handSize)) 120 | print("Table cards: ") 121 | for pos in data.tableCards: 122 | print(pos + ": [ ") 123 | for c in data.tableCards[pos]: 124 | print(c.toClientString() + " ") 125 | print("]") 126 | print("Discard pile: ") 127 | for c in data.discardPile: 128 | print("\t" + c.toClientString()) 129 | print("Note tokens used: " + str(data.usedNoteTokens) + "/8") 130 | print("Storm tokens used: " + str(data.usedStormTokens) + "/3") 131 | if type(data) is GameData.ServerActionInvalid: 132 | dataOk = True 133 | print("Invalid action performed. Reason:") 134 | print(data.message) 135 | if type(data) is GameData.ServerActionValid: 136 | dataOk = True 137 | print("Action valid!") 138 | print("Current player: " + data.player) 139 | if type(data) is GameData.ServerPlayerMoveOk: 140 | dataOk = True 141 | print("Nice move!") 142 | print("Current player: " + data.player) 143 | if type(data) is GameData.ServerPlayerThunderStrike: 144 | dataOk = True 145 | print("OH NO! The Gods are unhappy with you!") 146 | if type(data) is GameData.ServerHintData: 147 | dataOk = True 148 | print("Hint type: " + data.type) 149 | print("Player " + data.destination + " cards with value " + str(data.value) + " are:") 150 | for i in data.positions: 151 | print("\t" + str(i)) 152 | if type(data) is GameData.ServerInvalidDataReceived: 153 | dataOk = True 154 | print(data.data) 155 | if type(data) is GameData.ServerGameOver: 156 | dataOk = True 157 | print(data.message) 158 | print(data.score) 159 | print(data.scoreMessage) 160 | stdout.flush() 161 | #run = False 162 | print("Ready for a new game!") 163 | if not dataOk: 164 | print("Unknown or unimplemented data type: " + str(type(data))) 165 | print("[" + playerName + " - " + status + "]: ", end="") 166 | stdout.flush() -------------------------------------------------------------------------------- /2021-22/project/hanabi/constants.py: -------------------------------------------------------------------------------- 1 | # Program constants / server constants 2 | HOST = "127.0.0.1" 3 | PORT = 1024 # 0x4A7AB1 could have been a better port, but networkers did not allow us to have it 4 | DATASIZE = int(10240 / 4) -------------------------------------------------------------------------------- /2021-22/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 120 3 | include = '\.ipynb' 4 | -------------------------------------------------------------------------------- /2021-22/tic-tac-toe.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2021 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see 'LICENCE.md' for details." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "from itertools import permutations\n", 19 | "import numpy as np" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "TICTACTOE_MAP = np.array([[1, 6, 5], [8, 4, 0], [3, 2, 7]])\n", 29 | "\n", 30 | "\n", 31 | "def display(x, o):\n", 32 | " for r in range(3):\n", 33 | " for c in range(3):\n", 34 | " if TICTACTOE_MAP[r, c] in x:\n", 35 | " print(\"X\", end=\" \")\n", 36 | " elif TICTACTOE_MAP[r, c] in o:\n", 37 | " print(\"O\", end=\" \")\n", 38 | " else:\n", 39 | " print(\".\", end=\" \")\n", 40 | " print()" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 1, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "def won(cells):\n", 50 | " return any(sum(h) == 12 for h in permutations(cells, 3))\n", 51 | "\n", 52 | "\n", 53 | "def eval_terminal(x, o):\n", 54 | " if won(x):\n", 55 | " return 1\n", 56 | " elif won(o):\n", 57 | " return -1\n", 58 | " else:\n", 59 | " return 0" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 4, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "def minmax(board):\n", 69 | " val = eval_terminal(*board)\n", 70 | " possible = list(set(range(9)) - board[0] - board[1])\n", 71 | " if val != 0 or not possible:\n", 72 | " return None, val\n", 73 | " evaluations = list()\n", 74 | " for ply in possible:\n", 75 | " _, val = minmax((board[1], board[0] | {ply}))\n", 76 | " evaluations.append((ply, -val))\n", 77 | " return max(evaluations, key=lambda k: k[1])" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 5, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "name": "stdout", 87 | "output_type": "stream", 88 | "text": [ 89 | "X . O \n", 90 | "O . . \n", 91 | "X . . \n", 92 | "\n", 93 | "X . O \n", 94 | "O . . \n", 95 | "X . X \n" 96 | ] 97 | } 98 | ], 99 | "source": [ 100 | "p = ({1, 3}, {5, 8})\n", 101 | "display(*p)\n", 102 | "print()\n", 103 | "best_ply, eval = minmax(p)\n", 104 | "display(p[0] | {best_ply}, p[1])" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [] 113 | } 114 | ], 115 | "metadata": { 116 | "interpreter": { 117 | "hash": "81583c29eb1de1e2763f7f94748c11ed9fb4fb1823d30e61923417a9f34f86b1" 118 | }, 119 | "kernelspec": { 120 | "display_name": "Python 3.9.7 64-bit ('ci2021': conda)", 121 | "name": "python3" 122 | }, 123 | "language_info": { 124 | "codemirror_mode": { 125 | "name": "ipython", 126 | "version": 3 127 | }, 128 | "file_extension": ".py", 129 | "mimetype": "text/x-python", 130 | "name": "python", 131 | "nbconvert_exporter": "python", 132 | "pygments_lexer": "ipython3", 133 | "version": "3.9.7" 134 | }, 135 | "orig_nbformat": 4 136 | }, 137 | "nbformat": 4, 138 | "nbformat_minor": 2 139 | } 140 | -------------------------------------------------------------------------------- /2021-22/tic-tac-toe_rl.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2021 Giovanni Squillero 2 | # Free for personal or classroom use; see 'LICENCE.md' for details. 3 | # https://github.com/squillero/computational-intelligence 4 | 5 | import argparse 6 | import logging 7 | from itertools import permutations, product 8 | import numpy as np 9 | import coloredlogs # I like my log to be colorful 10 | from tqdm import tqdm # Coolest progress bar 11 | 12 | TICTACTOE_MAP = np.array([[1, 6, 5], [8, 4, 0], [3, 2, 7]]) 13 | 14 | 15 | def display(state, legend=None, *, coordinates=False): 16 | if not legend: 17 | legend = list() 18 | legend += [''] * 3 19 | x, o = state 20 | for r, c in product(range(3), repeat=2): 21 | if TICTACTOE_MAP[r, c] in x: 22 | print("X", end=" ") 23 | elif TICTACTOE_MAP[r, c] in o: 24 | print("O", end=" ") 25 | elif coordinates: 26 | print(f"{TICTACTOE_MAP[r, c]}", end=" ") 27 | else: 28 | print(".", end=" ") 29 | if c == 2: 30 | print(f" {legend[r]}") 31 | 32 | 33 | def winning_position(cells): 34 | return any(sum(h) == 12 for h in permutations(cells, 3)) 35 | 36 | 37 | def eval_static(state) -> int: 38 | """Statically evaluate a board: 1 if agent won, -1 if it lost""" 39 | if winning_position(state[0]): 40 | return 1 41 | elif winning_position(state[1]): 42 | return -1 43 | else: 44 | return 0 45 | 46 | 47 | def next_state(state, action: int): 48 | """Returns the next state when agent does `action` in `state`""" 49 | me, opponent = state 50 | assert len(me) <= len(opponent) 51 | return frozenset(set(me) | {action}), opponent 52 | 53 | 54 | def valid_actions(state, agent: int = 0): 55 | """Returns a list of valid actions""" 56 | if len(state[agent]) > len(state[1 - agent]): 57 | return list() 58 | else: 59 | return list(set(range(9)) - state[0] - state[1]) 60 | 61 | 62 | def best_action(Q: dict, state): 63 | if not valid_actions(state): 64 | return (None, eval_static(state)) 65 | else: 66 | return max(((a, Q[(state, a)]) for a in valid_actions(state)), key=lambda x: x[1]) 67 | 68 | 69 | def describe_policy(Q, V): 70 | non_zero = [q for q in Q.items() if q[1] != 0] 71 | learned = [q for q in Q.items() if q[1] != 0 and q[1] != 1 and q[1] != -1] 72 | print(f"Found {len(non_zero):,} non zero s/a over {len(Q):,}; {len(learned):,} learned.") 73 | non_zero = [v for v in V.items() if v[1] != 0] 74 | learned = [v for v in V.items() if v[1] != 0 and v[1] != 1 and v[1] != -1] 75 | print(f"Found {len(non_zero):,} non zero values over {len(V):,}; {len(learned):,} learned.") 76 | 77 | 78 | def main(train_epochs): 79 | states = set() 80 | states |= set((frozenset(x), frozenset(y)) for n in range(5) for x in permutations(range(9), n) 81 | for y in permutations(set(range(9)) - set(x), n)) 82 | states |= set((frozenset(x), frozenset(y)) for n in range(5) 83 | for x in permutations(range(9), n + 1) 84 | for y in permutations(set(range(9)) - set(x), n)) 85 | states |= set((frozenset(x), frozenset(y)) for n in range(5) for x in permutations(range(9), n) 86 | for y in permutations(set(range(9)) - set(x), n + 1)) 87 | 88 | states_sorted = sorted(states, key=lambda s: len(s[0]) + len(s[1])) 89 | final_states = {s for s in states_sorted if len(s[0]) + len(s[1]) == 9 or eval_static(s) != 0} 90 | V_table = {s: eval_static(s) for s in states_sorted} 91 | Q_table = {(s, a): eval_static(next_state(s, a)) for s in states_sorted 92 | for a in valid_actions(s)} 93 | logging.info(f"Found {len(states):,} states, {len(final_states):,} marked as final") 94 | logging.info(f"V-table contains {len(V_table):,} state values") 95 | logging.info(f"Q-table contains {len(Q_table):,} state-action pairs (utility values)") 96 | 97 | # Your code here 98 | 99 | 100 | if __name__ == '__main__': 101 | logging.basicConfig(format='[%(asctime)s] %(levelname)s: %(message)s', datefmt='%H:%M:%S') 102 | logging.getLogger().setLevel(level=logging.INFO) 103 | 104 | parser = argparse.ArgumentParser() 105 | parser.add_argument('-v', '--verbose', action='count', default=0, help='increase log verbosity') 106 | parser.add_argument('-d', 107 | '--debug', 108 | action='store_const', 109 | dest='verbose', 110 | const=2, 111 | help='log debug messages (same as -vv)') 112 | parser.add_argument('-t', 113 | '--train', 114 | type=int, 115 | metavar='EPOCH', 116 | action='store', 117 | dest='train_epochs', 118 | help='Set random seed (default: 1_000)', 119 | default=1_000) 120 | args = parser.parse_args() 121 | 122 | if args.verbose == 0: 123 | level = 'WARNING' 124 | elif args.verbose == 1: 125 | level = 'INFO' 126 | elif args.verbose == 2: 127 | level = 'DEBUG' 128 | coloredlogs.install(level=level, 129 | fmt='[%(asctime)s] %(levelname)s: %(message)s', 130 | datefmt='%H:%M:%S') 131 | 132 | main(train_epochs=args.train_epochs) -------------------------------------------------------------------------------- /2022-23/README.md: -------------------------------------------------------------------------------- 1 | # Notes for A.A. 2022-23 2 | 3 | * Use [Poetry](https://python-poetry.org/) for dependency management (run `poetry install` to recreate an environment with the versions specified in `poetry.lock`). 4 | * A working [Graphviz](https://graphviz.org/) may be needed to use the enhanced graph layouts in [Networkx](https://networkx.org/). 5 | -------------------------------------------------------------------------------- /2022-23/gx_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2022 Giovanni Squillero 2 | # https://github.com/squillero/computational-intelligence 3 | # Free for personal or classroom use; see 'LICENSE.md' for details. 4 | 5 | import heapq 6 | from collections import Counter 7 | 8 | 9 | class PriorityQueue: 10 | """A basic Priority Queue with simple performance optimizations""" 11 | 12 | def __init__(self): 13 | self._data_heap = list() 14 | self._data_set = set() 15 | 16 | def __bool__(self): 17 | return bool(self._data_set) 18 | 19 | def __contains__(self, item): 20 | return item in self._data_set 21 | 22 | def push(self, item, p=None): 23 | assert item not in self, f"Duplicated element" 24 | if p is None: 25 | p = len(self._data_set) 26 | self._data_set.add(item) 27 | heapq.heappush(self._data_heap, (p, item)) 28 | 29 | def pop(self): 30 | p, item = heapq.heappop(self._data_heap) 31 | self._data_set.remove(item) 32 | return item 33 | 34 | 35 | class Multiset: 36 | """Multiset""" 37 | 38 | def __init__(self, init=None): 39 | self._data = Counter() 40 | if init: 41 | for item in init: 42 | self.add(item) 43 | 44 | def __contains__(self, item): 45 | return item in self._data and self._data[item] > 0 46 | 47 | def __getitem__(self, item): 48 | return self.count(item) 49 | 50 | def __iter__(self): 51 | return (i for i in sorted(self._data.keys()) for _ in range(self._data[i])) 52 | 53 | def __len__(self): 54 | return sum(self._data.values()) 55 | 56 | def __copy__(self): 57 | t = Multiset() 58 | t._data = self._data.copy() 59 | return t 60 | 61 | def __str__(self): 62 | return f"M{{{', '.join(repr(i) for i in self)}}}" 63 | 64 | def __repr__(self): 65 | return str(self) 66 | 67 | def __or__(self, other: "Multiset"): 68 | tmp = Multiset() 69 | for i in set(self._data.keys()) | set(other._data.keys()): 70 | tmp.add(i, cnt=max(self[i], other[i])) 71 | return tmp 72 | 73 | def __and__(self, other: "Multiset"): 74 | return self.intersection(other) 75 | 76 | def __add__(self, other: "Multiset"): 77 | return self.union(other) 78 | 79 | def __sub__(self, other: "Multiset"): 80 | tmp = Multiset(self) 81 | for i, n in other._data.items(): 82 | tmp.remove(i, cnt=n) 83 | return tmp 84 | 85 | def __eq__(self, other: "Multiset"): 86 | return list(self) == list(other) 87 | 88 | def __le__(self, other: "Multiset"): 89 | for i, n in self._data.items(): 90 | if other.count(i) < n: 91 | return False 92 | return True 93 | 94 | def __lt__(self, other: "Multiset"): 95 | return self <= other and not self == other 96 | 97 | def __ge__(self, other: "Multiset"): 98 | return other <= self 99 | 100 | def __gt__(self, other: "Multiset"): 101 | return other < self 102 | 103 | def add(self, item, *, cnt=1): 104 | assert cnt >= 0, "Can't add a negative number of elements" 105 | if cnt > 0: 106 | self._data[item] += cnt 107 | 108 | def remove(self, item, *, cnt=1): 109 | assert item in self, f"Item not in collection" 110 | self._data[item] -= cnt 111 | if self._data[item] <= 0: 112 | del self._data[item] 113 | 114 | def count(self, item): 115 | return self._data[item] if item in self._data else 0 116 | 117 | def union(self, other: "Multiset"): 118 | t = Multiset(self) 119 | for i in other._data.keys(): 120 | t.add(i, cnt=other[i]) 121 | return t 122 | 123 | def intersection(self, other: "Multiset"): 124 | t = Multiset() 125 | for i in self._data.keys(): 126 | t.add(i, cnt=min(self[i], other[i])) 127 | return t 128 | -------------------------------------------------------------------------------- /2022-23/lab2_set-covering+ea.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "Copyright **`(c)`** 2022 Giovanni Squillero `` \n", 12 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 13 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. \n" 14 | ] 15 | }, 16 | { 17 | "cell_type": "markdown", 18 | "metadata": { 19 | "pycharm": { 20 | "name": "#%%\n" 21 | } 22 | }, 23 | "source": [ 24 | "# Lab 2: Set Covering with EA\n", 25 | "\n", 26 | "Same as first lab, but using an Evolutionary Algorithm..." 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [] 33 | } 34 | ], 35 | "metadata": { 36 | "kernelspec": { 37 | "display_name": "Python 3.10.7 ('ci22-dPIXJ0_o-py3.10')", 38 | "language": "python", 39 | "name": "python3" 40 | }, 41 | "language_info": { 42 | "codemirror_mode": { 43 | "name": "ipython", 44 | "version": 3 45 | }, 46 | "file_extension": ".py", 47 | "mimetype": "text/x-python", 48 | "name": "python", 49 | "nbconvert_exporter": "python", 50 | "pygments_lexer": "ipython3", 51 | "version": "3.10.7" 52 | }, 53 | "vscode": { 54 | "interpreter": { 55 | "hash": "10197e8e2f2aa67e2c349105091c77f4cd384fce4877865f002d9ec653f96bc0" 56 | } 57 | } 58 | }, 59 | "nbformat": 4, 60 | "nbformat_minor": 2 61 | } 62 | -------------------------------------------------------------------------------- /2022-23/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright © 2022 Giovanni Squillero 2 | # https://github.com/squillero/computational-intelligence 3 | # Free for personal or classroom use; see 'LICENSE.md' for details. 4 | 5 | [tool.black] 6 | exclude = "(^\\.|^__pycache__)" 7 | include = "(\\.py$|\\.ipynb$)" 8 | #include = "\\.ipynb" 9 | line-length = 120 10 | 11 | [tool.isort] 12 | profile = "black" 13 | 14 | [tool.poetry] 15 | authors = ["Giovanni Squillero "] 16 | description = "Code and Notebook dependencies for Computational Intelligence (2022-23)" 17 | license = "proprietary" 18 | name = "ci22" 19 | version = "0.1.0" 20 | 21 | [tool.poetry.dependencies] 22 | black = {extras = ["jupyter"], version = "^22.6.0"} 23 | isort = "^5.10.1" 24 | jupyter = "^1.0.0" 25 | matplotlib = "^3.5.3" 26 | nero = {extras = ["jupyter"], version = "^1.0.20220202"} 27 | networkx = "^2.8.5" 28 | numpy = ">=1.23" 29 | pandas = "^1.4.3" 30 | pydot = "^1.4.2" 31 | python = ">=3.10" 32 | scipy = "^1.9.0" 33 | seaborn = "^0.11.2" 34 | toml = "^0.10.2" 35 | tqdm = "^4.64.0" 36 | 37 | [tool.poetry.dev-dependencies] 38 | 39 | [build-system] 40 | build-backend = "poetry.core.masonry.api" 41 | requires = ["poetry-core>=1.0.0"] 42 | -------------------------------------------------------------------------------- /2022-23/quarto/main.py: -------------------------------------------------------------------------------- 1 | # Free for personal or classroom use; see 'LICENSE.md' for details. 2 | # https://github.com/squillero/computational-intelligence 3 | 4 | import logging 5 | import argparse 6 | import random 7 | import quarto 8 | 9 | 10 | class RandomPlayer(quarto.Player): 11 | """Random player""" 12 | 13 | def __init__(self, quarto: quarto.Quarto) -> None: 14 | super().__init__(quarto) 15 | 16 | def choose_piece(self) -> int: 17 | return random.randint(0, 15) 18 | 19 | def place_piece(self) -> tuple[int, int]: 20 | return random.randint(0, 3), random.randint(0, 3) 21 | 22 | 23 | def main(): 24 | game = quarto.Quarto() 25 | game.set_players((RandomPlayer(game), RandomPlayer(game))) 26 | winner = game.run() 27 | logging.warning(f"main: Winner: player {winner}") 28 | 29 | 30 | if __name__ == '__main__': 31 | parser = argparse.ArgumentParser() 32 | parser.add_argument('-v', '--verbose', action='count', 33 | default=0, help='increase log verbosity') 34 | parser.add_argument('-d', 35 | '--debug', 36 | action='store_const', 37 | dest='verbose', 38 | const=2, 39 | help='log debug messages (same as -vv)') 40 | args = parser.parse_args() 41 | 42 | if args.verbose == 0: 43 | logging.getLogger().setLevel(level=logging.WARNING) 44 | elif args.verbose == 1: 45 | logging.getLogger().setLevel(level=logging.INFO) 46 | elif args.verbose == 2: 47 | logging.getLogger().setLevel(level=logging.DEBUG) 48 | 49 | main() 50 | -------------------------------------------------------------------------------- /2022-23/quarto/quarto/__init__.py: -------------------------------------------------------------------------------- 1 | # Free for personal or classroom use; see 'LICENSE.md' for details. 2 | # https://github.com/squillero/computational-intelligence 3 | 4 | from .objects import * 5 | -------------------------------------------------------------------------------- /2022-23/quarto/quarto/objects.py: -------------------------------------------------------------------------------- 1 | # Free for personal or classroom use; see 'LICENSE.md' for details. 2 | # https://github.com/squillero/computational-intelligence 3 | 4 | import numpy as np 5 | from abc import abstractmethod 6 | import copy 7 | 8 | 9 | class Player(object): 10 | 11 | def __init__(self, quarto) -> None: 12 | self.__quarto = quarto 13 | 14 | @abstractmethod 15 | def choose_piece(self) -> int: 16 | pass 17 | 18 | @abstractmethod 19 | def place_piece(self) -> tuple[int, int]: 20 | pass 21 | 22 | def get_game(self): 23 | return self.__quarto 24 | 25 | 26 | class Piece(object): 27 | 28 | def __init__(self, high: bool, coloured: bool, solid: bool, square: bool) -> None: 29 | self.HIGH = high 30 | self.COLOURED = coloured 31 | self.SOLID = solid 32 | self.SQUARE = square 33 | self.binary = [int(high), int(coloured), int(solid), int(square)] 34 | 35 | 36 | class Quarto(object): 37 | 38 | MAX_PLAYERS = 2 39 | BOARD_SIDE = 4 40 | 41 | def __init__(self) -> None: 42 | self.__players = () 43 | self.reset() 44 | 45 | def reset(self): 46 | self._board = np.ones( 47 | shape=(self.BOARD_SIDE, self.BOARD_SIDE), dtype=int) * -1 48 | self._binary_board = np.full( 49 | shape=(self.BOARD_SIDE, self.BOARD_SIDE, 4), fill_value=np.nan) 50 | self.__pieces = [] 51 | self.__pieces.append(Piece(False, False, False, False)) # 0 52 | self.__pieces.append(Piece(False, False, False, True)) # 1 53 | self.__pieces.append(Piece(False, False, True, False)) # 2 54 | self.__pieces.append(Piece(False, False, True, True)) # 3 55 | self.__pieces.append(Piece(False, True, False, False)) # 4 56 | self.__pieces.append(Piece(False, True, False, True)) # 5 57 | self.__pieces.append(Piece(False, True, True, False)) # 6 58 | self.__pieces.append(Piece(False, True, True, True)) # 7 59 | self.__pieces.append(Piece(True, False, False, False)) # 8 60 | self.__pieces.append(Piece(True, False, False, True)) # 9 61 | self.__pieces.append(Piece(True, False, True, False)) # 10 62 | self.__pieces.append(Piece(True, False, True, True)) # 11 63 | self.__pieces.append(Piece(True, True, False, False)) # 12 64 | self.__pieces.append(Piece(True, True, False, True)) # 13 65 | self.__pieces.append(Piece(True, True, True, False)) # 14 66 | self.__pieces.append(Piece(True, True, True, True)) # 15 67 | self._current_player = 0 68 | self.__selected_piece_index = -1 69 | 70 | def set_players(self, players: tuple[Player, Player]): 71 | self.__players = players 72 | 73 | def get_current_player(self) -> int: 74 | ''' 75 | Gets the current player 76 | ''' 77 | return self._current_player 78 | 79 | def select(self, pieceIndex: int) -> bool: 80 | ''' 81 | select a piece. Returns True on success 82 | ''' 83 | if pieceIndex not in self._board: 84 | self.__selected_piece_index = pieceIndex 85 | return True 86 | return False 87 | 88 | def place(self, x: int, y: int) -> bool: 89 | ''' 90 | Place piece in coordinates (x, y). Returns true on success 91 | ''' 92 | if self.__placeable(x, y): 93 | self._board[y, x] = self.__selected_piece_index 94 | self._binary_board[y, 95 | x][:] = self.__pieces[self.__selected_piece_index].binary 96 | return True 97 | return False 98 | 99 | def __placeable(self, x: int, y: int) -> bool: 100 | return not (y < 0 or x < 0 or x > 3 or y > 3 or self._board[y, x] >= 0) 101 | 102 | def print(self): 103 | ''' 104 | Print the board 105 | ''' 106 | for row in self._board: 107 | print("\n -------------------") 108 | print("|", end="") 109 | for element in row: 110 | print(f" {element: >2}", end=" |") 111 | print("\n -------------------\n") 112 | print(f"Selected piece: {self.__selected_piece_index}\n") 113 | 114 | def get_piece_charachteristics(self, index: int) -> Piece: 115 | ''' 116 | Gets charachteristics of a piece (index-based) 117 | ''' 118 | return copy.deepcopy(self.__pieces[index]) 119 | 120 | def get_board_status(self) -> np.ndarray: 121 | ''' 122 | Get the current board status (pieces are represented by index) 123 | ''' 124 | return copy.deepcopy(self._board) 125 | 126 | def get_selected_piece(self) -> int: 127 | ''' 128 | Get index of selected piece 129 | ''' 130 | return copy.deepcopy(self.__selected_piece_index) 131 | 132 | def __check_horizontal(self) -> int: 133 | hsum = np.sum(self._binary_board, axis=1) 134 | 135 | if self.BOARD_SIDE in hsum or 0 in hsum: 136 | return self._current_player 137 | else: 138 | return -1 139 | 140 | def __check_vertical(self): 141 | vsum = np.sum(self._binary_board, axis=0) 142 | 143 | if self.BOARD_SIDE in vsum or 0 in vsum: 144 | return self._current_player 145 | else: 146 | return -1 147 | 148 | def __check_diagonal(self): 149 | dsum1 = np.trace(self._binary_board, axis1=0, axis2=1) 150 | dsum2 = np.trace(np.fliplr(self._binary_board), axis1=0, axis2=1) 151 | 152 | if self.BOARD_SIDE in dsum1 or self.BOARD_SIDE in dsum2 or 0 in dsum1 or 0 in dsum2: 153 | return self._current_player 154 | else: 155 | return -1 156 | 157 | def check_winner(self) -> int: 158 | ''' 159 | Check who is the winner 160 | ''' 161 | l = [self.__check_horizontal(), self.__check_vertical(), 162 | self.__check_diagonal()] 163 | for elem in l: 164 | if elem >= 0: 165 | return elem 166 | return -1 167 | 168 | def check_finished(self) -> bool: 169 | ''' 170 | Check who is the loser 171 | ''' 172 | for row in self._board: 173 | for elem in row: 174 | if elem == -1: 175 | return False 176 | return True 177 | 178 | def run(self) -> int: 179 | ''' 180 | Run the game (with output for every move) 181 | ''' 182 | winner = -1 183 | while winner < 0 and not self.check_finished(): 184 | self.print() 185 | piece_ok = False 186 | while not piece_ok: 187 | piece_ok = self.select( 188 | self.__players[self._current_player].choose_piece()) 189 | piece_ok = False 190 | self._current_player = ( 191 | self._current_player + 1) % self.MAX_PLAYERS 192 | self.print() 193 | while not piece_ok: 194 | x, y = self.__players[self._current_player].place_piece() 195 | piece_ok = self.place(x, y) 196 | winner = self.check_winner() 197 | self.print() 198 | return winner 199 | -------------------------------------------------------------------------------- /2022-23/quarto/x.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/plain": [ 11 | "2" 12 | ] 13 | }, 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "output_type": "execute_result" 17 | } 18 | ], 19 | "source": [ 20 | "1+1" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 5, 26 | "metadata": {}, 27 | "outputs": [ 28 | { 29 | "ename": "SyntaxError", 30 | "evalue": "iterable unpacking cannot be used in comprehension (3946669366.py, line 1)", 31 | "output_type": "error", 32 | "traceback": [ 33 | "\u001b[1;36m Cell \u001b[1;32mIn[5], line 1\u001b[1;36m\u001b[0m\n\u001b[1;33m [*x for x in product([True, False], repeat=4)]\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m iterable unpacking cannot be used in comprehension\n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "\n", 39 | "[]" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": null, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [] 48 | } 49 | ], 50 | "metadata": { 51 | "kernelspec": { 52 | "display_name": "Python 3.10.7 ('ci22-dPIXJ0_o-py3.10')", 53 | "language": "python", 54 | "name": "python3" 55 | }, 56 | "language_info": { 57 | "codemirror_mode": { 58 | "name": "ipython", 59 | "version": 3 60 | }, 61 | "file_extension": ".py", 62 | "mimetype": "text/x-python", 63 | "name": "python", 64 | "nbconvert_exporter": "python", 65 | "pygments_lexer": "ipython3", 66 | "version": "3.10.7" 67 | }, 68 | "orig_nbformat": 4, 69 | "vscode": { 70 | "interpreter": { 71 | "hash": "10197e8e2f2aa67e2c349105091c77f4cd384fce4877865f002d9ec653f96bc0" 72 | } 73 | } 74 | }, 75 | "nbformat": 4, 76 | "nbformat_minor": 2 77 | } 78 | -------------------------------------------------------------------------------- /2022-23/spare.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2022 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 45, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import logging\n", 19 | "\n", 20 | "logging.getLogger().setLevel(logging.DEBUG)" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 60, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "__CALLS__ = dict()\n", 30 | "\n", 31 | "\n", 32 | "def FitnessFunction(fn):\n", 33 | " __CALLS__[fn.__name__] = 0\n", 34 | " logging.debug(f\"FitnessFunction: Tracing __CALLS__['{fn.__name__}'] ({fn})\")\n", 35 | "\n", 36 | " def call_count(*args, **kwargs):\n", 37 | " __CALLS__[fn.__name__] += 1\n", 38 | " return fn(*args, **kwargs)\n", 39 | "\n", 40 | " return call_count" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 61, 46 | "metadata": {}, 47 | "outputs": [ 48 | { 49 | "name": "stderr", 50 | "output_type": "stream", 51 | "text": [ 52 | "DEBUG:root:FitnessFunction: Tracing __CALLS__['two_max'] ()\n" 53 | ] 54 | } 55 | ], 56 | "source": [ 57 | "@FitnessFunction\n", 58 | "def two_max(genome):\n", 59 | " return 1" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 58, 65 | "metadata": {}, 66 | "outputs": [ 67 | { 68 | "data": { 69 | "text/plain": [ 70 | "10" 71 | ] 72 | }, 73 | "execution_count": 58, 74 | "metadata": {}, 75 | "output_type": "execute_result" 76 | } 77 | ], 78 | "source": [ 79 | "for _ in range(10):\n", 80 | " two_max([])\n", 81 | "\n", 82 | "__CALLS__[\"two_max\"]" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 59, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "data": { 92 | "text/plain": [ 93 | "{'two_max': 10}" 94 | ] 95 | }, 96 | "execution_count": 59, 97 | "metadata": {}, 98 | "output_type": "execute_result" 99 | } 100 | ], 101 | "source": [ 102 | "__CALLS__" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [] 111 | } 112 | ], 113 | "metadata": { 114 | "kernelspec": { 115 | "display_name": "Python 3.10.8 ('ci22-TL8fdjaI-py3.10')", 116 | "language": "python", 117 | "name": "python3" 118 | }, 119 | "language_info": { 120 | "codemirror_mode": { 121 | "name": "ipython", 122 | "version": 3 123 | }, 124 | "file_extension": ".py", 125 | "mimetype": "text/x-python", 126 | "name": "python", 127 | "nbconvert_exporter": "python", 128 | "pygments_lexer": "ipython3", 129 | "version": "3.10.8" 130 | }, 131 | "orig_nbformat": 4, 132 | "vscode": { 133 | "interpreter": { 134 | "hash": "db7869eac3a3065f778b76b149009660cff2da61ddf3afbeaa5d4c3bda380063" 135 | } 136 | } 137 | }, 138 | "nbformat": 4, 139 | "nbformat_minor": 2 140 | } 141 | -------------------------------------------------------------------------------- /2022-23/test-problems.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "Copyright **`(c)`** 2022 Giovanni Squillero `` \n", 12 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 13 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. \n" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 1, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import logging\n", 23 | "import random" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "# Test Problems\n", 31 | "\n", 32 | "## *Call Counter* annotation for fitness functions" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 2, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "__CALLS__ = dict()\n", 42 | "\n", 43 | "\n", 44 | "def CallCounter(fn):\n", 45 | " \"\"\"Annotation @CallCounter\"\"\"\n", 46 | " assert fn.__name__ not in __CALLS__, f\"Function '{fn.__name__}' already listed in __CALLS__\"\n", 47 | " __CALLS__[fn.__name__] = 0\n", 48 | " logging.debug(f\"CallCounter: Counting __CALLS__['{fn.__name__}'] ({fn})\")\n", 49 | "\n", 50 | " def call_count(*args, **kwargs):\n", 51 | " __CALLS__[fn.__name__] += 1\n", 52 | " return fn(*args, **kwargs)\n", 53 | "\n", 54 | " return call_count" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "Example: how many calls to randomly generate a genome of 16 $1$'s?" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 3, 67 | "metadata": {}, 68 | "outputs": [ 69 | { 70 | "name": "stderr", 71 | "output_type": "stream", 72 | "text": [ 73 | "DEBUG:root:CallCounter: Counting __CALLS__['onemax'] ()\n" 74 | ] 75 | }, 76 | { 77 | "name": "stdout", 78 | "output_type": "stream", 79 | "text": [ 80 | "{'onemax': 29087}\n" 81 | ] 82 | } 83 | ], 84 | "source": [ 85 | "logging.getLogger().setLevel(logging.DEBUG)\n", 86 | "\n", 87 | "\n", 88 | "@CallCounter\n", 89 | "def onemax(genome):\n", 90 | " return max(sum(genome) / len(genome), 1 - sum(genome) / len(genome))\n", 91 | "\n", 92 | "\n", 93 | "while onemax([random.choice([True, False]) for _ in range(16)]) < 1:\n", 94 | " pass\n", 95 | "print(__CALLS__)" 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "## Pseudo Set-Covering\n", 103 | "\n", 104 | "Given a number $N$ and some lists of integers $P = (L_0, L_1, L_2, ..., L_n)$, \n", 105 | "determine, if possible, $S = (L_{s_0}, L_{s_1}, L_{s_2}, ..., L_{s_n})$\n", 106 | "such that each number between $0$ and $N-1$ appears in at least one list\n", 107 | "\n", 108 | "$$\\forall n \\in [0, N-1] \\ \\exists i : n \\in L_{s_i}$$\n", 109 | "\n", 110 | "and that the total numbers of elements in all $L_{s_i}$ is minimum. " 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 4, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "def pseudo_set_covering(N, seed=None):\n", 120 | " state = random.getstate()\n", 121 | " random.seed(seed)\n", 122 | " p = [\n", 123 | " list(set(random.randint(0, N - 1) for n in range(random.randint(N // 5, N // 2))))\n", 124 | " for n in range(random.randint(N, N * 5))\n", 125 | " ]\n", 126 | " random.setstate(state)\n", 127 | " return p" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 5, 133 | "metadata": {}, 134 | "outputs": [ 135 | { 136 | "name": "stderr", 137 | "output_type": "stream", 138 | "text": [ 139 | "DEBUG:root:CallCounter: Counting __CALLS__['foo'] ()\n" 140 | ] 141 | } 142 | ], 143 | "source": [ 144 | "@CallCounter\n", 145 | "def foo():\n", 146 | " pass" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 6, 152 | "metadata": {}, 153 | "outputs": [ 154 | { 155 | "data": { 156 | "text/plain": [ 157 | "(None, None, None)" 158 | ] 159 | }, 160 | "execution_count": 6, 161 | "metadata": {}, 162 | "output_type": "execute_result" 163 | } 164 | ], 165 | "source": [ 166 | "foo(), foo(), foo()" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": 7, 172 | "metadata": {}, 173 | "outputs": [ 174 | { 175 | "data": { 176 | "text/plain": [ 177 | "{'onemax': 29087, 'foo': 3}" 178 | ] 179 | }, 180 | "execution_count": 7, 181 | "metadata": {}, 182 | "output_type": "execute_result" 183 | } 184 | ], 185 | "source": [ 186 | "__CALLS__" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": null, 192 | "metadata": {}, 193 | "outputs": [], 194 | "source": [] 195 | } 196 | ], 197 | "metadata": { 198 | "kernelspec": { 199 | "display_name": "Python 3.10.7 ('ci22-dPIXJ0_o-py3.10')", 200 | "language": "python", 201 | "name": "python3" 202 | }, 203 | "language_info": { 204 | "codemirror_mode": { 205 | "name": "ipython", 206 | "version": 3 207 | }, 208 | "file_extension": ".py", 209 | "mimetype": "text/x-python", 210 | "name": "python", 211 | "nbconvert_exporter": "python", 212 | "pygments_lexer": "ipython3", 213 | "version": "3.10.7" 214 | }, 215 | "vscode": { 216 | "interpreter": { 217 | "hash": "10197e8e2f2aa67e2c349105091c77f4cd384fce4877865f002d9ec653f96bc0" 218 | } 219 | } 220 | }, 221 | "nbformat": 4, 222 | "nbformat_minor": 2 223 | } 224 | -------------------------------------------------------------------------------- /2022-23/tic-tac-toe.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2021 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see 'LICENCE.md' for details." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "from itertools import permutations\n", 19 | "import numpy as np" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "TICTACTOE_MAP = np.array([[1, 6, 5], [8, 4, 0], [3, 2, 7]])\n", 29 | "\n", 30 | "\n", 31 | "def display(x, o):\n", 32 | " for r in range(3):\n", 33 | " for c in range(3):\n", 34 | " if TICTACTOE_MAP[r, c] in x:\n", 35 | " print(\"X\", end=\" \")\n", 36 | " elif TICTACTOE_MAP[r, c] in o:\n", 37 | " print(\"O\", end=\" \")\n", 38 | " else:\n", 39 | " print(\".\", end=\" \")\n", 40 | " print()" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 3, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "def won(cells):\n", 50 | " return any(sum(h) == 12 for h in permutations(cells, 3))\n", 51 | "\n", 52 | "\n", 53 | "def eval_terminal(x, o):\n", 54 | " if won(x):\n", 55 | " return 1\n", 56 | " elif won(o):\n", 57 | " return -1\n", 58 | " else:\n", 59 | " return 0" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 4, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "def minmax(board):\n", 69 | " val = eval_terminal(*board)\n", 70 | " possible = list(set(range(9)) - board[0] - board[1])\n", 71 | " if val != 0 or not possible:\n", 72 | " return None, val\n", 73 | " evaluations = list()\n", 74 | " for ply in possible:\n", 75 | " _, val = minmax((board[1], board[0] | {ply}))\n", 76 | " evaluations.append((ply, -val))\n", 77 | " return max(evaluations, key=lambda k: k[1])" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 5, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "name": "stdout", 87 | "output_type": "stream", 88 | "text": [ 89 | "X . O \n", 90 | "O . . \n", 91 | "X . . \n", 92 | "\n", 93 | "X . O \n", 94 | "O . . \n", 95 | "X . X \n" 96 | ] 97 | } 98 | ], 99 | "source": [ 100 | "p = ({1, 3}, {5, 8})\n", 101 | "display(*p)\n", 102 | "print()\n", 103 | "best_ply, eval = minmax(p)\n", 104 | "display(p[0] | {best_ply}, p[1])" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [] 113 | } 114 | ], 115 | "metadata": { 116 | "kernelspec": { 117 | "display_name": "Python 3.10.7 ('ci22-dPIXJ0_o-py3.10')", 118 | "language": "python", 119 | "name": "python3" 120 | }, 121 | "language_info": { 122 | "codemirror_mode": { 123 | "name": "ipython", 124 | "version": 3 125 | }, 126 | "file_extension": ".py", 127 | "mimetype": "text/x-python", 128 | "name": "python", 129 | "nbconvert_exporter": "python", 130 | "pygments_lexer": "ipython3", 131 | "version": "3.10.7" 132 | }, 133 | "orig_nbformat": 4, 134 | "vscode": { 135 | "interpreter": { 136 | "hash": "10197e8e2f2aa67e2c349105091c77f4cd384fce4877865f002d9ec653f96bc0" 137 | } 138 | } 139 | }, 140 | "nbformat": 4, 141 | "nbformat_minor": 2 142 | } 143 | -------------------------------------------------------------------------------- /2023-24/Halloween.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "185f9931-b384-4fdc-a5b2-eea785428bb8", 6 | "metadata": {}, 7 | "source": [ 8 | "Copyright **`(c)`** 2023 Giovanni Squillero `` \n", 9 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 10 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "id": "3ffe7245-e849-41d0-9698-5f0e0b83fee9", 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "from itertools import product\n", 21 | "from random import random, randint, shuffle, seed\n", 22 | "import numpy as np\n", 23 | "from scipy import sparse" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 2, 29 | "id": "6f03bd67-78a0-4d72-95b7-77a918727b91", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "def make_set_covering_problem(num_points, num_sets, density):\n", 34 | " \"\"\"Returns a sparse array where rows are sets and columns are the covered items\"\"\"\n", 35 | " seed(num_points*2654435761+num_sets+density)\n", 36 | " sets = sparse.lil_array((num_sets, num_points), dtype=bool)\n", 37 | " for s, p in product(range(num_sets), range(num_points)):\n", 38 | " if random() < density:\n", 39 | " sets[s, p] = True\n", 40 | " for p in range(num_points):\n", 41 | " sets[randint(0, num_sets-1), p] = True\n", 42 | " return sets" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "id": "82b0be37-21d9-492d-9a1d-cf0cdf0ddd76", 48 | "metadata": {}, 49 | "source": [ 50 | "# Halloween Challenge\n", 51 | "\n", 52 | "Find the best solution with the fewest calls to the fitness functions for:\n", 53 | "\n", 54 | "* `num_points = [100, 1_000, 5_000]`\n", 55 | "* `num_sets = num_points`\n", 56 | "* `density = [.3, .7]` " 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 3, 62 | "id": "221ffdba-5d3d-48cc-bd08-45ccc9366ea6", 63 | "metadata": {}, 64 | "outputs": [ 65 | { 66 | "name": "stdout", 67 | "output_type": "stream", 68 | "text": [ 69 | "Element at row=42 and column=42: False\n" 70 | ] 71 | } 72 | ], 73 | "source": [ 74 | "x = make_set_covering_problem(1000, 1000, .3)\n", 75 | "print(\"Element at row=42 and column=42:\", x[42, 42])" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "id": "6492337b-8429-472d-9c3e-c79c5b46da54", 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [] 85 | } 86 | ], 87 | "metadata": { 88 | "kernelspec": { 89 | "display_name": "Python 3 (ipykernel)", 90 | "language": "python", 91 | "name": "python3" 92 | }, 93 | "language_info": { 94 | "codemirror_mode": { 95 | "name": "ipython", 96 | "version": 3 97 | }, 98 | "file_extension": ".py", 99 | "mimetype": "text/x-python", 100 | "name": "python", 101 | "nbconvert_exporter": "python", 102 | "pygments_lexer": "ipython3", 103 | "version": "3.11.2" 104 | } 105 | }, 106 | "nbformat": 4, 107 | "nbformat_minor": 5 108 | } 109 | -------------------------------------------------------------------------------- /2023-24/Lab1.txt: -------------------------------------------------------------------------------- 1 | First lab done -------------------------------------------------------------------------------- /2023-24/contrib/GAs_visualization_tool/README.md: -------------------------------------------------------------------------------- 1 | **Author:** Beatrice Occhiena s314971. See [`LICENSE`](https://github.com/beatrice-occhiena/Computational_intelligence/blob/main/LICENSE) for details. 2 | - institutional email: `S314971@studenti.polito.it` 3 | - personal email: `beatrice.occhiena@live.it` 4 | - github repository: [https://github.com/beatrice-occhiena/Computational_intelligence.git](https://github.com/beatrice-occhiena/Computational_intelligence.git) 5 | 6 | **Resources:** These notes are the result of additional research and analysis of the lecture material presented by Professor Giovanni Squillero for the Computational Intelligence course during the academic year 2023-2024 @ Politecnico di Torino. They are intended to be my attempt to make a personal contribution and to rework the topics covered in the following resources. 7 | - [https://github.com/squillero/computational-intelligence](https://github.com/squillero/computational-intelligence) 8 | - Stuart Russel, Peter Norvig, *Artificial Intelligence: A Modern Approach* [3th edition] 9 | 10 | - Sean Luke, *Essentials of Metaheuristics*, 2016 [online version 2.3] 11 | - Nikolaus Hansen, Dirk V. Arnold, Anne Auger, *Evolution Strategies*, February 2015 12 | 13 | . 14 | 15 | . 16 | 17 | # Visualization Tool for Population-based Methods 18 | In this mini-project I've tried to develop a Python program to visualize and experiment with evolutionary algorithms, in the context of optimizing complex functions with known landscapes. This will hopefully serve as a useful tool for understanding the behavior of evolutionary algorithms, and for experimenting with different parameters and operators. 19 | 20 | ## The Problem 21 | We will consider the problem of optimizing a function of two variables, `f(x,y)`, where `x` and `y` are real numbers. The chosen function is the **Himmelblau's function**, which is a well-known test function for optimization algorithms. 22 | 23 | ![himmelblau's](himmelblaus.png) 24 | 25 | ## The Population 26 | An individual in the population is a pair of real numbers, `x` and `y`. The fitness of an individual is the value of the function `f(x,y)`. 27 | - Parameters: *population_size, generations* 28 | 29 | ## Genetic Operators 30 | We will use the following genetic operators: 31 | - **Mutation**: each component of the individual is mutated with a certain probability and strength. The "pervasive" version of each operator mutates all the components of the individual. 32 | 1. `Uniform mutation` 33 | 2. `Pervasive uniform mutation` 34 | 3. `Gaussian mutation` 35 | - Parameters: *mutation_rate, mutation_strength, cooling_rate* 36 | - **Crossover**: the crossover operator combines two individuals to produce two new individuals. 37 | 1. `One-point crossover` 38 | 2. `Average crossover` 39 | - Parameters: *crossover_rate* 40 | - **Selection**: the selection operator selects an individual from the population, to be used as a parent for the next generation. 41 | 1. `Tournament selection` 42 | - Parameters: *tournament_size* 43 | 44 | ## Visualization 45 | This is the final result of a simulation with the following parameters: 46 | - **Tuning parameters**: 47 | - `population_size = 100` 48 | - `generations = 10` 49 | - `mutation_rate = 0.3` 50 | - `mutation_strength = 0.5` 51 | - `tournament_size = 2` 52 | - `cooling_rate = 1` 53 | - `crossover_rate = 1` 54 | - **Genetic operators**: 55 | - SELECTION: `tournament_selection` 56 | - CROSSOVER: `one_point_crossover` 57 | - MUTATION: `pervasive_gaussian_mutation` 58 | 59 | ![pop_evolution.gif](pop_evolution.gif) 60 | 61 | ## Further Developments 62 | - [ ] Add more genetic operators 63 | - [ ] Implement self-adaptive techniques 64 | - [ ] Add more fitness functions 65 | - [ ] Find a way to differentiate between genotypes and phenotypes 66 | 67 | -------------------------------------------------------------------------------- /2023-24/contrib/GAs_visualization_tool/himmelblaus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2023-24/contrib/GAs_visualization_tool/himmelblaus.png -------------------------------------------------------------------------------- /2023-24/contrib/GAs_visualization_tool/pop_evolution.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2023-24/contrib/GAs_visualization_tool/pop_evolution.gif -------------------------------------------------------------------------------- /2023-24/contrib/Prooving the non-solvability of the friends’ problem.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2023-24/contrib/Prooving the non-solvability of the friends’ problem.pdf -------------------------------------------------------------------------------- /2023-24/contrib/README.md: -------------------------------------------------------------------------------- 1 | # CONTRIB 2 | 3 | Spare students' contributions. Unless otherwise noted, all material is licensed under the [EUPL](https://eupl.eu/) 4 | -------------------------------------------------------------------------------- /2023-24/contrib/pizza_pub/README.md: -------------------------------------------------------------------------------- 1 | # Pizza pub problem 2 | 3 | ## Description 4 | 5 | A group of friends has to move from a pizzeria to a pub, the friends group is composed of computer engineers(ce), and data scientists(ds). 6 | The vehicle they have to move from one place to the other is a bike with a certain number of seats. 7 | At any moment in either the pizzera or pub the number of data scientists (if any) must be equal or greater to the number of computer engineers. 8 | 9 | ## Goal 10 | 11 | Move everyone from the pizzeria to the pub using the bike 12 | 13 | ## Solution 14 | 15 | The current state of the problem is defined as the number of computer engineers (ce) and data scientists (ds) at the pizzeria, on the bike and at the pub plus the position of the bike. 16 | 17 | The position of the bike is necessary since you cannot mount a bike which is elsewhere unless somebody is bringing it to you. 18 | 19 | This description of the state considers states where the position of the bike is different as different states, even though if at least one person is on the bike these two different states can generate the same set of adjacent states. (This may very well be improved in the future). 20 | 21 | The solution is found by generating from the initial state the adjacent states and exploring them until a solution is found. The same state is not analyzed twice. 22 | -------------------------------------------------------------------------------- /2023-24/contrib/pizza_pub/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2023-24/contrib/pizza_pub/__init__.py -------------------------------------------------------------------------------- /2023-24/contrib/pizza_pub/main.py: -------------------------------------------------------------------------------- 1 | from queue import Queue 2 | from state import State 3 | 4 | FRIENDS_COUNT = 6 5 | 6 | 7 | def explore_tree(queue: Queue[State], iteraton_limit=None) -> list[State] | None: 8 | discovered_sates: set[State] = set() 9 | while iteraton_limit if iteraton_limit else True: 10 | iteraton_limit -= 1 11 | current_state: State = queue.get() 12 | adjacents: set[State] = current_state.generate_adjacents() 13 | for adj in adjacents: 14 | if adj in discovered_sates: 15 | continue 16 | if adj.is_solution(): 17 | print(f'Solution found after analyzing {len(discovered_sates)} states') 18 | return adj.ancestor_states() 19 | queue.put(adj) 20 | discovered_sates.add(current_state) 21 | return None 22 | 23 | 24 | def main(): 25 | initial_state = State.initial(FRIENDS_COUNT) 26 | q = Queue() 27 | q.put(initial_state) 28 | path = explore_tree(q, 1500) 29 | for state in path: 30 | print(state) 31 | 32 | 33 | if __name__ == '__main__': 34 | main() 35 | -------------------------------------------------------------------------------- /2023-24/contrib/pizza_pub/state.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | from student_group import StudentGroup 3 | from dataclasses import dataclass 4 | from dataclasses import field 5 | 6 | BIKE_CAPACITY = 2 7 | 8 | 9 | @dataclass(frozen=True) 10 | class State: 11 | pizzeria: StudentGroup 12 | bike: StudentGroup = StudentGroup.empty() 13 | pub: StudentGroup = StudentGroup.empty() 14 | bike_position: str = 'pizzeria' 15 | parent: State | None = field(default=None, compare=False) 16 | 17 | def __str__(self): 18 | return f'{self.pizzeria}{self.bike}{self.pub} bike in: {self.bike_position}' 19 | 20 | def bike_elsewhere(self, source, destination): 21 | if self.bike_position in [source, destination]: 22 | return False 23 | return True 24 | 25 | def move_group(self, source_name: str, destination_name: str, group: StudentGroup) -> State: 26 | result_pizzera, result_bike, result_pub = self.pizzeria, self.bike, self.pub 27 | if source_name == 'bike': # getting off the bike 28 | result_bike -= group 29 | if destination_name == 'pizzeria': 30 | result_pizzera += group 31 | else: 32 | result_pub += group 33 | else: # mounting on the bike 34 | result_bike += group 35 | if source_name == 'pizzeria': 36 | result_pizzera -= group 37 | else: 38 | result_pub -= group 39 | if self.bike_position not in [source_name, destination_name]: 40 | result_bike_position = source_name if source_name != 'bike' else destination_name 41 | else: 42 | result_bike_position = self.bike_position 43 | return State(result_pizzera, result_bike, result_pub, result_bike_position, self) 44 | 45 | def generate_adjacents(self) -> set[State]: 46 | adjacents = set() 47 | source_destination = (('pizzeria', 'bike'), ('bike', 'pizzeria'), ('bike', 'pub'), ('pub', 'pizzeria')) 48 | for src_dest_pair in source_destination: 49 | source_name = src_dest_pair[0] 50 | destination_name = src_dest_pair[1] 51 | source: StudentGroup = getattr(self, source_name) 52 | 53 | if self.bike_elsewhere(source_name, destination_name) and self.bike == StudentGroup.empty(): 54 | continue # bike is elsewhere and nobody can bring it here 55 | 56 | for subgroup in source.generate_subgroups(max_size=BIKE_CAPACITY if destination_name == 'bike' else None): 57 | adjacent_candidate: State = self.move_group(source_name, destination_name, subgroup) 58 | if adjacent_candidate.is_valid(): 59 | adjacents.add(adjacent_candidate) 60 | return adjacents 61 | 62 | def is_valid(self) -> bool: 63 | if not self.pizzeria.is_valid(): 64 | return False 65 | if not self.pub.is_valid(): 66 | return False 67 | if self.bike.size() > BIKE_CAPACITY: 68 | return False 69 | return True 70 | 71 | def is_solution(self) -> bool: 72 | if self.pizzeria.size() != 0: 73 | return False 74 | if self.bike.size() != 0: 75 | return False 76 | return True 77 | 78 | def ancestor_states(self) -> list[State]: 79 | ancestors = [] 80 | state: State | None = self 81 | while state: 82 | ancestors.append(state) 83 | state = state.parent 84 | ancestors.reverse() 85 | return ancestors 86 | 87 | @staticmethod 88 | def initial(number_of_students: int): 89 | pizzeria_group = StudentGroup.split_evenly(number_of_students) 90 | return State(pizzeria_group) 91 | -------------------------------------------------------------------------------- /2023-24/contrib/pizza_pub/student_group.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | from dataclasses import dataclass 3 | 4 | 5 | @dataclass(frozen=True) 6 | class StudentGroup: 7 | ce: int 8 | ds: int 9 | 10 | def __add__(self, other): 11 | ce = self.ce + other.ce 12 | ds = self.ds + other.ds 13 | return StudentGroup(ce, ds) 14 | 15 | def __sub__(self, other): 16 | ce = self.ce - other.ce 17 | ds = self.ds - other.ds 18 | if ce < 0 or ds < 0: 19 | raise ValueError('Not enough students to subtract subgroup') 20 | return StudentGroup(ce, ds) 21 | 22 | def __str__(self): 23 | return f'({self.ce}, {self.ds})' 24 | 25 | def is_valid(self): 26 | if self.ds == 0: 27 | return True 28 | if self.ds >= self.ce: 29 | return True 30 | return False 31 | 32 | def generate_sized_subgroups(self, size: int) -> set[StudentGroup]: 33 | subgroups = set() 34 | max_ce = min(size, self.ce) 35 | for ce in range(max_ce + 1): 36 | if ce + self.ds < size: 37 | continue 38 | ds = size - ce 39 | subgroups.add(StudentGroup(ce, ds)) 40 | return subgroups 41 | 42 | def generate_subgroups(self, max_size: int | None) -> set[StudentGroup]: 43 | subgroups = set() 44 | max_size = min(max_size, self.size()) if max_size else self.size() 45 | for subgroup_size in range(1, max_size + 1): 46 | sized_soubgroups = self.generate_sized_subgroups(subgroup_size) 47 | subgroups.update(sized_soubgroups) 48 | return subgroups 49 | 50 | def size(self) -> int: 51 | return self.ce + self.ds 52 | 53 | @staticmethod 54 | def empty(): 55 | return StudentGroup(0, 0) 56 | 57 | @staticmethod 58 | def split_evenly(number_of_students): 59 | if number_of_students % 2 != 0: 60 | raise ValueError 61 | half_students = number_of_students // 2 62 | return StudentGroup(half_students, half_students) 63 | 64 | 65 | """ def __hash__(self): 66 | return hash((self.ce, self.ds)) 67 | 68 | def __eq__(self, other): 69 | if not isinstance(other, StudentGroup): 70 | return False 71 | return self.__dict__ == other.__dict__ 72 | 73 | def __init__(self, computer_engineers: int, data_scientists: int): 74 | if computer_engineers < 0 or data_scientists < 0: raise ValueError() 75 | self.ce = computer_engineers 76 | self.ds = data_scientists """ 77 | -------------------------------------------------------------------------------- /2023-24/contrib/pizza_pub/test/test_state.py: -------------------------------------------------------------------------------- 1 | from state import State 2 | from student_group import StudentGroup 3 | 4 | 5 | def test_equality(): 6 | s = State.initial(4) 7 | other = State.initial(4) 8 | assert s == other 9 | 10 | 11 | def test_bike_elsewhere_true(): 12 | s = State.initial(6) 13 | assert s.bike_position == 'pizzeria' 14 | assert s.bike_elsewhere('bike', 'pub') == True 15 | assert s.bike_elsewhere('pub', 'bike') == True 16 | 17 | 18 | def test_bike_elsewhere_false(): 19 | s = State.initial(8) 20 | assert s.bike_position == 'pizzeria' 21 | assert s.bike_elsewhere('bike', 'pizzeria') == False 22 | assert s.bike_elsewhere('pizzeria', 'bike') == False 23 | 24 | 25 | def test_move_group(): 26 | s = State.initial(8) 27 | group = StudentGroup.split_evenly(4) 28 | state_after_movement = s.move_group('pizzeria', 'bike', group) 29 | assert state_after_movement == State(StudentGroup(2, 2), StudentGroup(2, 2)) 30 | 31 | 32 | def test_ancestor_states(): 33 | parent = State(StudentGroup(0, 0), StudentGroup(2, 0), StudentGroup(1, 3), 'pizzeria') 34 | child = parent.move_group('bike', 'pub', StudentGroup(2, 0)) 35 | ancestors = child.ancestor_states() 36 | assert ancestors is not None 37 | assert len(ancestors) == 2 38 | assert child in ancestors 39 | assert parent in ancestors 40 | -------------------------------------------------------------------------------- /2023-24/contrib/pizza_pub/test/test_student_group.py: -------------------------------------------------------------------------------- 1 | from student_group import StudentGroup 2 | 3 | 4 | def test_equality(): 5 | first_group = StudentGroup(3, 4) 6 | second_group = StudentGroup(3, 4) 7 | assert first_group == second_group 8 | assert hash(first_group) == hash(second_group) 9 | 10 | 11 | def test_add(): 12 | first_group = StudentGroup(3, 4) 13 | second_group = StudentGroup(2, 0) 14 | res = first_group + second_group 15 | assert type(res) == type(first_group) 16 | assert res.ce == 5 17 | assert res.ds == 4 18 | 19 | 20 | def test_add_empty_groups(): 21 | first_group = StudentGroup(0, 0) 22 | second_group = StudentGroup(0, 0) 23 | res = first_group + second_group 24 | assert res.ce == 0 25 | assert res.ds == 0 26 | 27 | 28 | def test_generate_sized_subgroups(): 29 | group = StudentGroup(3, 4) 30 | subgroups = group.generate_sized_subgroups(3) 31 | expected_subgroups = {StudentGroup(0, 3), StudentGroup(1, 2), StudentGroup(2, 1), StudentGroup(3, 0)} 32 | assert len(expected_subgroups) == len(subgroups) 33 | for expected_subgroup in expected_subgroups: 34 | assert expected_subgroup in subgroups 35 | -------------------------------------------------------------------------------- /2023-24/gx_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2023 Giovanni Squillero 2 | # https://github.com/squillero/computational-intelligence 3 | # Free for personal or classroom use; see 'LICENSE.md' for details. 4 | 5 | import heapq 6 | from collections import Counter 7 | 8 | 9 | class PriorityQueue: 10 | """A basic Priority Queue with simple performance optimizations""" 11 | 12 | def __init__(self): 13 | self._data_heap = list() 14 | self._data_set = set() 15 | 16 | def __bool__(self): 17 | return bool(self._data_set) 18 | 19 | def __contains__(self, item): 20 | return item in self._data_set 21 | 22 | def push(self, item, p=None): 23 | assert item not in self, f"Duplicated element" 24 | if p is None: 25 | p = len(self._data_set) 26 | self._data_set.add(item) 27 | heapq.heappush(self._data_heap, (p, item)) 28 | 29 | def pop(self): 30 | p, item = heapq.heappop(self._data_heap) 31 | self._data_set.remove(item) 32 | return item 33 | 34 | 35 | class Multiset: 36 | """Multiset""" 37 | 38 | def __init__(self, init=None): 39 | self._data = Counter() 40 | if init: 41 | for item in init: 42 | self.add(item) 43 | 44 | def __contains__(self, item): 45 | return item in self._data and self._data[item] > 0 46 | 47 | def __getitem__(self, item): 48 | return self.count(item) 49 | 50 | def __iter__(self): 51 | return (i for i in sorted(self._data.keys()) for _ in range(self._data[i])) 52 | 53 | def __len__(self): 54 | return sum(self._data.values()) 55 | 56 | def __copy__(self): 57 | t = Multiset() 58 | t._data = self._data.copy() 59 | return t 60 | 61 | def __str__(self): 62 | return f"M{{{', '.join(repr(i) for i in self)}}}" 63 | 64 | def __repr__(self): 65 | return str(self) 66 | 67 | def __or__(self, other: "Multiset"): 68 | tmp = Multiset() 69 | for i in set(self._data.keys()) | set(other._data.keys()): 70 | tmp.add(i, cnt=max(self[i], other[i])) 71 | return tmp 72 | 73 | def __and__(self, other: "Multiset"): 74 | return self.intersection(other) 75 | 76 | def __add__(self, other: "Multiset"): 77 | return self.union(other) 78 | 79 | def __sub__(self, other: "Multiset"): 80 | tmp = Multiset(self) 81 | for i, n in other._data.items(): 82 | tmp.remove(i, cnt=n) 83 | return tmp 84 | 85 | def __eq__(self, other: "Multiset"): 86 | return list(self) == list(other) 87 | 88 | def __le__(self, other: "Multiset"): 89 | for i, n in self._data.items(): 90 | if other.count(i) < n: 91 | return False 92 | return True 93 | 94 | def __lt__(self, other: "Multiset"): 95 | return self <= other and not self == other 96 | 97 | def __ge__(self, other: "Multiset"): 98 | return other <= self 99 | 100 | def __gt__(self, other: "Multiset"): 101 | return other < self 102 | 103 | def add(self, item, *, cnt=1): 104 | assert cnt >= 0, "Can't add a negative number of elements" 105 | if cnt > 0: 106 | self._data[item] += cnt 107 | 108 | def remove(self, item, *, cnt=1): 109 | assert item in self, f"Item not in collection" 110 | self._data[item] -= cnt 111 | if self._data[item] <= 0: 112 | del self._data[item] 113 | 114 | def count(self, item): 115 | return self._data[item] if item in self._data else 0 116 | 117 | def union(self, other: "Multiset"): 118 | t = Multiset(self) 119 | for i in other._data.keys(): 120 | t.add(i, cnt=other[i]) 121 | return t 122 | 123 | def intersection(self, other: "Multiset"): 124 | t = Multiset() 125 | for i in self._data.keys(): 126 | t.add(i, cnt=min(self[i], other[i])) 127 | return t 128 | -------------------------------------------------------------------------------- /2023-24/lab10-gx.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2023 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 11, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "from itertools import combinations\n", 19 | "from collections import namedtuple, defaultdict\n", 20 | "from random import choice\n", 21 | "from copy import deepcopy\n", 22 | "\n", 23 | "from tqdm.auto import tqdm\n", 24 | "import numpy as np" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 2, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "State = namedtuple('State', ['x', 'o'])" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 3, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "MAGIC = [2, 7, 6, 9, 5, 1, 4, 3, 8]" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 4, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "def print_board(pos):\n", 52 | " \"\"\"Nicely prints the board\"\"\"\n", 53 | " for r in range(3):\n", 54 | " for c in range(3):\n", 55 | " i = r * 3 + c\n", 56 | " if MAGIC[i] in pos.x:\n", 57 | " print('X', end='')\n", 58 | " elif MAGIC[i] in pos.o:\n", 59 | " print('O', end='')\n", 60 | " else:\n", 61 | " print('.', end='')\n", 62 | " print()\n", 63 | " print()" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 5, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "def win(elements):\n", 73 | " \"\"\"Checks is elements is winning\"\"\"\n", 74 | " return any(sum(c) == 15 for c in combinations(elements, 3))\n", 75 | "\n", 76 | "def state_value(pos: State):\n", 77 | " \"\"\"Evaluate state: +1 first player wins\"\"\"\n", 78 | " if win(pos.x):\n", 79 | " return 1\n", 80 | " elif win(pos.o):\n", 81 | " return -1\n", 82 | " else:\n", 83 | " return 0\n", 84 | " \n", 85 | " " 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 8, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "def random_game():\n", 95 | " trajectory = list()\n", 96 | " state = State(set(), set())\n", 97 | " available = set(range(1, 9+1))\n", 98 | " while available:\n", 99 | " x = choice(list(available))\n", 100 | " state.x.add(x)\n", 101 | " trajectory.append(deepcopy(state))\n", 102 | " available.remove(x)\n", 103 | " if win(state.x) or not available:\n", 104 | " break\n", 105 | "\n", 106 | " o = choice(list(available))\n", 107 | " state.o.add(o)\n", 108 | " trajectory.append(deepcopy(state))\n", 109 | " available.remove(o)\n", 110 | " if win(state.o):\n", 111 | " break\n", 112 | " return trajectory" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 26, 118 | "metadata": {}, 119 | "outputs": [ 120 | { 121 | "data": { 122 | "application/vnd.jupyter.widget-view+json": { 123 | "model_id": "d498dd1aa362440fb767c62e2c167872", 124 | "version_major": 2, 125 | "version_minor": 0 126 | }, 127 | "text/plain": [ 128 | " 0%| | 0/500000 [00:00` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# LAB10\n", 17 | "\n", 18 | "Use reinforcement learning to devise a tic-tac-toe player.\n", 19 | "\n", 20 | "### Deadlines:\n", 21 | "\n", 22 | "* Submission: [Dies Natalis Solis Invicti](https://en.wikipedia.org/wiki/Sol_Invictus)\n", 23 | "* Reviews: [Befana](https://en.wikipedia.org/wiki/Befana)\n", 24 | "\n", 25 | "Notes:\n", 26 | "\n", 27 | "* Reviews will be assigned on Monday, December 4\n", 28 | "* You need to commit in order to be selected as a reviewer (ie. better to commit an empty work than not to commit)" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [] 37 | } 38 | ], 39 | "metadata": { 40 | "kernelspec": { 41 | "display_name": "ci-fLJ3OwGs-py3.12", 42 | "language": "python", 43 | "name": "python3" 44 | }, 45 | "language_info": { 46 | "codemirror_mode": { 47 | "name": "ipython", 48 | "version": 3 49 | }, 50 | "file_extension": ".py", 51 | "mimetype": "text/x-python", 52 | "name": "python", 53 | "nbconvert_exporter": "python", 54 | "pygments_lexer": "ipython3", 55 | "version": "3.12.0" 56 | } 57 | }, 58 | "nbformat": 4, 59 | "nbformat_minor": 2 60 | } 61 | -------------------------------------------------------------------------------- /2023-24/lab9.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2023 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# LAB9\n", 17 | "\n", 18 | "Write a local-search algorithm (eg. an EA) able to solve the *Problem* instances 1, 2, 5, and 10 on a 1000-loci genomes, using a minimum number of fitness calls. That's all.\n", 19 | "\n", 20 | "### Deadlines:\n", 21 | "\n", 22 | "* Submission: Sunday, December 3 ([CET](https://www.timeanddate.com/time/zones/cet))\n", 23 | "* Reviews: Sunday, December 10 ([CET](https://www.timeanddate.com/time/zones/cet))\n", 24 | "\n", 25 | "Notes:\n", 26 | "\n", 27 | "* Reviews will be assigned on Monday, December 4\n", 28 | "* You need to commit in order to be selected as a reviewer (ie. better to commit an empty work than not to commit)" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 1, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "from random import choices\n", 38 | "\n", 39 | "import lab9_lib" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "metadata": {}, 46 | "outputs": [ 47 | { 48 | "name": "stdout", 49 | "output_type": "stream", 50 | "text": [ 51 | "10100011100011010000111011110010111110101011101100: 9.11%\n", 52 | "00100110000001100001100101101100111010100010111101: 7.33%\n", 53 | "01011111110101011011110010011000101101001101111000: 23.33%\n", 54 | "11011110011000110101111101101101101011010100010101: 9.11%\n", 55 | "01101000111110011100011011110100111011011111111001: 9.11%\n", 56 | "11000100110001001001111100011010011000001111010111: 15.33%\n", 57 | "01000110100000011000000101011001100100000011000000: 7.56%\n", 58 | "10111000100100000000110001100011110000010001011111: 17.56%\n", 59 | "00011000001001111101100100001111000000100101111100: 7.34%\n", 60 | "01111011100110011111110100101000000100011101010111: 15.33%\n", 61 | "10\n" 62 | ] 63 | } 64 | ], 65 | "source": [ 66 | "fitness = lab9_lib.make_problem(10)\n", 67 | "for n in range(10):\n", 68 | " ind = choices([0, 1], k=50)\n", 69 | " print(f\"{''.join(str(g) for g in ind)}: {fitness(ind):.2%}\")\n", 70 | "\n", 71 | "print(fitness.calls)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [] 80 | } 81 | ], 82 | "metadata": { 83 | "kernelspec": { 84 | "display_name": "ci-fLJ3OwGs-py3.12", 85 | "language": "python", 86 | "name": "python3" 87 | }, 88 | "language_info": { 89 | "codemirror_mode": { 90 | "name": "ipython", 91 | "version": 3 92 | }, 93 | "file_extension": ".py", 94 | "mimetype": "text/x-python", 95 | "name": "python", 96 | "nbconvert_exporter": "python", 97 | "pygments_lexer": "ipython3", 98 | "version": "3.12.0" 99 | } 100 | }, 101 | "nbformat": 4, 102 | "nbformat_minor": 2 103 | } 104 | -------------------------------------------------------------------------------- /2023-24/lab9_lib.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2023 Giovanni Squillero 2 | # https://github.com/squillero/computational-intelligence 3 | # Free for personal or classroom use; see 'LICENSE.md' for details. 4 | 5 | from abc import abstractmethod 6 | 7 | 8 | class AbstractProblem: 9 | def __init__(self): 10 | self._calls = 0 11 | 12 | @property 13 | @abstractmethod 14 | def x(self): 15 | pass 16 | 17 | @property 18 | def calls(self): 19 | return self._calls 20 | 21 | @staticmethod 22 | def onemax(genome): 23 | return sum(bool(g) for g in genome) 24 | 25 | def __call__(self, genome): 26 | self._calls += 1 27 | fitnesses = sorted((AbstractProblem.onemax(genome[s :: self.x]) for s in range(self.x)), reverse=True) 28 | val = sum(f for f in fitnesses if f == fitnesses[0]) - sum( 29 | f * (0.1 ** (k + 1)) for k, f in enumerate(f for f in fitnesses if f < fitnesses[0]) 30 | ) 31 | return val / len(genome) 32 | 33 | 34 | def make_problem(a): 35 | class Problem(AbstractProblem): 36 | @property 37 | @abstractmethod 38 | def x(self): 39 | return a 40 | 41 | return Problem() 42 | -------------------------------------------------------------------------------- /2023-24/pull-request.txt: -------------------------------------------------------------------------------- 1 | I follow the course. -------------------------------------------------------------------------------- /2023-24/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright © 2023 Giovanni Squillero 2 | # https://github.com/squillero/computational-intelligence 3 | # Free for personal or classroom use; see 'LICENSE.md' for details. 4 | 5 | [build-system] 6 | build-backend = "poetry.core.masonry.api" 7 | requires = ["poetry-core>=1.0.0"] 8 | 9 | [tool.poetry] 10 | authors = ["Giovanni Squillero "] 11 | description = "Code and Notebook dependencies for Computational Intelligence (2023-24)" 12 | license = "proprietary" 13 | name = "ci" 14 | version = "2023.1" 15 | 16 | [tool.poetry.dependencies] 17 | black = {extras = ["yupyter"], version = "^22.12.0"} 18 | jupyter = "^1.0.0" 19 | matplotlib = "^3.5.3" 20 | nero = {extras = ["jupyter"], version = "^1.0.20220202"} 21 | networkx = "^2.8.5" 22 | numpy = ">=1.23" 23 | pandas = "^1.4.3" 24 | pydot = "^1.4.2" 25 | python = ">=3.10" 26 | scipy = "^1.9.0" 27 | seaborn = "^0.11.2" 28 | toml = "^0.10.2" 29 | tqdm = "^4.64.0" 30 | isort = "^5.10.1" 31 | yapf = "^0.32.0" 32 | 33 | [tool.poetry.dev-dependencies] 34 | 35 | [tool.poetry.group.dev.dependencies] 36 | ipykernel = "^6.27.0" 37 | 38 | [tool.isort] 39 | profile = "black" 40 | 41 | 42 | 43 | [tool.black] 44 | target-version = ['py311'] 45 | extend-exclude = "^venv$" 46 | include = '(\.ipynb$|\.py$)' 47 | line-length = 120 48 | skip-string-normalization = true 49 | -------------------------------------------------------------------------------- /2023-24/quixo/main.py: -------------------------------------------------------------------------------- 1 | import random 2 | from game import Game, Move, Player 3 | 4 | 5 | class RandomPlayer(Player): 6 | def __init__(self) -> None: 7 | super().__init__() 8 | 9 | def make_move(self, game: 'Game') -> tuple[tuple[int, int], Move]: 10 | from_pos = (random.randint(0, 4), random.randint(0, 4)) 11 | move = random.choice([Move.TOP, Move.BOTTOM, Move.LEFT, Move.RIGHT]) 12 | return from_pos, move 13 | 14 | 15 | class MyPlayer(Player): 16 | def __init__(self) -> None: 17 | super().__init__() 18 | 19 | def make_move(self, game: 'Game') -> tuple[tuple[int, int], Move]: 20 | from_pos = (random.randint(0, 4), random.randint(0, 4)) 21 | move = random.choice([Move.TOP, Move.BOTTOM, Move.LEFT, Move.RIGHT]) 22 | return from_pos, move 23 | 24 | 25 | if __name__ == '__main__': 26 | g = Game() 27 | g.print() 28 | player1 = MyPlayer() 29 | player2 = RandomPlayer() 30 | winner = g.play(player1, player2) 31 | g.print() 32 | print(f"Winner: Player {winner}") 33 | -------------------------------------------------------------------------------- /2023-24/quixo/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.26.0 2 | -------------------------------------------------------------------------------- /2023-24/set-covering_single-state.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2023 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "from random import random, choice, randint\n", 19 | "from functools import reduce\n", 20 | "from collections import namedtuple\n", 21 | "from queue import PriorityQueue, SimpleQueue, LifoQueue\n", 22 | "from copy import copy\n", 23 | "\n", 24 | "import numpy as np" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 2, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "PROBLEM_SIZE = 1_000\n", 34 | "NUM_SETS = 5_000\n", 35 | "SETS = tuple(np.array([random() < 0.3 for _ in range(PROBLEM_SIZE)]) for _ in range(NUM_SETS))\n", 36 | "State = namedtuple('State', ['taken', 'not_taken'])" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 3, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "def fitness1(state):\n", 46 | " cost = sum(state)\n", 47 | " valid = np.all(\n", 48 | " reduce(\n", 49 | " np.logical_or,\n", 50 | " [SETS[i] for i, t in enumerate(state) if t],\n", 51 | " np.array([False for _ in range(PROBLEM_SIZE)]),\n", 52 | " )\n", 53 | " )\n", 54 | " return valid, -cost\n", 55 | "\n", 56 | "def fitness2(state):\n", 57 | " cost = sum(state)\n", 58 | " valid = np.sum(\n", 59 | " reduce(\n", 60 | " np.logical_or,\n", 61 | " [SETS[i] for i, t in enumerate(state) if t],\n", 62 | " np.array([False for _ in range(PROBLEM_SIZE)]),\n", 63 | " )\n", 64 | " )\n", 65 | " return valid, -cost\n", 66 | "\n", 67 | "fitness = fitness2" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 4, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "def tweak(state):\n", 77 | " new_state = copy(state)\n", 78 | " index = randint(0, PROBLEM_SIZE - 1)\n", 79 | " new_state[index] = not new_state[index]\n", 80 | " return new_state" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 5, 86 | "metadata": {}, 87 | "outputs": [ 88 | { 89 | "name": "stdout", 90 | "output_type": "stream", 91 | "text": [ 92 | "(0, 0)\n", 93 | "(295, -1)\n", 94 | "(492, -2)\n", 95 | "(641, -3)\n", 96 | "(760, -4)\n", 97 | "(833, -5)\n", 98 | "(880, -6)\n", 99 | "(914, -7)\n", 100 | "(937, -8)\n", 101 | "(954, -9)\n", 102 | "(970, -10)\n", 103 | "(982, -11)\n", 104 | "(985, -12)\n", 105 | "(991, -13)\n", 106 | "(993, -14)\n", 107 | "(994, -15)\n", 108 | "(996, -16)\n", 109 | "(997, -17)\n", 110 | "(998, -18)\n", 111 | "(999, -19)\n", 112 | "(1000, -20)\n", 113 | "(1000, -19)\n", 114 | "(1000, -18)\n", 115 | "(1000, -17)\n", 116 | "(1000, -16)\n", 117 | "(1000, -15)\n", 118 | "(1000, -14)\n" 119 | ] 120 | } 121 | ], 122 | "source": [ 123 | "current_state = [choice([False, False, False, False, False, False]) for _ in range(NUM_SETS)]\n", 124 | "print(fitness(current_state))\n", 125 | "\n", 126 | "for step in range(10_000):\n", 127 | " new_state = tweak(current_state)\n", 128 | " if fitness(new_state) >= fitness(current_state):\n", 129 | " current_state = new_state\n", 130 | " print(fitness(current_state))" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 7, 136 | "metadata": { 137 | "scrolled": true 138 | }, 139 | "outputs": [ 140 | { 141 | "data": { 142 | "text/plain": [ 143 | "[False, False, False, False, False, False, False, False, False, False]" 144 | ] 145 | }, 146 | "execution_count": 7, 147 | "metadata": {}, 148 | "output_type": "execute_result" 149 | } 150 | ], 151 | "source": [ 152 | "current_state" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": null, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [] 161 | } 162 | ], 163 | "metadata": { 164 | "kernelspec": { 165 | "display_name": "Python 3 (ipykernel)", 166 | "language": "python", 167 | "name": "python3" 168 | }, 169 | "language_info": { 170 | "codemirror_mode": { 171 | "name": "ipython", 172 | "version": 3 173 | }, 174 | "file_extension": ".py", 175 | "mimetype": "text/x-python", 176 | "name": "python", 177 | "nbconvert_exporter": "python", 178 | "pygments_lexer": "ipython3", 179 | "version": "3.11.2" 180 | } 181 | }, 182 | "nbformat": 4, 183 | "nbformat_minor": 4 184 | } 185 | -------------------------------------------------------------------------------- /2024-25/1-max.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2024 Giovanni Squillero `` \n", 8 | "`https://github.com/squillero/computational-intelligence` \n", 9 | "Free for personal or classroom use; see 'LICENCE.md' for details." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import random\n", 19 | "from icecream import ic" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 8, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "PROBLEM_SIZE = 100" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 9, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "def quality(solution):\n", 38 | " return max(sum(solution), PROBLEM_SIZE-sum(solution))\n", 39 | "\n", 40 | "\n", 41 | "def tweak(solution):\n", 42 | " new_solution = solution[:]\n", 43 | " pos = random.randrange(PROBLEM_SIZE)\n", 44 | " new_solution[pos] = 1 - new_solution[pos]\n", 45 | " return new_solution" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 10, 51 | "metadata": {}, 52 | "outputs": [ 53 | { 54 | "name": "stderr", 55 | "output_type": "stream", 56 | "text": [ 57 | "ic| quality(initial_solution): 53\n" 58 | ] 59 | } 60 | ], 61 | "source": [ 62 | "initial_solution = [random.randint(0, 1) for _ in range(PROBLEM_SIZE)]\n", 63 | "ic(quality(initial_solution))\n", 64 | "None" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 11, 70 | "metadata": {}, 71 | "outputs": [ 72 | { 73 | "name": "stderr", 74 | "output_type": "stream", 75 | "text": [ 76 | "ic| steps: 0, quality(current_solution): 53\n", 77 | "ic| steps: 502, quality(current_solution): 100\n" 78 | ] 79 | } 80 | ], 81 | "source": [ 82 | "current_solution = initial_solution\n", 83 | "steps = 0\n", 84 | "ic(steps, quality(current_solution))\n", 85 | "while quality(current_solution) < PROBLEM_SIZE:\n", 86 | " steps += 1\n", 87 | " solution = tweak(current_solution)\n", 88 | " if quality(solution) > quality(current_solution):\n", 89 | " current_solution = solution\n", 90 | "ic(steps, quality(current_solution))\n", 91 | "None" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 13, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "name": "stderr", 101 | "output_type": "stream", 102 | "text": [ 103 | "ic| current_solution[0]: 0\n" 104 | ] 105 | }, 106 | { 107 | "data": { 108 | "text/plain": [ 109 | "0" 110 | ] 111 | }, 112 | "execution_count": 13, 113 | "metadata": {}, 114 | "output_type": "execute_result" 115 | } 116 | ], 117 | "source": [ 118 | "ic(current_solution[0])" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 14, 124 | "metadata": {}, 125 | "outputs": [ 126 | { 127 | "name": "stderr", 128 | "output_type": "stream", 129 | "text": [ 130 | "ic| steps: 0, quality(current_solution): 53\n", 131 | "ic| steps: 640, quality(current_solution): 100\n" 132 | ] 133 | } 134 | ], 135 | "source": [ 136 | "current_solution = initial_solution\n", 137 | "steps = 0\n", 138 | "ic(steps, quality(current_solution))\n", 139 | "while quality(current_solution) < PROBLEM_SIZE:\n", 140 | " temp = current_solution[:]\n", 141 | " best_so_far = current_solution[:]\n", 142 | " for inner_step in range(10):\n", 143 | " steps += 1\n", 144 | " solution = tweak(current_solution)\n", 145 | " if quality(solution) > quality(best_so_far):\n", 146 | " best_so_far = solution\n", 147 | " # temp = solution\n", 148 | " if quality(best_so_far) > quality(current_solution):\n", 149 | " current_solution = best_so_far\n", 150 | "ic(steps, quality(current_solution))\n", 151 | "None" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 15, 157 | "metadata": {}, 158 | "outputs": [ 159 | { 160 | "name": "stderr", 161 | "output_type": "stream", 162 | "text": [ 163 | "ic| current_solution[0]: 0\n" 164 | ] 165 | }, 166 | { 167 | "data": { 168 | "text/plain": [ 169 | "0" 170 | ] 171 | }, 172 | "execution_count": 15, 173 | "metadata": {}, 174 | "output_type": "execute_result" 175 | } 176 | ], 177 | "source": [ 178 | "ic(current_solution[0])" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": null, 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [] 187 | } 188 | ], 189 | "metadata": { 190 | "kernelspec": { 191 | "display_name": "ci-WEKR9SVn-py3.12", 192 | "language": "python", 193 | "name": "python3" 194 | }, 195 | "language_info": { 196 | "codemirror_mode": { 197 | "name": "ipython", 198 | "version": 3 199 | }, 200 | "file_extension": ".py", 201 | "mimetype": "text/x-python", 202 | "name": "python", 203 | "nbconvert_exporter": "python", 204 | "pygments_lexer": "ipython3", 205 | "version": "3.12.6" 206 | } 207 | }, 208 | "nbformat": 4, 209 | "nbformat_minor": 2 210 | } 211 | -------------------------------------------------------------------------------- /2024-25/cities/italy.csv: -------------------------------------------------------------------------------- 1 | "Ancona",43.6,13.5 2 | "Andria",41.230000000000004,16.29 3 | "Bari",41.12,16.87 4 | "Bergamo",45.7,9.67 5 | "Bologna",44.5,11.34 6 | "Bolzano",46.5,11.35 7 | "Brescia",45.550000000000004,10.22 8 | "Cagliari",39.22,9.1 9 | "Catania",37.5,15.08 10 | "Ferrara",44.84,11.61 11 | "Florence",43.78,11.24 12 | "Foggia",41.47,15.55 13 | "Forlì",44.22,12.030000000000001 14 | "Genoa",44.42,8.93 15 | "Giugliano in Campania",40.93,14.19 16 | "Latina",41.47,12.89 17 | "Leghorn",43.550000000000004,10.3 18 | "Messina",38.19,15.55 19 | "Milan",45.47,9.17 20 | "Modena",44.65,10.92 21 | "Monza",45.58,9.27 22 | "Naples",40.85,14.27 23 | "Novara",45.45,8.620000000000001 24 | "Padua",45.410000000000004,11.870000000000001 25 | "Palermo",38.12,13.36 26 | "Parma",44.81,10.32 27 | "Perugia",43.11,12.39 28 | "Pescara",42.46,14.21 29 | "Piacenza",45.06,9.68 30 | "Prato",43.89,11.09 31 | "Ravenna",44.42,12.21 32 | "Reggio di Calabria",38.11,15.65 33 | "Reggio nell'Emilia",44.71,10.63 34 | "Rimini",44.06,12.57 35 | "Rome",41.89,12.5 36 | "Salerno",40.68,14.77 37 | "Sassari",40.730000000000004,8.56 38 | "Syracuse",37.07,15.290000000000001 39 | "Taranto",40.480000000000004,17.240000000000002 40 | "Terni",42.57,12.65 41 | "Trento",46.08,11.120000000000001 42 | "Trieste",45.65,13.77 43 | "Turin",45.08,7.68 44 | "Venice",45.43,12.33 45 | "Verona",45.44,10.99 46 | "Vicenza",45.550000000000004,11.540000000000001 47 | -------------------------------------------------------------------------------- /2024-25/cities/russia.csv: -------------------------------------------------------------------------------- 1 | "Abakan",53.72,91.43 2 | "Achinsk",56.28,90.5 3 | "Almetyevsk",54.9,52.31 4 | "Angarsk",52.57,103.91 5 | "Arkhangelsk",64.57000000000001,40.53 6 | "Armavir",44.99,41.12 7 | "Artyom",43.36,132.18 8 | "Arzamas",55.38,43.82 9 | "Astrakhan",46.35,48.050000000000004 10 | "Balakovo",52.03,47.78 11 | "Balashikha",55.800000000000004,37.95 12 | "Barnaul",53.36,83.75 13 | "Bataysk",47.14,39.75 14 | "Belgorod",50.61,36.59 15 | "Berezniki",59.410000000000004,56.77 16 | "Biysk",52.53,85.17 17 | "Blagoveshchensk",50.27,127.53 18 | "Bratsk",56.300000000000004,101.71000000000001 19 | "Bryansk",53.26,34.42 20 | "Cheboksary",56.13,47.25 21 | "Chelyabinsk",55.15,61.43 22 | "Cherepovets",59.13,37.9 23 | "Cherkessk",44.29,42.06 24 | "Chita",52.050000000000004,113.46000000000001 25 | "Derbent",42.06,48.29 26 | "Dimitrovgrad",54.25,49.550000000000004 27 | "Dzerzhinsk",56.24,43.46 28 | "Elektrostal",55.79,38.44 29 | "Elista",46.32,44.21 30 | "Engels",51.5,46.12 31 | "Groznyy",43.31,45.7 32 | "Irkutsk",52.33,104.24000000000001 33 | "Ivanovo",57.01,40.99 34 | "Izhevsk",56.85,53.230000000000004 35 | "Kaliningrad",54.71,20.5 36 | "Kaluga",54.54,36.27 37 | "Kamensk‐Uralskiy",56.410000000000004,61.93 38 | "Kamyshin",50.1,45.4 39 | "Kaspiysk",42.88,47.64 40 | "Kazan",55.75,49.13 41 | "Kemerovo",55.33,86.08 42 | "Khabarovsk",48.42,135.12 43 | "Khasavyurt",43.25,46.59 44 | "Khimki",55.89,37.44 45 | "Kirov",58.6,49.660000000000004 46 | "Kislovodsk",43.910000000000004,42.72 47 | "Kolomna",55.08,38.78 48 | "Kolpino",59.75,30.6 49 | "Komsomolsk‐na‐Amure",50.56,137. 50 | "Kopeysk",55.11,61.65 51 | "Korolyov",55.92,37.82 52 | "Kostroma",57.77,40.93 53 | "Kovrov",56.36,41.32 54 | "Krasnodar",45.03,38.980000000000004 55 | "Krasnoyarsk",56.02,93.06 56 | "Kurgan",55.45,65.33 57 | "Kursk",51.730000000000004,36.19 58 | "Kyzyl",51.71,94.38 59 | "Leninsk‐Kuznetskiy",54.660000000000004,86.16 60 | "Lipetsk",52.620000000000005,39.62 61 | "Lyubertsy",55.67,37.89 62 | "Magadan",59.57,150.8 63 | "Magnitogorsk",53.42,58.97 64 | "Makhachkala",42.980000000000004,47.5 65 | "Maykop",44.61,40.11 66 | "Miass",55.,60.09 67 | "Moscow",55.75,37.62 68 | "Murmansk",68.96000000000001,33.08 69 | "Murom",55.57,42.04 70 | "Mytishchi",55.910000000000004,37.730000000000004 71 | "Naberezhnye Chelny",55.69,52.32 72 | "Nakhodka",42.83,132.89000000000001 73 | "Nalchik",43.5,43.62 74 | "Nazran",43.21,44.800000000000004 75 | "Neftekamsk",56.08,54.27 76 | "Nefteyugansk",61.08,72.7 77 | "Nevinnomyssk",44.63,41.95 78 | "Nizhnekamsk",55.64,51.82 79 | "Nizhnevartovsk",60.93,76.57000000000001 80 | "Nizhniy Tagil",57.92,59.97 81 | "Nizhny Novgorod",56.33,44. 82 | "Noginsk",55.85,38.44 83 | "Norilsk",69.34,88.22 84 | "Novocheboksarsk",56.120000000000005,47.5 85 | "Novocherkassk",47.42,40.09 86 | "Novokuybyshevsk",53.11,49.93 87 | "Novokuznetsk",53.75,87.10000000000001 88 | "Novomoskovsk",54.09,38.22 89 | "Novorossiysk",44.72,37.77 90 | "Novoshakhtinsk",47.75,39.94 91 | "Novosibirsk",55.04,82.93 92 | "Novotroitsk",51.21,58.32 93 | "Novyy Urengoy",66.09,76.51 94 | "Noyabrsk",63.17,75.62 95 | "Obninsk",55.1,36.61 96 | "Odintsovo",55.67,37.29 97 | "Oktyabrskiy",54.47,53.46 98 | "Omsk",55.,73.4 99 | "Orekhovo‐Zuevo",55.82,38.980000000000004 100 | "Orenberg",51.783333,55.1 101 | "Orenburg",51.78,55.1 102 | "Orsk",51.21,58.63 103 | "Oryol",52.97,36.08 104 | "Penza",53.2,45. 105 | "Perm",58.,56.25 106 | "Pervouralsk",56.910000000000004,59.95 107 | "Petropavlovsk‐Kamchatskiy",53.02,158.65 108 | "Petrozavodsk",61.82,34.33 109 | "Podolsk",55.42,37.54 110 | "Prokopyevsk",53.9,86.71000000000001 111 | "Pskov",57.83,28.330000000000002 112 | "Pyatigorsk",44.050000000000004,43.06 113 | "Rostov‐na‐Donu",47.24,39.71 114 | "Rubtsovsk",51.53,81.2 115 | "Ryazan",54.620000000000005,39.74 116 | "Rybinsk",58.050000000000004,38.83 117 | "Saint Petersburg",59.93,30.32 118 | "Salavat",53.370000000000005,55.92 119 | "Samara",53.2,50.15 120 | "Saransk",54.18,45.18 121 | "Saratov",51.57,46.03 122 | "Sergiyev Posad",56.32,38.13 123 | "Serpukhov",54.92,37.410000000000004 124 | "Severodvinsk",64.57000000000001,39.83 125 | "Seversk",56.61,84.83 126 | "Shakhty",47.71,40.21 127 | "Shchyolkovo",55.9,38.02 128 | "Smolensk",54.78,32.04 129 | "Sochi",43.6,39.730000000000004 130 | "Staryy Oskol",51.300000000000004,37.84 131 | "Stavropol",45.04,41.97 132 | "Sterlitamak",53.63,55.95 133 | "Surgut",61.25,73.42 134 | "Syktyvkar",61.67,50.81 135 | "Syzran",53.17,48.47 136 | "Taganrog",47.22,38.910000000000004 137 | "Tambov",52.730000000000004,41.43 138 | "Tobolsk",58.2,68.27 139 | "Tolyatti",53.480000000000004,49.51 140 | "Tomsk",56.5,84.97 141 | "Tula",54.2,37.61 142 | "Tver",56.86,35.89 143 | "Tyumen",57.15,65.53 144 | "Ufa",54.78,56.04 145 | "Ulan‐Ude",51.83,107.62 146 | "Ulyanovsk",54.33,48.4 147 | "Ussuriysk",43.800000000000004,132.01 148 | "Velikie Luki",56.34,30.53 149 | "Velikiy Novgorod",58.52,31.28 150 | "Vladikavkaz",43.04,44.68 151 | "Vladimir",56.14,40.4 152 | "Vladivostok",43.13,131.9 153 | "Volgodonsk",47.51,42.15 154 | "Volgograd",48.71,44.480000000000004 155 | "Vologda",59.22,39.9 156 | "Volzhskiy",48.79,44.77 157 | "Voronezh",51.72,39.26 158 | "Yakutsk",62.03,129.73 159 | "Yaroslavl",57.620000000000005,39.87 160 | "Yekaterinburg",56.85,60.6 161 | "Yelets",52.6,38.51 162 | "Yoshkar‐Ola",56.64,47.870000000000005 163 | "Yuzhno‐Sakhalinsk",46.95,142.74 164 | "Zelenograd",55.94,37.29 165 | "Zheleznodorozhnyy",55.75,38.0167 166 | "Zhukovskiy",55.550000000000004,38.25 167 | "Zlatoust",55.17,59.65 168 | -------------------------------------------------------------------------------- /2024-25/cities/vanuatu.csv: -------------------------------------------------------------------------------- 1 | "Isangel",-19.53,169.28 2 | "Lakatoro",-16.09,167.4 3 | "Longana",-15.3,168. 4 | "Luganville",-15.51,167.15 5 | "Norsup",-16.07,167.39000000000001 6 | "Port Olry",-15.05,167.05 7 | "Sola",-13.870000000000001,167.55 8 | "Vila",-17.74,168.31 9 | -------------------------------------------------------------------------------- /2024-25/contrib/poetry_installation_guide/README.md: -------------------------------------------------------------------------------- 1 | > **Author:** Daniel Bologna s310582 2 | > **Last update:** 26-09-2024:11.30 3 | 4 | # venv + Poetry installation 5 | 6 | - [venv + Poetry installation](#venv--poetry-installation) 7 | - [Intro](#intro) 8 | - [Python installation](#python-installation) 9 | - [Windows powershell setup](#windows-powershell-setup) 10 | - [Virtual environment](#virtual-environment) 11 | - [Setting up vscode](#setting-up-vscode) 12 | - [Creating a Virtual environment using venv](#creating-a-virtual-environment-using-venv) 13 | - [Activate the environment](#activate-the-environment) 14 | - [Install poetry](#install-poetry) 15 | - [Downalod the .toml file for the course](#downalod-the-toml-file-for-the-course) 16 | - [Configure poetry](#configure-poetry) 17 | - [jupyter](#jupyter) 18 | - [Create jupyter notebook](#create-jupyter-notebook) 19 | - [Select the interpreter](#select-the-interpreter) 20 | - [Credits](#credits) 21 | 22 | ## Intro 23 | 24 | Hi, this is how I installed poetry inside a virtual environment in my **windows machine**. It may not work for everyone! 25 | 26 | > This guide is intended for those taking the Computational Intelligence 24/25 course at Turin Polytechnic. 27 | 28 | ## Python installation 29 | 30 | This is not a python installation guide but I'll leave some resources that may help you: 31 | 32 | - https://www.python.org/ 33 | - https://apps.microsoft.com/detail/9pjpw5ldxlz5?hl=en-US&gl=US 34 | 35 | ## Windows powershell setup 36 | 37 | By default windows' powershell does not allow running .ps1 scripts. To list/enable/disable this feature we can run the following commands on the powershell: 38 | 39 | ``` 40 | // list all the policies 41 | Get-ExecutionPolicy -ExecutionPolicy -List 42 | 43 | // enable the current user 44 | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser 45 | 46 | // remove permission to the current user 47 | Set-ExecutionPolicy -ExecutionPolicy Undefined -Scope CurrentUser 48 | ``` 49 | 50 | check [about_Execution_Policies](https://learn.microsoft.com/it-it/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4) for more details. 51 | 52 | ## Virtual environment 53 | As stated in the [poetry docs](https://python-poetry.org/docs/): 54 | 55 | > *Poetry should always be installed in a dedicated virtual environment to isolate it from the rest of your system. It should in no case be installed in the environment of the project that is to be managed by Poetry. This ensures that Poetry’s own dependencies will not be accidentally upgraded or uninstalled.* 56 | 57 | 58 | ### Setting up vscode 59 | 60 | Open visual studio code in your desired folder. Then open the terminal 61 | 62 | 63 | >Terminal -> New Terminal 64 | > 65 | >or 66 | > 67 | >ctrl + ò 68 | 69 | Check [Getting started with the terminal](https://code.visualstudio.com/docs/terminal/getting-started#:~:text=Open%20the%20terminal%20by%20selecting,the%20Ctrl%2B%60%20keyboard%20shortcut.). 70 | 71 | You should see a powershell terminal opened in your interface: 72 | 73 | ![](imgs/p1.png) 74 | 75 | ### Creating a Virtual environment using venv 76 | 77 | > ⚠️ for the following step always remain in the your working folder. 78 | 79 | In the just opened terminal use the following command: 80 | 81 | ``` 82 | python -m venv 83 | ``` 84 | 85 | A new folder with `` should appear: 86 | 87 | ![](imgs/p2.png) 88 | 89 | Check [venv — Creation of virtual environments](https://docs.python.org/3/library/venv.html) for more info. 90 | 91 | ### Activate the environment 92 | 93 | In the terminal write: 94 | 95 | ``` 96 | .\\Scripts\Activate.ps1 97 | ``` 98 | 99 | to activate the environment 100 | 101 | ![](imgs/p3.png) 102 | 103 | > to exit from the environment just type 104 | > 105 | > ``` 106 | > deactivate 107 | > ``` 108 | 109 | ## Install poetry 110 | 111 | While **having the venv activated**, use pip to install poetry: 112 | 113 | ``` 114 | pip install poetry 115 | ``` 116 | 117 | ### Downalod the .toml file for the course 118 | 119 | To configure the project we need the .toml file with all the required packages. We can use the one in [Professor Squillero's Repository](https://github.com/squillero/computational-intelligence/blob/master/2024-25/pyproject.toml). 120 | Download the file and put it inside your project folder (NOT inside the venv folder). 121 | 122 | ``` 123 | . 124 | └── ProjectFolder/ 125 | ├── / 126 | │ ├── Include/ 127 | │ ├── Lib/ 128 | │ ├── Scripts/ 129 | │ └── pyvenv.cfg 130 | ├── 131 | └── pyproject.toml 132 | ``` 133 | 134 | ### Configure poetry 135 | 136 | Now we can run the following command to tell poetry to use the .toml file to download all the required packages: 137 | 138 | ``` 139 | peotry install 140 | ``` 141 | 142 | It will take some time to download all the files. You can check in `/Lib/` if the packages and dependencies are correctly installed. 143 | 144 | After installation you're good to go! 145 | 146 | ## jupyter 147 | 148 | To conclude this guide let's create a notebook and set the new environment we created before as the current kernel. 149 | 150 | ### Create jupyter notebook 151 | 152 | Create a .ipynb file in your folder and then open it. 153 | 154 | ### Select the interpreter 155 | 156 | In the top right corner of the file view we can see a "select kernel" button. 157 | 158 | ![](imgs/p4.png) 159 | 160 | Click it and a pop up dialg window should appear. Click Python Environment 161 | 162 | ![](imgs/p5.png) 163 | 164 | Then select your newly created environment 165 | 166 | ![](imgs/p6.png) 167 | 168 | You're all done now! Try some code and check if all the file works. 169 | 170 | ## Credits 171 | 172 | - [python website](https://www.python.org/) 173 | - [python on the microsoft store](https://apps.microsoft.com/detail/9pjpw5ldxlz5?hl=en-US&gl=US) 174 | - [about_Execution_Policies](https://learn.microsoft.com/it-it/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4) 175 | - [poetry docs](https://python-poetry.org/docs/) 176 | - [Getting started with the terminal](https://code.visualstudio.com/docs/terminal/getting-started#:~:text=Open%20the%20terminal%20by%20selecting,the%20Ctrl%2B%60%20keyboard%20shortcut.) 177 | - [venv — Creation of virtual environments](https://docs.python.org/3/library/venv.html) 178 | - [Professor Squillero's Repository](https://github.com/squillero/computational-intelligence/blob/master/2024-25/pyproject.toml) -------------------------------------------------------------------------------- /2024-25/contrib/poetry_installation_guide/imgs/p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/contrib/poetry_installation_guide/imgs/p1.png -------------------------------------------------------------------------------- /2024-25/contrib/poetry_installation_guide/imgs/p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/contrib/poetry_installation_guide/imgs/p2.png -------------------------------------------------------------------------------- /2024-25/contrib/poetry_installation_guide/imgs/p3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/contrib/poetry_installation_guide/imgs/p3.png -------------------------------------------------------------------------------- /2024-25/contrib/poetry_installation_guide/imgs/p4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/contrib/poetry_installation_guide/imgs/p4.png -------------------------------------------------------------------------------- /2024-25/contrib/poetry_installation_guide/imgs/p5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/contrib/poetry_installation_guide/imgs/p5.png -------------------------------------------------------------------------------- /2024-25/contrib/poetry_installation_guide/imgs/p6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/contrib/poetry_installation_guide/imgs/p6.png -------------------------------------------------------------------------------- /2024-25/golang-demos/.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | /shortest-path/demo-sp 6 | 7 | *.exe 8 | *.exe~ 9 | *.dll 10 | *.so 11 | *.dylib 12 | 13 | # Test binary, built with `go test -c` 14 | *.test 15 | 16 | # Output of the go coverage tool, specifically when used with LiteIDE 17 | *.out 18 | 19 | # Dependency directories (remove the comment below to include it) 20 | # vendor/ 21 | 22 | # Go workspace file 23 | go.work 24 | go.work.sum 25 | 26 | # env file 27 | .env 28 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/go.mod: -------------------------------------------------------------------------------- 1 | module demo-sp 2 | 3 | go 1.21 4 | 5 | require github.com/hajimehoshi/ebiten/v2 v2.7.8 6 | 7 | require ( 8 | github.com/ebitengine/gomobile v0.0.0-20240518074828-e86332849895 // indirect 9 | github.com/ebitengine/hideconsole v1.0.0 // indirect 10 | github.com/ebitengine/purego v0.7.0 // indirect 11 | github.com/go-text/typesetting v0.1.1-0.20240325125605-c7936fe59984 // indirect 12 | github.com/jezek/xgb v1.1.1 // indirect 13 | golang.org/x/image v0.18.0 // indirect 14 | golang.org/x/sync v0.7.0 // indirect 15 | golang.org/x/sys v0.20.0 // indirect 16 | golang.org/x/text v0.16.0 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/go.sum: -------------------------------------------------------------------------------- 1 | github.com/ebitengine/gomobile v0.0.0-20240518074828-e86332849895 h1:48bCqKTuD7Z0UovDfvpCn7wZ0GUZ+yosIteNDthn3FU= 2 | github.com/ebitengine/gomobile v0.0.0-20240518074828-e86332849895/go.mod h1:XZdLv05c5hOZm3fM2NlJ92FyEZjnslcMcNRrhxs8+8M= 3 | github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE= 4 | github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A= 5 | github.com/ebitengine/purego v0.7.0 h1:HPZpl61edMGCEW6XK2nsR6+7AnJ3unUxpTZBkkIXnMc= 6 | github.com/ebitengine/purego v0.7.0/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= 7 | github.com/go-text/typesetting v0.1.1-0.20240325125605-c7936fe59984 h1:NwCC36eQsDf1xVZG9jD7ngXNNjsvk8KXky15ogA1Vo0= 8 | github.com/go-text/typesetting v0.1.1-0.20240325125605-c7936fe59984/go.mod h1:2+owI/sxa73XA581LAzVuEBZ3WEEV2pXeDswCH/3i1I= 9 | github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66 h1:GUrm65PQPlhFSKjLPGOZNPNxLCybjzjYBzjfoBGaDUY= 10 | github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= 11 | github.com/hajimehoshi/bitmapfont/v3 v3.0.0 h1:r2+6gYK38nfztS/et50gHAswb9hXgxXECYgE8Nczmi4= 12 | github.com/hajimehoshi/bitmapfont/v3 v3.0.0/go.mod h1:+CxxG+uMmgU4mI2poq944i3uZ6UYFfAkj9V6WqmuvZA= 13 | github.com/hajimehoshi/ebiten/v2 v2.7.8 h1:QrlvF2byCzMuDsbxFReJkOCbM3O2z1H/NKQaGcA8PKk= 14 | github.com/hajimehoshi/ebiten/v2 v2.7.8/go.mod h1:Ulbq5xDmdx47P24EJ+Mb31Zps7vQq+guieG9mghQUaA= 15 | github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4= 16 | github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= 17 | golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= 18 | golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= 19 | golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= 20 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 21 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= 22 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 23 | golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= 24 | golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 25 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/graph/graph.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package graph 6 | 7 | import ( 8 | "demo-sp/randy" 9 | "demo-sp/viz" 10 | "math" 11 | "sort" 12 | ) 13 | 14 | type Graph struct { 15 | CanvasSize int 16 | Nodes []viz.Point 17 | Edges [][]float64 18 | } 19 | 20 | func distance(cities []viz.Point, c1 int, c2 int) float64 { 21 | return math.Sqrt(math.Pow(float64(cities[c1].X-cities[c2].X), 2) + math.Pow(float64(cities[c1].Y-cities[c2].Y), 2)) 22 | } 23 | 24 | func (g *Graph) Distance(c1 int, c2 int) float64 { 25 | return distance(g.Nodes, c1, c2) 26 | } 27 | 28 | func (g *Graph) Initialize(numNodes int, edgeProbability float64) { 29 | 30 | // Nodes 31 | g.Nodes = make([]viz.Point, numNodes) 32 | cs := float32(g.CanvasSize) 33 | g.Nodes[0] = viz.Point{X: cs * .05, Y: cs * .95} // source: first node 34 | g.Nodes[numNodes-1] = viz.Point{X: cs * .95, Y: cs * .05} // destination: last node 35 | for t := 1; t < numNodes-1; { 36 | g.Nodes[t] = viz.Point{X: cs * randy.R.Float32(), Y: cs * randy.R.Float32()} 37 | if g.Distance(t, g.nearest(t)) > float64(cs/5)/float64(numNodes) { 38 | t++ 39 | } 40 | } 41 | // Edges 42 | g.Edges = make([][]float64, numNodes) 43 | for i := range g.Edges { 44 | g.Edges[i] = make([]float64, numNodes) 45 | } 46 | // create a safe, yet terribly long path from source to destination 47 | for c := 0; c < numNodes-1; c++ { 48 | g.Edges[c][c+1] = g.Distance(c, c+1) 49 | } 50 | // add random Edges 51 | for n0 := 0; n0 < numNodes; n0++ { 52 | n := g.NodesSorted(n0) 53 | for t := 0; t < numNodes-1 && (t == 0 || randy.R.Float64() < edgeProbability); t++ { 54 | g.Edges[n0][n[t]] = distance(g.Nodes, n0, n[t]) 55 | g.Edges[n[t]][n0] = g.Edges[n0][n[t]] 56 | } 57 | } 58 | } 59 | 60 | func (g *Graph) NodesSorted(v int) []int { 61 | // return the list of nodes sorted by distance from vertex v 62 | n := make([]struct { 63 | v int 64 | d float64 65 | }, len(g.Nodes)) 66 | for i := range n { 67 | n[i].v = i 68 | n[i].d = g.Distance(v, i) 69 | } 70 | sort.Slice(n, func(i, j int) bool { 71 | return n[i].d < n[j].d 72 | }) 73 | r := make([]int, len(g.Nodes)-1) 74 | for i := 1; i < len(g.Nodes); i++ { 75 | r[i-1] = n[i].v 76 | } 77 | return r 78 | } 79 | 80 | func (g *Graph) PathLength(path []int) float64 { 81 | length := 0.0 82 | for i := 0; i < len(path)-1; i++ { 83 | length += g.Edges[path[i]][path[i+1]] 84 | } 85 | return length 86 | } 87 | 88 | func (g *Graph) DrawPath(feed chan<- interface{}, path []int, tag int32) { 89 | p := make([]viz.Point, len(path)) 90 | for s := 0; s < len(path); s++ { 91 | p[s] = g.Nodes[path[s]] 92 | } 93 | for i := 0; i < len(path)-1; i++ { 94 | feed <- viz.TaggedVanishingPolyline{Tag: tag, Polyline: viz.Polyline{Points: p}} 95 | } 96 | } 97 | 98 | func (g *Graph) Neighbors(v int) []int { 99 | r := make([]int, 0) 100 | for i := 0; i < len(g.Nodes); i++ { 101 | if g.Edges[v][i] > 0 { 102 | r = append(r, i) 103 | } 104 | } 105 | return r 106 | } 107 | 108 | func (g *Graph) NearestNeighbors(v int) []int { 109 | r := make([]int, 0) 110 | for _, i := range g.NodesSorted(v) { 111 | if g.Edges[v][i] > 0 { 112 | r = append(r, i) 113 | } 114 | } 115 | return r 116 | } 117 | 118 | func (g *Graph) nearest(v int) int { 119 | var nearest int = 0 120 | 121 | if nearest == v { 122 | nearest++ 123 | } 124 | for i := 0; i < len(g.Nodes); i++ { 125 | if i != v && g.Distance(i, v) < g.Distance(nearest, v) { 126 | nearest = i 127 | } 128 | } 129 | return nearest 130 | } 131 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/main.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package main 6 | 7 | import ( 8 | "demo-sp/graph" 9 | "demo-sp/randy" 10 | "demo-sp/solvers" 11 | "demo-sp/viz" 12 | "flag" 13 | "log" 14 | "log/slog" 15 | "math/rand/v2" 16 | "time" 17 | ) 18 | 19 | const ( 20 | CanvasSize int = 1000 21 | WindowSize int = 800 22 | ) 23 | 24 | func main() { 25 | log.SetPrefix("CI24 ") // 🐁 26 | log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lmsgprefix | log.LUTC) 27 | 28 | // command line arguments 29 | verbose := flag.Bool("v", false, "Verbose operations") 30 | seed := flag.Uint64("r", 42, "Random seed") 31 | numNodes := flag.Int("n", 10, "Number of nodes") 32 | edgeProbability := flag.Float64("e", .5, "Edge probability") 33 | flag.Parse() 34 | if *verbose { 35 | slog.SetLogLoggerLevel(slog.LevelDebug) 36 | } 37 | if *seed == 0 { 38 | randy.R = rand.New(rand.NewPCG(uint64(float64(*numNodes) / *edgeProbability), 39 | uint64(time.Now().UTC().UnixNano()))) 40 | } else { 41 | randy.R = rand.New(rand.NewPCG(*seed, uint64(float64(*numNodes) / *edgeProbability))) 42 | } 43 | 44 | slog.Debug("Computational Intelligence 🐹 2024/25!") 45 | slog.Debug("Using random", "seed", *seed) 46 | 47 | // all passed by reference... 48 | feed := make(chan interface{}, 1000) 49 | graph := &graph.Graph{CanvasSize: CanvasSize} 50 | graph.Initialize(*numNodes, *edgeProbability) 51 | 52 | go func() { 53 | for n1 := 0; n1 < *numNodes; n1 += 1 { 54 | feed <- viz.ColoredCircle{Color: viz.ColorMidnightBlue, Center: graph.Nodes[n1], Radius: 5} 55 | for n2 := n1 + 1; n2 < *numNodes; n2 += 1 { 56 | if graph.Edges[n1][n2] > 0 { 57 | feed <- viz.ColoredPolyline{Color: viz.ColorMidnightBlue, 58 | Polyline: viz.Polyline{Points: []viz.Point{graph.Nodes[n1], graph.Nodes[n2]}}} 59 | } 60 | } 61 | } 62 | }() 63 | 64 | //go func() { 65 | // tag++ 66 | // solvers.GreedyRandom(graph, feed, tag) 67 | //}() 68 | 69 | //go func() { 70 | // tag++ 71 | // solvers.GreedyLazy(graph, feed, tag) 72 | //}() 73 | 74 | //go func() { 75 | // tag++ 76 | // solvers.GreedyInformed(graph, feed, tag) 77 | //}() 78 | 79 | go func() { 80 | var tag int32 = 0 81 | known := make([]int, len(graph.Nodes)) 82 | for s := 0; s < len(graph.Nodes); s++ { 83 | known[s] = s 84 | } 85 | solvers.BranchNBound(graph, feed, tag, known) 86 | }() 87 | 88 | //go func() { 89 | // var tag int32 = 0 90 | // known := solvers.GreedyRandom(graph, feed, tag) 91 | // solvers.BranchNBound(graph, feed, tag, known) 92 | //}() 93 | 94 | //go func() { 95 | // var tag int32 = 1 96 | // known := solvers.GreedyLazy(graph, feed, tag) 97 | // solvers.BranchNBound(graph, feed, tag, known) 98 | //}() 99 | 100 | //go func() { 101 | // var tag int32 = 2 102 | // known := solvers.GreedyInformed(graph, feed, tag) 103 | // solvers.BranchNBound(graph, feed, tag, known) 104 | //}() 105 | 106 | go solvers.AStarSearch(graph, feed, 1) 107 | go solvers.GreedySearch(graph, feed, 2) 108 | go solvers.DepthFirstSearch(graph, feed, 3) 109 | go solvers.BreadthFirstSearch(graph, feed, 4) 110 | go solvers.UniformCostSearch(graph, feed, 5) 111 | 112 | viz.Run(feed, "Computational Intelligence 🐹 2024/25", CanvasSize, WindowSize) 113 | //britishMuseum(graph) 114 | } 115 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/randy/rand.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package randy 6 | 7 | import "math/rand/v2" 8 | 9 | var R *rand.Rand 10 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/solvers/branch-n-bound.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package solvers 6 | 7 | import ( 8 | "demo-sp/graph" 9 | "demo-sp/viz" 10 | "golang.org/x/text/language" 11 | "golang.org/x/text/message" 12 | ) 13 | 14 | type bnbStatus struct { 15 | graph *graph.Graph 16 | feed chan<- interface{} 17 | tag int32 18 | current []int 19 | best []int 20 | steps int32 21 | pp *message.Printer 22 | } 23 | 24 | func BranchNBound(graph *graph.Graph, feed chan<- interface{}, tag int32, knownSolution []int) []int { 25 | // British Museum algorithm -- see: https://en.wikipedia.org/wiki/British_Museum_algorithm 26 | 27 | feed <- viz.TaggedText{Tag: tag, Text: "Branch n' Bound"} 28 | status := &bnbStatus{ 29 | graph: graph, 30 | feed: feed, 31 | tag: tag, 32 | current: make([]int, 1, len(graph.Nodes)), // 1 element, set cap to nNodes 33 | best: knownSolution, // nNodes elems 34 | steps: 0, 35 | pp: message.NewPrinter(language.English), 36 | } 37 | status.current[0] = 0 38 | status.feed <- viz.TaggedText{Tag: status.tag, Text: status.pp.Sprintf("BnB: %.2f (%d) — Warming up...", 39 | status.graph.PathLength(status.best), len(status.best)-1)} 40 | bnbStep(status) 41 | status.feed <- viz.TaggedText{Tag: status.tag, Text: status.pp.Sprintf("BnB: %.2f (%d) — Completed in %d steps", 42 | status.graph.PathLength(status.best), len(status.best)-1, status.steps)} 43 | return status.best 44 | } 45 | 46 | func bnbStep(s *bnbStatus) { 47 | s.steps++ 48 | last := s.current[len(s.current)-1] 49 | if last == len(s.graph.Nodes)-1 { 50 | if s.graph.PathLength(s.current) < s.graph.PathLength(s.best) { 51 | s.best = s.best[:len(s.current)] 52 | copy(s.best, s.current) 53 | s.graph.DrawPath(s.feed, s.best, s.tag) 54 | s.feed <- viz.TaggedText{Tag: s.tag, Text: s.pp.Sprintf("BnB: %.2f (%d)", 55 | s.graph.PathLength(s.best)-1, len(s.best))} 56 | } 57 | return 58 | } else if s.graph.PathLength(s.current) > s.graph.PathLength(s.best) { 59 | // bound 60 | return 61 | } 62 | for _, n := range s.graph.Neighbors(last) { 63 | if !in(s.current, n) { 64 | s.current = append(s.current, n) 65 | bnbStep(s) 66 | s.current = s.current[:len(s.current)-1] 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/solvers/greedy.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package solvers 6 | 7 | import ( 8 | "demo-sp/graph" 9 | "demo-sp/randy" 10 | "demo-sp/viz" 11 | "golang.org/x/text/language" 12 | "golang.org/x/text/message" 13 | ) 14 | 15 | type greedyStatus struct { 16 | graph *graph.Graph 17 | feed chan<- interface{} 18 | tag int32 19 | current []int 20 | order []int 21 | visited []bool 22 | backs int32 23 | pp *message.Printer 24 | } 25 | 26 | func GreedyRandom(graph *graph.Graph, feed chan<- interface{}, tag int32) []int { 27 | feed <- viz.TaggedText{Tag: tag, Text: "Greedy Random"} 28 | status := &greedyStatus{ 29 | graph: graph, 30 | feed: feed, 31 | tag: tag, 32 | current: make([]int, 1, len(graph.Nodes)), // 1 element, set cap to nNodes 33 | order: randy.R.Perm(len(graph.Nodes)), // nNodes elems 34 | visited: make([]bool, len(graph.Nodes)), 35 | backs: 0, 36 | pp: message.NewPrinter(language.English), 37 | } 38 | 39 | status.current[0] = 0 40 | greedyStep(status) 41 | var bt string 42 | if status.backs != 1 { 43 | bt = "s" 44 | } 45 | status.graph.DrawPath(status.feed, status.current, status.tag) 46 | status.feed <- viz.TaggedText{Tag: status.tag, Text: status.pp.Sprintf("Greedy (pure random): %.2f (%d) — Completed with %d backtrack%s", 47 | status.graph.PathLength(status.current), len(status.current)-1, status.backs, bt)} 48 | return status.current 49 | } 50 | 51 | func GreedyInformed(graph *graph.Graph, feed chan<- interface{}, tag int32) []int { 52 | feed <- viz.TaggedText{Tag: tag, Text: "Greedy Informed"} 53 | status := &greedyStatus{ 54 | graph: graph, 55 | feed: feed, 56 | tag: tag, 57 | current: make([]int, 1, len(graph.Nodes)), // 1 element, set cap to nNodes 58 | visited: make([]bool, len(graph.Nodes)), 59 | backs: 0, 60 | pp: message.NewPrinter(language.English), 61 | } 62 | status.order = append(status.order, len(status.graph.Nodes)-1) 63 | for _, n := range status.graph.NodesSorted(len(status.graph.Nodes) - 1) { 64 | status.order = append(status.order, n) 65 | } 66 | status.current[0] = 0 67 | greedyStep(status) 68 | var bt string 69 | if status.backs != 1 { 70 | bt = "s" 71 | } 72 | status.graph.DrawPath(status.feed, status.current, status.tag) 73 | status.feed <- viz.TaggedText{Tag: status.tag, Text: status.pp.Sprintf("Greedy (informed): %.2f (%d) — Completed with %d backtrack%s", 74 | status.graph.PathLength(status.current), len(status.current)-1, status.backs, bt)} 75 | 76 | return status.current 77 | } 78 | 79 | func GreedyLazy(graph *graph.Graph, feed chan<- interface{}, tag int32) []int { 80 | feed <- viz.TaggedText{Tag: tag, Text: "Greedy Lazy"} 81 | status := &greedyStatus{ 82 | graph: graph, 83 | feed: feed, 84 | tag: tag, 85 | order: make([]int, 0), 86 | current: make([]int, 1, len(graph.Nodes)), // 1 element, set cap to nNodes 87 | visited: make([]bool, len(graph.Nodes)), 88 | backs: 0, 89 | pp: message.NewPrinter(language.English), 90 | } 91 | 92 | status.current[0] = 0 93 | greedyStep(status) 94 | var bt string 95 | if status.backs != 1 { 96 | bt = "s" 97 | } 98 | status.graph.DrawPath(status.feed, status.current, status.tag) 99 | status.feed <- viz.TaggedText{Tag: status.tag, Text: status.pp.Sprintf("Greedy (lazy): %.2f (%d) — Completed with %d backtrack%s", 100 | status.graph.PathLength(status.current), len(status.current)-1, status.backs, bt)} 101 | 102 | return status.current 103 | } 104 | 105 | func greedyStep(s *greedyStatus) bool { 106 | last := s.current[len(s.current)-1] 107 | if last == len(s.graph.Nodes)-1 { 108 | return true 109 | } 110 | // neighbors... 111 | var order []int 112 | if len(s.order) > 0 { 113 | order = s.order 114 | } else { 115 | order = make([]int, len(s.graph.NodesSorted(last))) 116 | copy(order, s.graph.NodesSorted(last)) 117 | } 118 | neighbors := make([]int, 0, len(s.graph.Nodes)) 119 | for _, n := range order { 120 | if s.graph.Edges[last][n] > 0 && !s.visited[n] { 121 | neighbors = append(neighbors, n) 122 | } 123 | } 124 | for _, n := range neighbors { 125 | if !in(s.current, n) { 126 | s.current = append(s.current, n) 127 | if greedyStep(s) { 128 | return true 129 | } 130 | s.backs++ 131 | s.visited[last] = true 132 | s.current = s.current[:len(s.current)-1] 133 | } 134 | } 135 | return false 136 | } 137 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/solvers/queue.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package solvers 6 | 7 | import ( 8 | "container/heap" 9 | ) 10 | 11 | type Queue interface { 12 | Enqueue(path []int) 13 | Dequeue() []int 14 | Empty() bool 15 | } 16 | 17 | // Last In - First Out (a Stack) 18 | 19 | type Lifo struct { 20 | data [][]int 21 | } 22 | 23 | func (l *Lifo) Empty() bool { 24 | return len(l.data) == 0 25 | } 26 | func (l *Lifo) Enqueue(path []int) { 27 | l.data = append(l.data, path) 28 | } 29 | 30 | func (l *Lifo) Dequeue() []int { 31 | d := l.data[len(l.data)-1] 32 | l.data = l.data[:len(l.data)-1] 33 | return d 34 | } 35 | 36 | // First In - First Out (an English Queue) 37 | 38 | type Fifo struct { 39 | data [][]int 40 | } 41 | 42 | func (f *Fifo) Empty() bool { 43 | return len(f.data) == 0 44 | } 45 | func (f *Fifo) Enqueue(path []int) { 46 | f.data = append(f.data, path) 47 | } 48 | 49 | func (f *Fifo) Dequeue() []int { 50 | d := f.data[0] 51 | f.data = f.data[1:len(f.data)] 52 | return d 53 | } 54 | 55 | // Highest Priority First Out (emergency room) 56 | 57 | type item struct { 58 | path []int 59 | priority float64 60 | } 61 | type Hpfo struct { 62 | data []item 63 | p func(path []int) float64 64 | } 65 | 66 | func (h *Hpfo) Len() int { return len(h.data) } 67 | func (h *Hpfo) Less(i, j int) bool { return h.data[i].priority < h.data[j].priority } 68 | func (h *Hpfo) Swap(i, j int) { h.data[i], h.data[j] = h.data[j], h.data[i] } 69 | 70 | func (h *Hpfo) Push(x any) { 71 | h.data = append(h.data, x.(item)) 72 | } 73 | 74 | func (h *Hpfo) Pop() any { 75 | e := h.data[len(h.data)-1] 76 | h.data = h.data[:len(h.data)-1] 77 | return e 78 | } 79 | 80 | func (h *Hpfo) Empty() bool { 81 | return h.Len() == 0 82 | } 83 | func (h *Hpfo) Enqueue(path []int) { 84 | heap.Push(h, item{path: path, priority: h.p(path)}) 85 | } 86 | func (h *Hpfo) Dequeue() []int { 87 | return heap.Pop(h).(item).path 88 | } 89 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/solvers/tree-search.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package solvers 6 | 7 | import ( 8 | "demo-sp/graph" 9 | "demo-sp/viz" 10 | "golang.org/x/text/language" 11 | "golang.org/x/text/message" 12 | ) 13 | 14 | func DepthFirstSearch(graph *graph.Graph, feed chan<- interface{}, tag int32) []int { 15 | return treeSearch(graph, feed, tag, "DFS", &Lifo{}) 16 | } 17 | 18 | func BreadthFirstSearch(graph *graph.Graph, feed chan<- interface{}, tag int32) []int { 19 | return treeSearch(graph, feed, tag, "BFS", &Fifo{}) 20 | } 21 | 22 | func UniformCostSearch(graph *graph.Graph, feed chan<- interface{}, tag int32) []int { 23 | return treeSearch(graph, feed, tag, "UCS", 24 | &Hpfo{ 25 | p: func(path []int) float64 { 26 | return graph.PathLength(path) 27 | }, 28 | }) 29 | } 30 | 31 | func GreedySearch(graph *graph.Graph, feed chan<- interface{}, tag int32) []int { 32 | return treeSearch(graph, feed, tag, "Greedy", 33 | &Hpfo{ 34 | p: func(path []int) float64 { 35 | return graph.Distance(path[len(path)-1], len(graph.Nodes)-1) 36 | }, 37 | }) 38 | } 39 | 40 | func AStarSearch(graph *graph.Graph, feed chan<- interface{}, tag int32) []int { 41 | return treeSearch(graph, feed, tag, "A*", 42 | &Hpfo{ 43 | p: func(path []int) float64 { 44 | return graph.PathLength(path) + graph.Distance(path[len(path)-1], len(graph.Nodes)-1) 45 | }, 46 | }) 47 | } 48 | 49 | func treeSearch(graph *graph.Graph, feed chan<- interface{}, tag int32, name string, frontier Queue) []int { 50 | pp := message.NewPrinter(language.English) 51 | 52 | //check := make(map[string]int) 53 | 54 | frontier.Enqueue([]int{0}) 55 | steps := 0 56 | for !frontier.Empty() { 57 | //slog.Debug("TS", "frontier", frontier) 58 | path := frontier.Dequeue() 59 | //check[fmt.Sprint(path)]++ 60 | //if check[fmt.Sprint(path)] > 1 { 61 | // log.Fatalf("Panik: %v", path) 62 | //} 63 | //slog.Debug("TS", "path", path, "len", graph.PathLength(path)) 64 | graph.DrawPath(feed, path, tag) 65 | 66 | if path[len(path)-1] == len(graph.Nodes)-1 { 67 | feed <- viz.TaggedText{Tag: tag, Text: pp.Sprintf("%s: %.2f (%d) — Completed in %d steps", name, 68 | graph.PathLength(path), len(path)-1, steps)} 69 | return path 70 | } else { 71 | feed <- viz.TaggedText{Tag: tag, Text: pp.Sprintf("%s: %.2f (%d)", name, 72 | graph.PathLength(path), len(path)-1)} 73 | } 74 | 75 | for _, node := range graph.Neighbors(path[len(path)-1]) { 76 | if in(path, node) { 77 | continue 78 | } 79 | steps++ 80 | new_path := make([]int, len(path)+1) 81 | copy(new_path, path) 82 | new_path[len(path)] = node 83 | frontier.Enqueue(new_path) 84 | } 85 | } 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/solvers/util.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package solvers 6 | 7 | func in(path []int, n int) bool { 8 | for _, p := range path { 9 | if p == n { 10 | return true 11 | } 12 | } 13 | return false 14 | } 15 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/viz/colors.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package viz 6 | 7 | import "image/color" 8 | 9 | // https://htmlcolorcodes.com/color-names/ 10 | 11 | var ColorAliceBlue = color.RGBA{R: 0xf0, G: 0xf8, B: 0xff, A: 0xff} 12 | var ColorAmethyst = color.RGBA{R: 0x99, G: 0x66, B: 0xcc, A: 0xff} 13 | var ColorAndroidGreen = color.RGBA{R: 0xa4, G: 0xc6, B: 0x39, A: 0xff} 14 | var ColorAuburn = color.RGBA{R: 0xa5, G: 0x2a, B: 0x2a, A: 0xff} 15 | var ColorBabyBlueEyes = color.RGBA{R: 0xa1, G: 0xca, B: 0xf1, A: 0xff} 16 | var ColorBabyPink = color.RGBA{R: 0xf4, G: 0xc2, B: 0xc2, A: 0xff} 17 | var ColorBallBlue = color.RGBA{R: 0x21, G: 0xab, B: 0xcd, A: 0xff} 18 | var ColorBlue = color.RGBA{R: 0x00, G: 0x00, B: 0xff, A: 0xff} 19 | var ColorBurlywood = color.RGBA{R: 0xde, G: 0xb8, B: 0x87, A: 0xff} 20 | var ColorCadmiumRed = color.RGBA{R: 0xe3, G: 0x30, B: 0x22, A: 0xff} 21 | var ColorCanaryYellow = color.RGBA{R: 0xff, G: 0xef, B: 0x00, A: 0xff} 22 | var ColorCornsilk = color.RGBA{R: 0xff, G: 0xf8, B: 0xdc, A: 0xff} 23 | var ColorCrimson = color.RGBA{R: 0xdc, G: 0x14, B: 0x3c, A: 0xff} 24 | var ColorDarkOrchid = color.RGBA{R: 0x99, G: 0x32, B: 0xcc, A: 0xff} 25 | var ColorDeepPink = color.RGBA{R: 0xff, G: 0x14, B: 0x93, A: 0xff} 26 | var ColorDeepSkyBlue = color.RGBA{R: 0x00, G: 0xbf, B: 0xff, A: 0xff} 27 | var ColorGainsboro = color.RGBA{R: 0xdc, G: 0xdc, B: 0xdc, A: 0xff} 28 | var ColorIndigo = color.RGBA{R: 0x4b, G: 0x00, B: 0x82, A: 0xff} 29 | var ColorLavenderBlush = color.RGBA{R: 0xff, G: 0xf0, B: 0xf5, A: 0xff} 30 | var ColorLightBlue = color.RGBA{R: 0xad, G: 0xd8, B: 0xe6, A: 0xff} 31 | var ColorLightCoral = color.RGBA{R: 0xf0, G: 0x80, B: 0x80, A: 0xff} 32 | var ColorLightGreen = color.RGBA{R: 0x90, G: 0xee, B: 0x90, A: 0xff} 33 | var ColorLightPink = color.RGBA{R: 0xff, G: 0xb6, B: 0xc1, A: 0xff} 34 | var ColorLightSalmon = color.RGBA{R: 0xff, G: 0xa0, B: 0x7a, A: 0xff} 35 | var ColorLightSkyBlue = color.RGBA{R: 0x87, G: 0xce, B: 0xfa, A: 0xff} 36 | var ColorLightSteelBlue = color.RGBA{R: 0xb0, G: 0xc4, B: 0xde, A: 0xff} 37 | var ColorLightYellow = color.RGBA{R: 0xff, G: 0xff, B: 0xe0, A: 0xff} 38 | var ColorMediumBlue = color.RGBA{R: 0x00, G: 0x00, B: 0xcd, A: 0xff} 39 | var ColorMediumVioletRed = color.RGBA{R: 0xc7, G: 0x15, B: 0x85, A: 0xff} 40 | var ColorMidnightBlue = color.RGBA{R: 0x19, G: 0x19, B: 0x70, A: 0xff} 41 | var ColorMidnightBlueDarker = color.RGBA{R: 0x0d, G: 0x0d, B: 0x3d, A: 0xff} 42 | var ColorOlive = color.RGBA{R: 0x80, G: 0x80, B: 0x00, A: 0xff} 43 | var ColorOrangeRed = color.RGBA{R: 0xff, G: 0x45, B: 0x00, A: 0xff} 44 | var ColorOrchid = color.RGBA{R: 0xda, G: 0x70, B: 0xd6, A: 0xff} 45 | var ColorPaleGoldenrod = color.RGBA{R: 0xee, G: 0xe8, B: 0xaa, A: 0xff} 46 | var ColorPeru = color.RGBA{R: 0xcd, G: 0x85, B: 0x3f, A: 0xff} 47 | var ColorRed = color.RGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff} 48 | var ColorSandyBrown = color.RGBA{R: 0xf4, G: 0xa4, B: 0x60, A: 0xff} 49 | var ColorSnow = color.RGBA{R: 0xff, G: 0xfa, B: 0xfa, A: 0xff} 50 | var ColorSpringGreen = color.RGBA{R: 0x00, G: 0xff, B: 0x7f, A: 0xff} 51 | var ColorTomato = color.RGBA{R: 0xff, G: 0x63, B: 0x47, A: 0xff} 52 | var ColorYellow = color.RGBA{R: 0xff, G: 0xff, B: 0x00, A: 0xff} 53 | var ColorDarkOliveGreen = color.RGBA{R: 0x55, G: 0x6b, B: 0x2f, A: 0xff} 54 | var ColorGold = color.RGBA{R: 0xff, G: 0xd7, B: 0x00, A: 0xff} 55 | var ColorDeepskyBlue = color.RGBA{R: 0x00, G: 0xbf, B: 0xff, A: 0xff} 56 | -------------------------------------------------------------------------------- /2024-25/golang-demos/shortest-path/viz/visual.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Giovanni Squillero 2 | // https://github.com/squillero/computational-intelligence 3 | // Free under certain conditions — see the license for details. 4 | 5 | package viz 6 | 7 | import ( 8 | "bytes" 9 | "github.com/hajimehoshi/ebiten/v2" 10 | "github.com/hajimehoshi/ebiten/v2/examples/resources/fonts" 11 | "github.com/hajimehoshi/ebiten/v2/text/v2" 12 | "github.com/hajimehoshi/ebiten/v2/vector" 13 | "image/color" 14 | "log" 15 | ) 16 | 17 | const MaxTags int = 8 18 | 19 | var TagColors [MaxTags]color.RGBA = [MaxTags]color.RGBA{ 20 | ColorOrangeRed, 21 | ColorGold, 22 | ColorSpringGreen, 23 | ColorDeepskyBlue, 24 | ColorDeepPink, 25 | ColorDarkOliveGreen, 26 | ColorBlue, 27 | ColorMidnightBlue, 28 | } 29 | 30 | type Point struct { 31 | X, Y float32 32 | } 33 | type Polyline struct { 34 | Points []Point 35 | } 36 | type ColoredPolyline struct { 37 | Color color.RGBA 38 | Polyline 39 | } 40 | type TaggedPolyline struct { 41 | Tag int32 42 | Polyline 43 | } 44 | type TaggedVanishingPolyline TaggedPolyline 45 | 46 | type ColoredCircle struct { 47 | Color color.RGBA 48 | Center Point 49 | Radius float32 50 | } 51 | type TaggedText struct { 52 | Text string 53 | Tag int32 54 | drawOptions *text.DrawOptions 55 | } 56 | 57 | // vizData implements ebiten.Game interface. 58 | type vizData struct { 59 | feed <-chan interface{} 60 | playgroundSize int 61 | coloredPolylines []ColoredPolyline 62 | taggedPolylines [MaxTags]Polyline 63 | taggedVanishingPolylines [MaxTags][]Polyline 64 | taggedTexts [MaxTags]TaggedText 65 | coloredCircles []ColoredCircle 66 | textFaceSource *text.GoTextFaceSource 67 | } 68 | 69 | // Layout takes the outside size (e.g., the window size) and returns the (logical) screen size. 70 | // If you don't have to adjust the screen size with the outside size, just return a fixed size. 71 | func (data *vizData) Layout(_, _ int) (screenWidth, screenHeight int) { 72 | return data.playgroundSize, data.playgroundSize 73 | } 74 | 75 | // Update the ebiten "game state" (called every 1/60s tick by default) 76 | func (data *vizData) Update() error { 77 | for done := false; !done; { 78 | select { 79 | case f := <-data.feed: 80 | switch f.(type) { 81 | case ColoredPolyline: 82 | data.coloredPolylines = append(data.coloredPolylines, f.(ColoredPolyline)) 83 | case TaggedPolyline: 84 | data.taggedPolylines[f.(TaggedPolyline).Tag] = Polyline{Points: f.(TaggedPolyline).Points} 85 | case TaggedVanishingPolyline: 86 | data.taggedVanishingPolylines[f.(TaggedVanishingPolyline).Tag] = append(data.taggedVanishingPolylines[f.(TaggedVanishingPolyline).Tag], 87 | Polyline{Points: f.(TaggedVanishingPolyline).Points}) 88 | case ColoredCircle: 89 | data.coloredCircles = append(data.coloredCircles, f.(ColoredCircle)) 90 | case TaggedText: 91 | t := f.(TaggedText) 92 | t.drawOptions = &text.DrawOptions{} 93 | t.drawOptions.GeoM.Translate(26, 10+float64(t.Tag*20)-10) 94 | t.drawOptions.ColorScale.ScaleWithColor(color.White) 95 | data.taggedTexts[f.(TaggedText).Tag] = t 96 | default: 97 | log.Fatalf("Unknown message ``%s'' in feed channel", f) 98 | } 99 | default: 100 | done = true 101 | } 102 | } 103 | return nil 104 | } 105 | 106 | // Draw draws the game screen. 107 | // Draw is called every frame (typically 1/60[s] for 60Hz display). 108 | func (data *vizData) Draw(screen *ebiten.Image) { 109 | // static polyline 110 | for _, l := range data.coloredPolylines { 111 | drawPolyline(screen, l.Points, 5, l.Color) 112 | } 113 | // circles 114 | for _, c := range data.coloredCircles { 115 | vector.DrawFilledCircle(screen, c.Center.X, c.Center.Y, c.Radius, c.Color, true) 116 | } 117 | // vanished tagged lines 118 | for t := 0; t < MaxTags; t += 1 { 119 | col := TagColors[t] 120 | col.R >>= 1 121 | col.G >>= 1 122 | col.B >>= 1 123 | for p := 0; p < len(data.taggedVanishingPolylines[t])-1; p += 1 { 124 | drawPolyline(screen, data.taggedVanishingPolylines[t][p].Points, 1.0, col) 125 | } 126 | } 127 | // tagged polylines 128 | for t := 0; t < MaxTags; t += 1 { 129 | if len(data.taggedVanishingPolylines[t]) > 0 { 130 | col := TagColors[t] 131 | drawPolyline(screen, data.taggedVanishingPolylines[t][len(data.taggedVanishingPolylines[t])-1].Points, 2.0, col) 132 | } 133 | } 134 | // tagged texts 135 | for t := 0; t < MaxTags; t += 1 { 136 | if data.taggedTexts[t].Text != "" { 137 | 138 | vector.DrawFilledCircle(screen, 16, 14+float32(t*20), 8, TagColors[t], true) 139 | text.Draw(screen, data.taggedTexts[t].Text, &text.GoTextFace{ 140 | Source: data.textFaceSource, 141 | Size: 20, 142 | }, data.taggedTexts[t].drawOptions) 143 | } 144 | } 145 | } 146 | 147 | func drawPolyline(screen *ebiten.Image, points []Point, strokeWidth float32, color color.RGBA) { 148 | xe := points[0].X 149 | ye := points[0].Y 150 | for i := 1; i < len(points); i += 1 { 151 | xs := xe 152 | ys := ye 153 | xe = points[i].X 154 | ye = points[i].Y 155 | vector.StrokeLine(screen, xs, ys, xe, ye, strokeWidth, color, true) 156 | } 157 | } 158 | 159 | func Run(feed <-chan interface{}, title string, playgroundSize, windowSize int) { 160 | var err error 161 | 162 | // setup window 163 | ebiten.SetWindowSize(windowSize, windowSize) 164 | ebiten.SetWindowTitle(title) 165 | 166 | // Call ebiten.RunGame to start your game loop. 167 | data := &vizData{feed: feed, playgroundSize: playgroundSize} 168 | if data.textFaceSource, err = text.NewGoTextFaceSource(bytes.NewReader(fonts.MPlus1pRegular_ttf)); err != nil { 169 | log.Fatal(err) 170 | } 171 | if err := ebiten.RunGame(data); err != nil { 172 | log.Fatal(err) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /2024-25/gx_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2022 Giovanni Squillero 2 | # https://github.com/squillero/computational-intelligence 3 | # Free for personal or classroom use; see 'LICENSE.md' for details. 4 | 5 | import heapq 6 | from collections import Counter 7 | 8 | 9 | class PriorityQueue: 10 | """A basic Priority Queue with simple performance optimizations""" 11 | 12 | def __init__(self): 13 | self._data_heap = list() 14 | self._data_set = set() 15 | 16 | def __bool__(self): 17 | return bool(self._data_set) 18 | 19 | def __contains__(self, item): 20 | return item in self._data_set 21 | 22 | def push(self, item, p=None): 23 | assert item not in self, f"Duplicated element" 24 | if p is None: 25 | p = len(self._data_set) 26 | self._data_set.add(item) 27 | heapq.heappush(self._data_heap, (p, item)) 28 | 29 | def pop(self): 30 | p, item = heapq.heappop(self._data_heap) 31 | self._data_set.remove(item) 32 | return item 33 | 34 | 35 | class Multiset: 36 | """Multiset""" 37 | 38 | def __init__(self, init=None): 39 | self._data = Counter() 40 | if init: 41 | for item in init: 42 | self.add(item) 43 | 44 | def __contains__(self, item): 45 | return item in self._data and self._data[item] > 0 46 | 47 | def __getitem__(self, item): 48 | return self.count(item) 49 | 50 | def __iter__(self): 51 | return (i for i in sorted(self._data.keys()) for _ in range(self._data[i])) 52 | 53 | def __len__(self): 54 | return sum(self._data.values()) 55 | 56 | def __copy__(self): 57 | t = Multiset() 58 | t._data = self._data.copy() 59 | return t 60 | 61 | def __str__(self): 62 | return f"M{{{', '.join(repr(i) for i in self)}}}" 63 | 64 | def __repr__(self): 65 | return str(self) 66 | 67 | def __or__(self, other: "Multiset"): 68 | tmp = Multiset() 69 | for i in set(self._data.keys()) | set(other._data.keys()): 70 | tmp.add(i, cnt=max(self[i], other[i])) 71 | return tmp 72 | 73 | def __and__(self, other: "Multiset"): 74 | return self.intersection(other) 75 | 76 | def __add__(self, other: "Multiset"): 77 | return self.union(other) 78 | 79 | def __sub__(self, other: "Multiset"): 80 | tmp = Multiset(self) 81 | for i, n in other._data.items(): 82 | tmp.remove(i, cnt=n) 83 | return tmp 84 | 85 | def __eq__(self, other: "Multiset"): 86 | return list(self) == list(other) 87 | 88 | def __le__(self, other: "Multiset"): 89 | for i, n in self._data.items(): 90 | if other.count(i) < n: 91 | return False 92 | return True 93 | 94 | def __lt__(self, other: "Multiset"): 95 | return self <= other and not self == other 96 | 97 | def __ge__(self, other: "Multiset"): 98 | return other <= self 99 | 100 | def __gt__(self, other: "Multiset"): 101 | return other < self 102 | 103 | def add(self, item, *, cnt=1): 104 | assert cnt >= 0, "Can't add a negative number of elements" 105 | if cnt > 0: 106 | self._data[item] += cnt 107 | 108 | def remove(self, item, *, cnt=1): 109 | assert item in self, f"Item not in collection" 110 | self._data[item] -= cnt 111 | if self._data[item] <= 0: 112 | del self._data[item] 113 | 114 | def count(self, item): 115 | return self._data[item] if item in self._data else 0 116 | 117 | def union(self, other: "Multiset"): 118 | t = Multiset(self) 119 | for i in other._data.keys(): 120 | t.add(i, cnt=other[i]) 121 | return t 122 | 123 | def intersection(self, other: "Multiset"): 124 | t = Multiset() 125 | for i in self._data.keys(): 126 | t.add(i, cnt=min(self[i], other[i])) 127 | return t 128 | -------------------------------------------------------------------------------- /2024-25/min-sum.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "vscode": { 7 | "languageId": "plaintext" 8 | } 9 | }, 10 | "source": [ 11 | "Copyright **`(c)`** 2024 Giovanni Squillero `` \n", 12 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 13 | "Free under certain conditions — see the [`license`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 1, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "from random import randint\n", 23 | "from icecream import ic" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 8, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "PROBLEM_SIZE = 4\n", 33 | "NUMBERS = [randint(1, 10) for _ in range(PROBLEM_SIZE)]\n", 34 | "NUMBERS = [10, 5, 3, 7]\n", 35 | "GOAL = 15" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 9, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "text/plain": [ 46 | "[10, 5, 3, 7]" 47 | ] 48 | }, 49 | "execution_count": 9, 50 | "metadata": {}, 51 | "output_type": "execute_result" 52 | } 53 | ], 54 | "source": [ 55 | "NUMBERS" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [ 63 | { 64 | "data": { 65 | "text/plain": [ 66 | "[5, 3, 7]" 67 | ] 68 | }, 69 | "execution_count": 12, 70 | "metadata": {}, 71 | "output_type": "execute_result" 72 | } 73 | ], 74 | "source": [ 75 | "fronteer = [[False] * PROBLEM_SIZE]\n", 76 | "\n", 77 | "state = fronteer.pop()\n", 78 | "while sum(NUMBERS[n] for n in range(PROBLEM_SIZE) if state[n]) != GOAL:\n", 79 | " valid_actions = [n for n in range(PROBLEM_SIZE) if not state[n]]\n", 80 | " for a in valid_actions:\n", 81 | " new_state = state[:]\n", 82 | " new_state[a] = True\n", 83 | " fronteer.append(new_state)\n", 84 | " state = fronteer.pop()\n", 85 | "[NUMBERS[i] for i in range(PROBLEM_SIZE) if state[i]]" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 13, 91 | "metadata": {}, 92 | "outputs": [ 93 | { 94 | "data": { 95 | "text/plain": [ 96 | "[10, 5]" 97 | ] 98 | }, 99 | "execution_count": 13, 100 | "metadata": {}, 101 | "output_type": "execute_result" 102 | } 103 | ], 104 | "source": [ 105 | "fronteer = [[False] * PROBLEM_SIZE]\n", 106 | "\n", 107 | "state = fronteer.pop(0)\n", 108 | "while sum(NUMBERS[n] for n in range(PROBLEM_SIZE) if state[n]) != GOAL:\n", 109 | " valid_actions = [n for n in range(PROBLEM_SIZE) if not state[n]]\n", 110 | " for a in valid_actions:\n", 111 | " new_state = state[:]\n", 112 | " new_state[a] = True\n", 113 | " fronteer.append(new_state)\n", 114 | " state = fronteer.pop(0)\n", 115 | "[NUMBERS[i] for i in range(PROBLEM_SIZE) if state[i]]" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [] 124 | } 125 | ], 126 | "metadata": { 127 | "kernelspec": { 128 | "display_name": "ci-WEKR9SVn-py3.12", 129 | "language": "python", 130 | "name": "python3" 131 | }, 132 | "language_info": { 133 | "codemirror_mode": { 134 | "name": "ipython", 135 | "version": 3 136 | }, 137 | "file_extension": ".py", 138 | "mimetype": "text/x-python", 139 | "name": "python", 140 | "nbconvert_exporter": "python", 141 | "pygments_lexer": "ipython3", 142 | "version": "3.12.7" 143 | } 144 | }, 145 | "nbformat": 4, 146 | "nbformat_minor": 2 147 | } 148 | -------------------------------------------------------------------------------- /2024-25/n-puzzle.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "vscode": { 7 | "languageId": "plaintext" 8 | } 9 | }, 10 | "source": [ 11 | "Copyright **`(c)`** 2024 Giovanni Squillero `` \n", 12 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 13 | "Free under certain conditions — see the [`license`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 12, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "from collections import namedtuple\n", 23 | "from random import choice\n", 24 | "from tqdm.auto import tqdm\n", 25 | "import numpy as np" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 13, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "PUZZLE_DIM = 5\n", 35 | "action = namedtuple('Action', ['pos1', 'pos2'])" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 14, 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "def available_actions(state: np.ndarray) -> list['Action']:\n", 45 | " x, y = [int(_[0]) for _ in np.where(state == 0)]\n", 46 | " actions = list()\n", 47 | " if x > 0:\n", 48 | " actions.append(action((x, y), (x - 1, y)))\n", 49 | " if x < PUZZLE_DIM - 1:\n", 50 | " actions.append(action((x, y), (x + 1, y)))\n", 51 | " if y > 0:\n", 52 | " actions.append(action((x, y), (x, y - 1)))\n", 53 | " if y < PUZZLE_DIM - 1:\n", 54 | " actions.append(action((x, y), (x, y + 1)))\n", 55 | " return actions\n", 56 | "\n", 57 | "\n", 58 | "\n", 59 | "def do_action(state: np.ndarray, action: 'Action') -> np.ndarray:\n", 60 | " new_state = state.copy()\n", 61 | " new_state[action.pos1], new_state[action.pos2] = new_state[action.pos2], new_state[action.pos1]\n", 62 | " return new_state" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": {}, 69 | "outputs": [ 70 | { 71 | "data": { 72 | "application/vnd.jupyter.widget-view+json": { 73 | "model_id": "7ef479ae718a4138bc0c9ea4accf87e1", 74 | "version_major": 2, 75 | "version_minor": 0 76 | }, 77 | "text/plain": [ 78 | "Randomizing: 0%| | 0/100000 [00:00 2 | # https://github.com/squillero/computational-intelligence 3 | # Free under certain conditions — see the license for details. 4 | 5 | import numpy as np 6 | 7 | # All numpy's mathematical functions can be used in formulas 8 | # see: https://numpy.org/doc/stable/reference/routines.math.html 9 | 10 | 11 | # Notez bien: No need to include f0 -- it's just an example! 12 | def f0(x: np.ndarray) -> np.ndarray: 13 | return x[0] + np.sin(x[1]) / 5 14 | 15 | 16 | def f1(x: np.ndarray) -> np.ndarray: ... 17 | 18 | 19 | def f2(x: np.ndarray) -> np.ndarray: ... 20 | 21 | 22 | def f3(x: np.ndarray) -> np.ndarray: ... 23 | 24 | 25 | def f4(x: np.ndarray) -> np.ndarray: ... 26 | 27 | 28 | def f5(x: np.ndarray) -> np.ndarray: ... 29 | 30 | 31 | def f6(x: np.ndarray) -> np.ndarray: ... 32 | 33 | 34 | def f7(x: np.ndarray) -> np.ndarray: ... 35 | 36 | 37 | def f8(x: np.ndarray) -> np.ndarray: ... 38 | -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_0.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_0.npz -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_1.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_1.npz -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_2.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_2.npz -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_3.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_3.npz -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_4.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_4.npz -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_5.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_5.npz -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_6.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_6.npz -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_7.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_7.npz -------------------------------------------------------------------------------- /2024-25/project-work/data/problem_8.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/squillero/computational-intelligence/b04e766fce7a04ad746e1d54095595daaf07975a/2024-25/project-work/data/problem_8.npz -------------------------------------------------------------------------------- /2024-25/project-work/src/README.md: -------------------------------------------------------------------------------- 1 | # MY WONDERFUL SYMREG PROGRAM 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 4 | 5 | ... 6 | 7 | ```python 8 | problem = np.load('problem_X.npz') 9 | x = problem['x'] 10 | y = problem['y'] 11 | x.shape 12 | 13 | def fX(x: np.ndarray) -> np.ndarray: 14 | ... 15 | 16 | ``` 17 | -------------------------------------------------------------------------------- /2024-25/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright © 2024 Giovanni Squillero 2 | # https://github.com/squillero/computational-intelligence 3 | # Free for personal or classroom use; see 'LICENSE.md' for details. 4 | 5 | [build-system] 6 | build-backend = "poetry.core.masonry.api" 7 | requires = ["poetry-core>=1.0.0"] 8 | 9 | [tool.poetry] 10 | authors = ["Giovanni Squillero "] 11 | description = "Code and Notebook dependencies for Computational Intelligence (2023-24)" 12 | license = "proprietary" 13 | name = "ci" 14 | version = "2023.1" 15 | package-mode = false 16 | 17 | [tool.poetry.dependencies] 18 | black = { extras = ["jupyter"], version = "^22.12.0" } 19 | jupyter = "^1.0.0" 20 | matplotlib = "^3.5.3" 21 | nero = { extras = ["jupyter"], version = "^1.0.20220202" } 22 | networkx = "^2.8.5" 23 | pydot = "^1.4.2" 24 | python = ">=3.10" 25 | scipy = "^1.9.0" 26 | toml = "^0.10.2" 27 | tqdm = "^4.64.0" 28 | isort = "^5.10.1" 29 | multiset = "^3.1.0" 30 | icecream = "^2.1.3" 31 | scikit-learn = "^1.5.1" 32 | numpy = "^2.1.0" 33 | joblib = "^1.4.2" 34 | pandas = "^2.2.3" 35 | geopy = "^2.4.1" 36 | seaborn = "^0.13.2" 37 | 38 | [tool.poetry.dev-dependencies] 39 | 40 | [tool.poetry.group.dev.dependencies] 41 | ipykernel = "^6.27.0" 42 | 43 | [tool.isort] 44 | profile = "black" 45 | 46 | [tool.black] 47 | target-version = ['py310'] 48 | extend-exclude = "^venv$" 49 | include = '(\.ipynb$|\.py$)' 50 | line-length = 120 51 | skip-string-normalization = true 52 | -------------------------------------------------------------------------------- /2024-25/set-cover.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2024 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# Set Cover problem\n", 17 | "\n", 18 | "See: https://en.wikipedia.org/wiki/Set_cover_problem" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 1, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "from random import random, seed\n", 28 | "from itertools import product\n", 29 | "import numpy as np\n", 30 | "\n", 31 | "from icecream import ic" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "## Reproducible Initialization\n", 39 | "\n", 40 | "If you want to get reproducible results, use `rng` (and restart the kernel); for non-reproducible ones, use `np.random`." 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 6, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "UNIVERSE_SIZE = 100_000\n", 50 | "NUM_SETS = 10_000\n", 51 | "DENSITY = 0.3\n", 52 | "\n", 53 | "rng = np.random.Generator(np.random.PCG64([UNIVERSE_SIZE, NUM_SETS, int(10_000 * DENSITY)]))" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 7, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "# DON'T EDIT THESE LINES!\n", 63 | "\n", 64 | "SETS = np.random.random((NUM_SETS, UNIVERSE_SIZE)) < DENSITY\n", 65 | "for s in range(UNIVERSE_SIZE):\n", 66 | " if not np.any(SETS[:, s]):\n", 67 | " SETS[np.random.randint(NUM_SETS), s] = True\n", 68 | "COSTS = np.pow(SETS.sum(axis=1), 1.1)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "## Helper Functions" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 8, 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "def valid(solution):\n", 85 | " \"\"\"Checks wether solution is valid (ie. covers all universe)\"\"\"\n", 86 | " return np.all(np.logical_or.reduce(SETS[solution]))\n", 87 | "\n", 88 | "\n", 89 | "def cost(solution):\n", 90 | " \"\"\"Returns the cost of a solution (to be minimized)\"\"\"\n", 91 | " return COSTS[solution].sum()" 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "metadata": {}, 97 | "source": [ 98 | "## Have Fun!" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 9, 104 | "metadata": {}, 105 | "outputs": [ 106 | { 107 | "data": { 108 | "text/plain": [ 109 | "(np.True_, np.float64(841052547.0129727))" 110 | ] 111 | }, 112 | "execution_count": 9, 113 | "metadata": {}, 114 | "output_type": "execute_result" 115 | } 116 | ], 117 | "source": [ 118 | "# A dumb solution of \"all\" sets\n", 119 | "solution = np.full(NUM_SETS, True)\n", 120 | "valid(solution), cost(solution)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 10, 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "data": { 130 | "text/plain": [ 131 | "(np.True_, np.float64(423460252.60587573))" 132 | ] 133 | }, 134 | "execution_count": 10, 135 | "metadata": {}, 136 | "output_type": "execute_result" 137 | } 138 | ], 139 | "source": [ 140 | "# A random solution with random 50% of the sets\n", 141 | "solution = rng.random(NUM_SETS) < .5\n", 142 | "valid(solution), cost(solution)" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "rng." 152 | ] 153 | } 154 | ], 155 | "metadata": { 156 | "kernelspec": { 157 | "display_name": "Python 3 (ipykernel)", 158 | "language": "python", 159 | "name": "python3" 160 | }, 161 | "language_info": { 162 | "codemirror_mode": { 163 | "name": "ipython", 164 | "version": 3 165 | }, 166 | "file_extension": ".py", 167 | "mimetype": "text/x-python", 168 | "name": "python", 169 | "nbconvert_exporter": "python", 170 | "pygments_lexer": "ipython3", 171 | "version": "3.12.5" 172 | } 173 | }, 174 | "nbformat": 4, 175 | "nbformat_minor": 4 176 | } 177 | -------------------------------------------------------------------------------- /2024-25/set-cover_ea.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2024 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# Set Cover problem\n", 17 | "\n", 18 | "See: https://en.wikipedia.org/wiki/Set_cover_problem" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 1, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "import functools\n", 28 | "from dataclasses import dataclass\n", 29 | "\n", 30 | "import numpy as np\n", 31 | "from tqdm.auto import tqdm\n", 32 | "from icecream import ic" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "## Reproducible Initialization\n", 40 | "\n", 41 | "If you want to get reproducible results, use `rng` (and restart the kernel); for non-reproducible ones, use `np.random`." 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 2, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "UNIVERSE_SIZE = 1000\n", 51 | "NUM_SETS = 100\n", 52 | "DENSITY = 0.2" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 3, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "# DON'T EDIT THESE LINES!\n", 62 | "\n", 63 | "rng = np.random.Generator(np.random.PCG64([UNIVERSE_SIZE, NUM_SETS, int(10_000 * DENSITY)]))\n", 64 | "\n", 65 | "SETS = np.random.random((NUM_SETS, UNIVERSE_SIZE)) < DENSITY\n", 66 | "for s in range(UNIVERSE_SIZE):\n", 67 | " if not np.any(SETS[:, s]):\n", 68 | " SETS[np.random.randint(NUM_SETS), s] = True\n", 69 | "COSTS = np.pow(SETS.sum(axis=1), 1.1)\n", 70 | "\n", 71 | "\n", 72 | "def counter(fn):\n", 73 | " \"\"\"Simple decorator for counting number of calls\"\"\"\n", 74 | "\n", 75 | " @functools.wraps(fn)\n", 76 | " def helper(*args, **kargs):\n", 77 | " helper.calls += 1\n", 78 | " return fn(*args, **kargs)\n", 79 | "\n", 80 | " helper.calls = 0\n", 81 | " return helper\n", 82 | "\n", 83 | "\n", 84 | "@counter\n", 85 | "def cost(solution):\n", 86 | " \"\"\"Returns the cost of a solution (to be minimized) tracking number of calls\"\"\"\n", 87 | " return COSTS[solution].sum()" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "# Squillero's EA" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "metadata": {}, 100 | "source": [ 101 | "## Helper Functions" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 4, 107 | "metadata": {}, 108 | "outputs": [], 109 | "source": [ 110 | "def valid(solution):\n", 111 | " \"\"\"Checks wether solution is valid (ie. covers all universe)\"\"\"\n", 112 | " return np.all(np.logical_or.reduce(SETS[solution]))\n", 113 | "\n", 114 | "\n", 115 | "def num_covered(solution):\n", 116 | " \"\"\"Checks wether solution is valid (ie. covers all universe)\"\"\"\n", 117 | " return np.sum(np.logical_or.reduce(SETS[solution]))\n", 118 | "\n", 119 | "\n", 120 | "@dataclass\n", 121 | "class Individual:\n", 122 | " genome: np.ndarray\n", 123 | " fitness: float = None\n", 124 | "\n", 125 | "\n", 126 | "def fitness(individual):\n", 127 | " return int(num_covered(individual.genome)), -float(cost(individual.genome))\n", 128 | "\n", 129 | "\n", 130 | "def parent_selection(population):\n", 131 | " candidates = sorted(np.random.choice(population, 2), key=lambda e: e.fitness, reverse=True)\n", 132 | " return candidates[0]\n", 133 | "\n", 134 | "\n", 135 | "def xover(p1: Individual, p2: Individual):\n", 136 | " m = np.random.rand(NUM_SETS) < 0.5\n", 137 | " genome = p1.genome.copy()\n", 138 | " genome[m] = p2.genome[m]\n", 139 | " return Individual(genome)\n", 140 | "\n", 141 | "\n", 142 | "def muatation(p: Individual):\n", 143 | " genome = p.genome.copy()\n", 144 | " x = 0\n", 145 | " while x < 0.1:\n", 146 | " index = np.random.randint(NUM_SETS)\n", 147 | " genome[index] = not genome[index]\n", 148 | " x = np.random.random()\n", 149 | " return Individual(genome)" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "## Have Fun!" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 5, 162 | "metadata": {}, 163 | "outputs": [ 164 | { 165 | "data": { 166 | "application/vnd.jupyter.widget-view+json": { 167 | "model_id": "ac66cf5ad88040678a6d3003b7e841b8", 168 | "version_major": 2, 169 | "version_minor": 0 170 | }, 171 | "text/plain": [ 172 | " 0%| | 0/10000 [00:00` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free for personal or classroom use; see [`LICENSE.md`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# Set Cover problem\n", 17 | "\n", 18 | "See: https://en.wikipedia.org/wiki/Set_cover_problem" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 1, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "import functools\n", 28 | "import numpy as np\n", 29 | "\n", 30 | "from tqdm.auto import tqdm\n", 31 | "from icecream import ic" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "## Reproducible Initialization\n", 39 | "\n", 40 | "If you want to get reproducible results, use `rng` (and restart the kernel); for non-reproducible ones, use `np.random`." 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 6, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "UNIVERSE_SIZE = 10_000\n", 50 | "NUM_SETS = 1000\n", 51 | "DENSITY = 0.3" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 7, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "# DON'T EDIT THESE LINES!\n", 61 | "\n", 62 | "rng = np.random.Generator(np.random.PCG64([UNIVERSE_SIZE, NUM_SETS, int(10_000 * DENSITY)]))\n", 63 | "\n", 64 | "SETS = np.random.random((NUM_SETS, UNIVERSE_SIZE)) < DENSITY\n", 65 | "for s in range(UNIVERSE_SIZE):\n", 66 | " if not np.any(SETS[:, s]):\n", 67 | " SETS[np.random.randint(NUM_SETS), s] = True\n", 68 | "COSTS = np.pow(SETS.sum(axis=1), 1.1)\n", 69 | "\n", 70 | "\n", 71 | "def counter(fn):\n", 72 | " \"\"\"Simple decorator for counting number of calls\"\"\"\n", 73 | "\n", 74 | " @functools.wraps(fn)\n", 75 | " def helper(*args, **kargs):\n", 76 | " helper.calls += 1\n", 77 | " return fn(*args, **kargs)\n", 78 | "\n", 79 | " helper.calls = 0\n", 80 | " return helper\n", 81 | "\n", 82 | "\n", 83 | "@counter\n", 84 | "def cost(solution):\n", 85 | " \"\"\"Returns the cost of a solution (to be minimized) tracking number of calls\"\"\"\n", 86 | " return COSTS[solution].sum()" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "# Squillero's greedy solution" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "## Helper Functions" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 8, 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [ 109 | "def valid(solution):\n", 110 | " \"\"\"Checks wether solution is valid (ie. covers all universe)\"\"\"\n", 111 | " return np.all(np.logical_or.reduce(SETS[solution]))\n", 112 | "\n", 113 | "\n", 114 | "def num_covered(solution):\n", 115 | " \"\"\"Checks wether solution is valid (ie. covers all universe)\"\"\"\n", 116 | " return np.sum(np.logical_or.reduce(SETS[solution]))" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "## Have Fun!" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 9, 129 | "metadata": {}, 130 | "outputs": [ 131 | { 132 | "data": { 133 | "application/vnd.jupyter.widget-view+json": { 134 | "model_id": "21a84b6b092a4c41a69465e4cc8d9f51", 135 | "version_major": 2, 136 | "version_minor": 0 137 | }, 138 | "text/plain": [ 139 | " 0%| | 0/10000 [00:00` \n", 12 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 13 | "Free under certain conditions — see the [`license`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 1, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import logging\n", 23 | "from itertools import combinations\n", 24 | "import pandas as pd\n", 25 | "import numpy as np\n", 26 | "from geopy.distance import geodesic\n", 27 | "import networkx as nx\n", 28 | "\n", 29 | "from icecream import ic\n", 30 | "\n", 31 | "logging.basicConfig(level=logging.DEBUG)" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "CITIES = pd.read_csv('cities/china.csv', header=None, names=['name', 'lat', 'lon'])\n", 41 | "DIST_MATRIX = np.zeros((len(CITIES), len(CITIES)))\n", 42 | "for c1, c2 in combinations(CITIES.itertuples(), 2):\n", 43 | " DIST_MATRIX[c1.Index, c2.Index] = DIST_MATRIX[c2.Index, c1.Index] = geodesic(\n", 44 | " (c1.lat, c1.lon), (c2.lat, c2.lon)\n", 45 | " ).km\n", 46 | "CITIES.head()" 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "## Lab3" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "median = np.median(DIST_MATRIX.reshape(1, -1))\n", 63 | "ic(median)\n", 64 | "# DIST_MATRIX[DIST_MATRIX > median] = np.inf\n", 65 | "G = nx.Graph()\n", 66 | "for c1, c2 in combinations(CITIES.itertuples(), 2):\n", 67 | " G.add_node(c1)\n", 68 | " G.add_node(c2)\n", 69 | " if DIST_MATRIX[c1.Index, c2.Index] <= median:\n", 70 | " G.add_edge(c1, c2)\n", 71 | "nx.is_connected(G)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [] 80 | } 81 | ], 82 | "metadata": { 83 | "kernelspec": { 84 | "display_name": "ci-WEKR9SVn-py3.12", 85 | "language": "python", 86 | "name": "python3" 87 | }, 88 | "language_info": { 89 | "codemirror_mode": { 90 | "name": "ipython", 91 | "version": 3 92 | }, 93 | "file_extension": ".py", 94 | "mimetype": "text/x-python", 95 | "name": "python", 96 | "nbconvert_exporter": "python", 97 | "pygments_lexer": "ipython3", 98 | "version": "3.12.7" 99 | } 100 | }, 101 | "nbformat": 4, 102 | "nbformat_minor": 2 103 | } 104 | -------------------------------------------------------------------------------- /2024-25/symreg/d3584.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2024 Giovanni Squillero 2 | # https://github.com/squillero/computational-intelligence 3 | # Free under certain conditions — see the license for details. 4 | 5 | import numpy as np 6 | 7 | 8 | def f(x: np.ndarray) -> np.ndarray: 9 | return x[0] + x[1] / 5 10 | -------------------------------------------------------------------------------- /2024-25/symreg/gxgp/__init__.py: -------------------------------------------------------------------------------- 1 | # * Giovanni Squillero's GP Toolbox 2 | # / \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | # 2 + A no-nonsense GP in pure Python 4 | # / \ 5 | # 10 11 Distributed under MIT License 6 | 7 | try: 8 | from icecream import install 9 | 10 | install() 11 | except ImportError: 12 | pass 13 | 14 | from .draw import * 15 | from .gp_common import * 16 | from .gp_dag import * 17 | from .gp_tree import * 18 | from .node import * 19 | from .random import gxgp_random 20 | from .utils import * 21 | -------------------------------------------------------------------------------- /2024-25/symreg/gxgp/draw.py: -------------------------------------------------------------------------------- 1 | # * Giovanni Squillero's GP Toolbox 2 | # / \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | # 2 + A no-nonsense GP in pure Python 4 | # / \ 5 | # 10 11 Distributed under MIT License 6 | 7 | import inspect 8 | 9 | 10 | def draw(node: "Node"): 11 | import networkx as nx 12 | from networkx.drawing.nx_pydot import graphviz_layout 13 | 14 | G = nx.DiGraph() 15 | for n1 in list(node.subtree): 16 | for n2 in list(n1._successors): 17 | G.add_edge(id(n1), id(n2)) 18 | 19 | pos = graphviz_layout(G, prog="dot") # dot neato twopi circo fdp sfdp 20 | # plt.figure() 21 | # plt.title(node.long_name) 22 | 23 | nx.draw_networkx_nodes( 24 | G, 25 | nodelist=[id(n) for n in node.subtree if not 26 | n.is_leaf], 27 | pos=pos, 28 | node_size=800, 29 | node_color='lightpink', 30 | node_shape='o' # so^>vvv Node: 14 | offspring = deepcopy(tree1) 15 | ic(offspring) 16 | successors = None 17 | while not successors: 18 | node = gxgp_random.choice(list(offspring.subtree)) 19 | successors = node.successors 20 | i = gxgp_random.randrange(len(successors)) 21 | ic(successors, i) 22 | successors[i] = deepcopy(gxgp_random.choice(list(tree2.subtree))) 23 | ic(successors, i) 24 | node.successors = successors 25 | return offspring 26 | -------------------------------------------------------------------------------- /2024-25/symreg/gxgp/gp_dag.py: -------------------------------------------------------------------------------- 1 | # * Giovanni Squillero's GP Toolbox 2 | # / \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | # 2 + A no-nonsense GP in pure Python 4 | # / \ 5 | # 10 11 Distributed under MIT License 6 | 7 | from typing import Collection 8 | 9 | from .node import Node 10 | from .random import gxgp_random 11 | from .utils import arity 12 | 13 | __all__ = ['DagGP'] 14 | 15 | 16 | class DagGP: 17 | def __init__(self, operators: Collection, variables: int | Collection, constants: int | Collection): 18 | self._operators = list(operators) 19 | if isinstance(variables, int): 20 | self._variables = [Node(DagGP.default_variable(i)) for i in range(variables)] 21 | else: 22 | self._variables = [Node(t) for t in variables] 23 | if isinstance(constants, int): 24 | self._constants = [Node(gxgp_random.random()) for i in range(constants)] 25 | else: 26 | self._constants = [Node(t) for t in constants] 27 | 28 | def create_individual(self, n_nodes=7): 29 | pool = self._variables * (1 + len(self._constants) // len(self._variables)) + self._constants 30 | individual = None 31 | while individual is None or len(individual) < n_nodes: 32 | op = gxgp_random.choice(self._operators) 33 | params = gxgp_random.choices(pool, k=arity(op)) 34 | individual = Node(op, params) 35 | pool.append(individual) 36 | return individual 37 | 38 | @staticmethod 39 | def default_variable(i: int) -> str: 40 | return f'x{i}' 41 | 42 | @staticmethod 43 | def evaluate(individual: Node, X, variable_names=None): 44 | if variable_names: 45 | names = variable_names 46 | else: 47 | names = [DagGP.default_variable(i) for i in range(len(X[0]))] 48 | 49 | y_pred = list() 50 | for row in X: 51 | y_pred.append(individual(**{n: v for n, v in zip(names, row)})) 52 | return y_pred 53 | 54 | @staticmethod 55 | def plot_evaluate(individual: Node, X, variable_names=None): 56 | import matplotlib.pyplot as plt 57 | 58 | y_pred = DagGP.evaluate(individual, X, variable_names) 59 | plt.figure() 60 | plt.title(individual.long_name) 61 | plt.scatter([x[0] for x in X], y_pred) 62 | 63 | return y_pred 64 | 65 | @staticmethod 66 | def mse(individual: Node, X, y, variable_names=None): 67 | y_pred = DagGP.evaluate(individual, X, variable_names) 68 | return sum((a - b) ** 2 for a, b in zip(y, y_pred)) / len(y) 69 | -------------------------------------------------------------------------------- /2024-25/symreg/gxgp/gp_tree.py: -------------------------------------------------------------------------------- 1 | # * Giovanni Squillero's GP Toolbox 2 | # / \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | # 2 + A no-nonsense GP in pure Python 4 | # / \ 5 | # 10 11 Distributed under MIT License 6 | 7 | import random 8 | from typing import Collection 9 | 10 | from .node import Node 11 | from .utils import arity 12 | 13 | __all__ = ['TreeGP'] 14 | 15 | 16 | class TreeGP: 17 | def __init__(self, operators: Collection, variables: int | Collection, constants: int | Collection, *, seed=42): 18 | raise NotImplementedError 19 | -------------------------------------------------------------------------------- /2024-25/symreg/gxgp/node.py: -------------------------------------------------------------------------------- 1 | # * Giovanni Squillero's GP Toolbox 2 | # / \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | # 2 + A no-nonsense GP in pure Python 4 | # / \ 5 | # 10 11 Distributed under MIT License 6 | 7 | import numbers 8 | import warnings 9 | from typing import Callable 10 | 11 | from .draw import draw 12 | from .utils import arity 13 | 14 | __all__ = ['Node'] 15 | 16 | 17 | class Node: 18 | _func: Callable 19 | _successors: tuple['Node'] 20 | _arity: int 21 | _str: str 22 | 23 | def __init__(self, node=None, successors=None, *, name=None): 24 | if callable(node): 25 | 26 | def _f(*_args, **_kwargs): 27 | return node(*_args) 28 | 29 | self._func = _f 30 | self._successors = tuple(successors) 31 | self._arity = arity(node) 32 | assert self._arity is None or len(tuple(successors)) == self._arity, ( 33 | "Panic: Incorrect number of children." 34 | + f" Expected {len(tuple(successors))} found {arity(node)}" 35 | ) 36 | self._leaf = False 37 | assert all(isinstance(s, Node) for s in successors), "Panic: Successors must be `Node`" 38 | self._successors = tuple(successors) 39 | if name is not None: 40 | self._str = name 41 | elif node.__name__ == '': 42 | self._str = 'λ' 43 | else: 44 | self._str = node.__name__ 45 | elif isinstance(node, numbers.Number): 46 | self._func = eval(f'lambda **_kw: {node}') 47 | self._successors = tuple() 48 | self._arity = 0 49 | self._str = f'{node:g}' 50 | elif isinstance(node, str): 51 | self._func = eval(f'lambda *, {node}, **_kw: {node}') 52 | self._successors = tuple() 53 | self._arity = 0 54 | self._str = str(node) 55 | else: 56 | assert False 57 | 58 | def __call__(self, **kwargs): 59 | return self._func(*[c(**kwargs) for c in self._successors], **kwargs) 60 | 61 | def __str__(self): 62 | return self.long_name 63 | 64 | def __len__(self): 65 | return 1 + sum(len(c) for c in self._successors) 66 | 67 | @property 68 | def value(self): 69 | return self() 70 | 71 | @property 72 | def arity(self): 73 | return self._arity 74 | 75 | @property 76 | def successors(self): 77 | return list(self._successors) 78 | 79 | @successors.setter 80 | def successors(self, new_successors): 81 | assert len(new_successors) == len(self._successors) 82 | self._successors = tuple(new_successors) 83 | 84 | @property 85 | def is_leaf(self): 86 | return not self._successors 87 | 88 | @property 89 | def short_name(self): 90 | return self._str 91 | 92 | @property 93 | def long_name(self): 94 | if self.is_leaf: 95 | return self.short_name 96 | else: 97 | return f'{self.short_name}(' + ', '.join(c.long_name for c in self._successors) + ')' 98 | 99 | @property 100 | def subtree(self): 101 | result = set() 102 | _get_subtree(result, self) 103 | return result 104 | 105 | def draw(self): 106 | try: 107 | return draw(self) 108 | except Exception as msg: 109 | warnings.warn(f"Drawing not available ({msg})", UserWarning, 2) 110 | return None 111 | 112 | 113 | def _get_subtree(bunch: set, node: Node): 114 | bunch.add(node) 115 | for c in node._successors: 116 | _get_subtree(bunch, c) 117 | -------------------------------------------------------------------------------- /2024-25/symreg/gxgp/random.py: -------------------------------------------------------------------------------- 1 | # * Giovanni Squillero's GP Toolbox 2 | # / \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | # 2 + A no-nonsense GP in pure Python 4 | # / \ 5 | # 10 11 Distributed under MIT License 6 | 7 | import random 8 | 9 | assert "gxgp_random" not in globals(), "Paranoia check: gxgp_random already initialized" 10 | gxgp_random = random.Random(42) 11 | -------------------------------------------------------------------------------- /2024-25/symreg/gxgp/utils.py: -------------------------------------------------------------------------------- 1 | # * Giovanni Squillero's GP Toolbox 2 | # / \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | # 2 + A no-nonsense GP in pure Python 4 | # / \ 5 | # 10 11 Distributed under MIT License 6 | 7 | import inspect 8 | from typing import Callable 9 | 10 | __all__ = ['arity'] 11 | 12 | 13 | def arity(f: Callable) -> int: 14 | """Return the number of expected parameter or None if variable""" 15 | if inspect.getfullargspec(f).varargs is not None: 16 | return None 17 | else: 18 | return len(inspect.getfullargspec(f).args) 19 | -------------------------------------------------------------------------------- /2024-25/symreg/symreg.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2024 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free under certain conditions — see the [`license`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import numpy as np\n", 19 | "from icecream import ic" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "import numpy as np\n", 29 | "def true_f(x: np.ndarray) -> np.ndarray:\n", 30 | " return x[0] + np.sin(x[1]) / 5" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 3, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "TEST_SIZE = 10_000\n", 40 | "TRAIN_SIZE = 1000\n", 41 | "\n", 42 | "x_validation = np.vstack(\n", 43 | " [\n", 44 | " np.random.random_sample(size=TEST_SIZE) * 2 * np.pi - np.pi,\n", 45 | " np.random.random_sample(size=TEST_SIZE) * 2 - 1,\n", 46 | " ]\n", 47 | ")\n", 48 | "y_validation = true_f(x_validation)\n", 49 | "train_indexes = np.random.choice(TEST_SIZE, size=TRAIN_SIZE, replace=False)\n", 50 | "x_train = x_validation[:, train_indexes]\n", 51 | "y_train = y_validation[train_indexes]\n", 52 | "assert np.all(y_train == true_f(x_train)), \"D'ho\"\n", 53 | "\n", 54 | "np.savez('problem_0.npz', x=x_train, y=y_train)" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "## Evaluation" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 4, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "import d3584" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 5, 76 | "metadata": {}, 77 | "outputs": [ 78 | { 79 | "data": { 80 | "text/plain": [ 81 | "((2, 1000), (1000,))" 82 | ] 83 | }, 84 | "execution_count": 5, 85 | "metadata": {}, 86 | "output_type": "execute_result" 87 | } 88 | ], 89 | "source": [ 90 | "problem = np.load('problem_0.npz')\n", 91 | "x = problem['x']\n", 92 | "y = problem['y']\n", 93 | "x.shape, y.shape" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 9, 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "MSE (train): 0.0151147\n", 106 | "MSE (real) : 0.0145592\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "print(f\"MSE (train): {100*np.square(y_train-d3584.f(x_train)).sum()/len(y_train):g}\")\n", 112 | "print(f\"MSE (real) : {100*np.square(y_validation-d3584.f(x_validation)).sum()/len(y_validation):g}\")" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": null, 118 | "metadata": {}, 119 | "outputs": [], 120 | "source": [] 121 | } 122 | ], 123 | "metadata": { 124 | "kernelspec": { 125 | "display_name": "ci-WEKR9SVn-py3.12", 126 | "language": "python", 127 | "name": "python3" 128 | }, 129 | "language_info": { 130 | "codemirror_mode": { 131 | "name": "ipython", 132 | "version": 3 133 | }, 134 | "file_extension": ".py", 135 | "mimetype": "text/x-python", 136 | "name": "python", 137 | "nbconvert_exporter": "python", 138 | "pygments_lexer": "ipython3", 139 | "version": "3.12.8" 140 | } 141 | }, 142 | "nbformat": 4, 143 | "nbformat_minor": 2 144 | } 145 | -------------------------------------------------------------------------------- /2024-25/symreg/symreg_user.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright **`(c)`** 2024 Giovanni Squillero `` \n", 8 | "[`https://github.com/squillero/computational-intelligence`](https://github.com/squillero/computational-intelligence) \n", 9 | "Free under certain conditions — see the [`license`](https://github.com/squillero/computational-intelligence/blob/master/LICENSE.md) for details. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import numpy as np\n", 19 | "from icecream import ic" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [ 27 | { 28 | "data": { 29 | "text/plain": [ 30 | "(2, 1000)" 31 | ] 32 | }, 33 | "execution_count": 2, 34 | "metadata": {}, 35 | "output_type": "execute_result" 36 | } 37 | ], 38 | "source": [ 39 | "problem = np.load('problem_0.npz')\n", 40 | "x = problem['x']\n", 41 | "y = problem['y']\n", 42 | "x.shape" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [] 51 | } 52 | ], 53 | "metadata": { 54 | "kernelspec": { 55 | "display_name": "ci-staff-mErg2TPS-py3.13", 56 | "language": "python", 57 | "name": "python3" 58 | }, 59 | "language_info": { 60 | "codemirror_mode": { 61 | "name": "ipython", 62 | "version": 3 63 | }, 64 | "file_extension": ".py", 65 | "mimetype": "text/x-python", 66 | "name": "python", 67 | "nbconvert_exporter": "python", 68 | "pygments_lexer": "ipython3", 69 | "version": "3.13.0" 70 | } 71 | }, 72 | "nbformat": 4, 73 | "nbformat_minor": 2 74 | } 75 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## Computational Intelligence 2 | 3 | 4 | 5 | #### Copyright © 2021-2024 by Giovanni Squillero 6 | 7 | Permission to make digital or hard copies of some or all of these files for 8 | personal or classroom use is granted without fee provided that copies are not 9 | made or distributed for profit or commercial advantage, and that copies bear 10 | both this copyright notice and the full reference to the source repository. 11 | To republish, to redistribute to lists, or to post on servers, contact the 12 | Author. Copyrights for third-party contributions must be honored. 13 | These files are offered as-is, without any warranty. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Computational Intelligence 2 | ========================== 3 | 4 | This repo contains notes and code fragments for my lectures of *Computational Intelligence* ([01URROV](https://didattica.polito.it/pls/portal30/gap.pkg_guide.viewGap?p_cod_ins=01URROV)) at [Politecnico di Torino](https://www.polito.it/) since 2021-22. 5 | 6 | Students are encouraged to join the Telegram group [polito_01urrov](https://t.me/polito_01urrov). 7 | 8 | **Copyright © [Giovanni Squillero](https://squillero.github.io/)** (unless otherwise noted in individual files) 9 | Copying and distributing these files are permitted under certain conditions, see file [`LICENSE.md`](./LICENSE.md) for details. 10 | --------------------------------------------------------------------------------