├── projects
├── TSP
│ ├── GA
│ │ ├── __init__.py
│ │ ├── test
│ │ │ ├── __init__.py
│ │ │ └── test_tsp_ga.py
│ │ └── tsp_ga.py
│ └── pyswarm.py
├── seminar
│ └── assets
│ │ ├── cv.png
│ │ ├── rcnn.png
│ │ ├── roi.png
│ │ ├── ross.png
│ │ ├── tasks.png
│ │ ├── rcnn-2.png
│ │ ├── ImageNet-1.png
│ │ ├── fast-rcnn.png
│ │ ├── mask-rcnn.png
│ │ ├── rcnn-conv.png
│ │ ├── rcnn-prob.png
│ │ ├── deeplearning.png
│ │ ├── fast-rcnn-1.png
│ │ ├── faster-rcnn.png
│ │ ├── mask-rcnn-1.png
│ │ ├── mask-rcnn-2.png
│ │ ├── classification.png
│ │ └── understanding.png
├── sudoku
│ ├── images
│ │ ├── fiinished.png
│ │ ├── sudoku-board-bare.jpg
│ │ ├── Screenshot_20170831_204744.png
│ │ └── Screenshot_20170831_204758.png
│ ├── utils
│ │ ├── __init__.py
│ │ ├── assets.py
│ │ └── SudokuSquare.py
│ ├── README.md
│ ├── visualizer.py
│ ├── PySudoku.py
│ ├── solver.py
│ └── solver_test.py
└── Naive-Bayes
│ └── text-classification-naive-bayes.ipynb
├── 01-Artificial-Intelligence
├── __init__.py
├── tests
│ ├── __init__.py
│ ├── pytest.ini
│ └── test_agents.py
├── assignments
│ ├── images
│ │ ├── fig2.2
│ │ ├── fig2-2.png
│ │ └── fig2-3.png
│ ├── Exercise 2.4.ipynb
│ └── AI in 2030_REPORT-summary.ipynb
├── 1-Introduction
│ ├── Summary-of-Turing-original-paper-on-AI.md
│ └── introduction.ipynb
├── agents.py
└── 2-Intelligent-agents
│ └── intelligent-agents.ipynb
├── papers
└── ai_100_report_0901fnlc_single (1)(1).pdf
├── ci
├── dl_env.py
└── install_python.ps1
├── environments
├── dl_env_mac.yml
├── dl_env_linux_gpu.yml
├── dl_env_windows.yml
├── dl_env_linux.yml
├── README.md
├── dl_env_linux-v2.yml
└── dl_env_linux_gpu-v2.yml
├── LICENSE
├── appveyor.yml
├── .travis.yml
├── .gitignore
├── README.md
└── 02-Problem-Solving
└── 03-Search
└── search.ipynb
/projects/TSP/GA/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/projects/TSP/GA/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/assignments/images/fig2.2:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/tests/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | filterwarnings =
3 | ignore::ResourceWarning
--------------------------------------------------------------------------------
/projects/seminar/assets/cv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/cv.png
--------------------------------------------------------------------------------
/projects/seminar/assets/rcnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/rcnn.png
--------------------------------------------------------------------------------
/projects/seminar/assets/roi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/roi.png
--------------------------------------------------------------------------------
/projects/seminar/assets/ross.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/ross.png
--------------------------------------------------------------------------------
/projects/seminar/assets/tasks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/tasks.png
--------------------------------------------------------------------------------
/projects/seminar/assets/rcnn-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/rcnn-2.png
--------------------------------------------------------------------------------
/projects/seminar/assets/ImageNet-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/ImageNet-1.png
--------------------------------------------------------------------------------
/projects/seminar/assets/fast-rcnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/fast-rcnn.png
--------------------------------------------------------------------------------
/projects/seminar/assets/mask-rcnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/mask-rcnn.png
--------------------------------------------------------------------------------
/projects/seminar/assets/rcnn-conv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/rcnn-conv.png
--------------------------------------------------------------------------------
/projects/seminar/assets/rcnn-prob.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/rcnn-prob.png
--------------------------------------------------------------------------------
/projects/sudoku/images/fiinished.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/sudoku/images/fiinished.png
--------------------------------------------------------------------------------
/projects/seminar/assets/deeplearning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/deeplearning.png
--------------------------------------------------------------------------------
/projects/seminar/assets/fast-rcnn-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/fast-rcnn-1.png
--------------------------------------------------------------------------------
/projects/seminar/assets/faster-rcnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/faster-rcnn.png
--------------------------------------------------------------------------------
/projects/seminar/assets/mask-rcnn-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/mask-rcnn-1.png
--------------------------------------------------------------------------------
/projects/seminar/assets/mask-rcnn-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/mask-rcnn-2.png
--------------------------------------------------------------------------------
/projects/seminar/assets/classification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/classification.png
--------------------------------------------------------------------------------
/projects/seminar/assets/understanding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/seminar/assets/understanding.png
--------------------------------------------------------------------------------
/projects/sudoku/images/sudoku-board-bare.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/sudoku/images/sudoku-board-bare.jpg
--------------------------------------------------------------------------------
/papers/ai_100_report_0901fnlc_single (1)(1).pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/papers/ai_100_report_0901fnlc_single (1)(1).pdf
--------------------------------------------------------------------------------
/projects/sudoku/images/Screenshot_20170831_204744.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/sudoku/images/Screenshot_20170831_204744.png
--------------------------------------------------------------------------------
/projects/sudoku/images/Screenshot_20170831_204758.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/projects/sudoku/images/Screenshot_20170831_204758.png
--------------------------------------------------------------------------------
/ci/dl_env.py:
--------------------------------------------------------------------------------
1 | import tensorflow as tf
2 |
3 | a = tf.constant(5)
4 | b = tf.constant(6)
5 | c = tf.add(a, b)
6 |
7 | with tf.Session() as sess:
8 | assert sess.run(c) == 11
9 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/assignments/images/fig2-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/01-Artificial-Intelligence/assignments/images/fig2-2.png
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/assignments/images/fig2-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/artificial-intelligence/master/01-Artificial-Intelligence/assignments/images/fig2-3.png
--------------------------------------------------------------------------------
/projects/sudoku/utils/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Thu Aug 31 20:14:15 2017
5 |
6 | @author: Anderson Banihirwe
7 | """
8 |
9 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/tests/test_agents.py:
--------------------------------------------------------------------------------
1 | import random
2 | from agents import Agent
3 |
4 | random.seed("airtificial-seed")
5 |
6 | def test_agent():
7 | a = Agent()
8 | assert isinstance(a, Agent)
9 |
--------------------------------------------------------------------------------
/environments/dl_env_mac.yml:
--------------------------------------------------------------------------------
1 | name: dl
2 | channels:
3 | - menpo
4 | - conda-forge
5 | - defaults
6 | dependencies:
7 | - python=3.6
8 | - numpy
9 | - scipy
10 | - pandas
11 | - jupyter
12 | - pillow
13 | - tensorflow
14 | - nltk
15 | - keras
16 | - scikit-image
17 | - scikit-learn
18 | - seaborn
19 | - bokeh
20 | - opencv3
21 | - flask
22 | - flask-socketio
23 | - cvxopt
24 |
--------------------------------------------------------------------------------
/environments/dl_env_linux_gpu.yml:
--------------------------------------------------------------------------------
1 | name: dl-gpu
2 | channels:
3 | - menpo
4 | - conda-forge
5 | - defaults
6 | dependencies:
7 | - python=3.6
8 | - numpy
9 | - scipy
10 | - pandas
11 | - jupyter
12 | - pillow
13 | - tensorflow-gpu
14 | - nltk
15 | - keras
16 | - scikit-image
17 | - scikit-learn
18 | - seaborn
19 | - bokeh
20 | - opencv3
21 | - flask
22 | - flask-socketio
23 | - cvxopt
24 |
--------------------------------------------------------------------------------
/environments/dl_env_windows.yml:
--------------------------------------------------------------------------------
1 | name: dl
2 | channels:
3 | - menpo
4 | - conda-forge
5 | - defaults
6 | dependencies:
7 | - python=3.6
8 | - numpy
9 | - scipy
10 | - pandas
11 | - jupyter
12 | - pillow
13 | - tensorflow
14 | - nltk
15 | - keras
16 | - scikit-image
17 | - scikit-learn
18 | - seaborn
19 | - bokeh
20 | - opencv3
21 | - flask
22 | - flask-socketio
23 | - cvxopt
24 | -pip:
25 | - coverage
26 | - coveralls
27 | - codecov
28 | - pytest
29 |
--------------------------------------------------------------------------------
/environments/dl_env_linux.yml:
--------------------------------------------------------------------------------
1 | name: dl
2 | channels:
3 | - menpo
4 | - conda-forge
5 | - defaults
6 | dependencies:
7 | - python=3.6
8 | - numpy
9 | - scipy
10 | - pandas
11 | - jupyter
12 | - pillow
13 | - tensorflow
14 | - nltk
15 | - keras
16 | - scikit-image
17 | - scikit-learn
18 | - seaborn
19 | - bokeh
20 | - opencv3
21 | - flask
22 | - flask-socketio
23 | - cvxopt
24 | - pip:
25 | - coverage
26 | - coveralls
27 | - codecov
28 | - pytest
29 |
--------------------------------------------------------------------------------
/projects/TSP/GA/test/test_tsp_ga.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))
4 |
5 | from tsp_ga import *
6 |
7 | cities = Cities(5)
8 | tours = alltours(cities)
9 |
10 | def test_cities():
11 | assert isinstance(cities, frozenset)
12 |
13 |
14 | def test_alltours():
15 | assert len(tours) == 24
16 |
17 | def test_tour_length():
18 | assert tour_length(tours) != None
19 |
20 | def test_plot():
21 | pass
22 |
--------------------------------------------------------------------------------
/projects/sudoku/utils/assets.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Thu Aug 31 20:15:04 2017
5 |
6 | @author: Anderson Banihirwe
7 | """
8 |
9 | import os
10 | import pygame
11 |
12 | def load_image(name):
13 | fullpath = os.path.join("images", name)
14 | try:
15 | image = pygame.image.load(fullpath)
16 | if image.get_alpha() == None:
17 | image = image.convert()
18 |
19 | else:
20 | image = image.convert_alpha()
21 |
22 |
23 | except pygame.error:
24 | print("Oops! Could not load image:", fullpath)
25 |
26 | return image, image.get_rect()
27 |
--------------------------------------------------------------------------------
/projects/sudoku/README.md:
--------------------------------------------------------------------------------
1 | # Diagonal Sudoku Solver
2 |
3 | 
4 |
5 | 
6 |
7 | The function (naked_twins) first looks for all boxes with only two values inside. The function then iterates over these boxes, finds all units the current box is a member of. Now having a box and a unit, the function looks for identical boxes. I a match is found, the boxes are called naked twins, and the values of this naked twins can be removed from all other boxes in the current unit.
8 |
9 | One important note to make is that it is tempting to detect pairs in all boxes, and flag them as candidates, and process through them one at the time. It is important to chech if the box previously flagged as pair, can have been pruned down to a single value in an earlier naked twin detection. A last check if the box is still a pair is important.
10 |
11 |
--------------------------------------------------------------------------------
/projects/sudoku/visualizer.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Thu Aug 31 20:32:37 2017
5 |
6 | @author: Anderson Banihirwe
7 | """
8 |
9 |
10 | from PySudoku import play
11 |
12 | def visualize_assignments(assignments):
13 | """ Visualizes the set of assignments created by the Sudoku AI"""
14 | last_assignment = None
15 | filtered_assignments = []
16 |
17 | for i in range(len(assignments)):
18 | if last_assignment:
19 | last_assignment_items = [item for item in last_assignment.items() if len(item[1]) == 1]
20 | current_assignment_items = [item for item in assignments[i].items() if len(item[1]) == 1]
21 | shared_items = set(last_assignment_items) & set(current_assignment_items)
22 | if len(shared_items) < len(current_assignment_items):
23 | filtered_assignments.append(assignments[i])
24 | last_assignment = assignments[i]
25 |
26 | play(filtered_assignments)
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/1-Introduction/Summary-of-Turing-original-paper-on-AI.md:
--------------------------------------------------------------------------------
1 | # [COMPUTING MACHINERY AND INTELLIGENCE](http://www.loebner.net/Prizef/TuringArticle.html)
2 |
By A. M. Turing
3 |
4 | ## The Imitation Game
5 | >"Can machines think?"
6 |
7 | - To define the meaning of the terms **machine** and **think**, Turing proposes a new form of the problem that can be described in terms of an imitation game.
8 |
9 | - The game is played with three people:
10 | - A man (A)
11 | - A woman (B)
12 | - An interrogator (C)
13 | - The interrogator stays in a room apart from the other two.
14 |
15 | - The object of the game for the interrogator is to determine which of the other two is the man and which is the woman.
16 |
17 | - He knows them by labels X and Y, and at the end of the game he says either **X is A and Y is B** or **X is B and Y is A**.
18 |
19 | - The answers should be written, or better still, typewritten.
20 |
21 | >What will happen when a machine takes the part of A in this game?
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Anderson Banihirwe
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # CI on Windows via appveyor
2 | # Adapted (minorly) from xarray's appveyor.yml, which itself
3 | # was based on Olivier Grisel's python-appveyor-demo
4 |
5 | environment:
6 |
7 | matrix:
8 | - PYTHON: "C:\\Python36-conda64"
9 | PYTHON_VERSION: "3.6"
10 | PYTHON_ARCH: "64"
11 | CONDA_ENV: "py36"
12 |
13 | install:
14 | # Install miniconda Python
15 | - "powershell ./ci/install_python.ps1"
16 |
17 | # Prepend newly installed Python to the PATH of this build (this cannot be
18 | # done from inside the powershell script as it would require to restart
19 | # the parent CMD process).
20 | - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
21 |
22 | # Check that we have the expected version and architecture for Python
23 | - "python --version"
24 | - "python -c \"import struct; print(struct.calcsize('P') * 8)\""
25 |
26 | # install xarray and depenencies
27 | - "conda --version"
28 | - "conda list"
29 | - "conda env create -f environments\\dl_windows.yml"
30 | - "activate dl"
31 | - "conda list"
32 |
33 | test_script:
34 | - "coverage run -m pytest"
35 | - "coverage report -m"
36 |
37 | on_success:
38 | - "coveralls"
39 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | notifications:
2 | email: false
3 |
4 | sudo: required
5 |
6 | dist: trusty
7 |
8 | language: python
9 | python:
10 | - "3.6"
11 |
12 | install:
13 | - sudo apt-get update
14 | # We do this conditionally because it saves us some downloading if the
15 | # version is the same.
16 | - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
17 | wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh;
18 | else
19 | wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
20 | fi
21 | - bash miniconda.sh -b -p $HOME/miniconda
22 | - export PATH="$HOME/miniconda/bin:$PATH"
23 | - hash -r
24 | - conda config --set always_yes yes --set changeps1 no
25 | - conda update -q conda
26 | # Useful for debugging any issues with conda
27 | - conda info -a
28 |
29 | # Create dl environment with packages from dl_env_linux.yml file
30 | #- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION --file ./ci/requirements.txt
31 | - conda env create -f ./environments/dl_env_linux.yml
32 |
33 | before_script:
34 | - source activate dl
35 | - conda list
36 |
37 | script:
38 | - coverage run -m pytest
39 | - coverage report -m
40 |
41 |
42 |
43 | after_success:
44 | - bash <(curl -s https://codecov.io/bash)
45 | - codecov
46 | - coveralls
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .ipynb_checkpoints
2 | *.ppt
3 | *.zip
4 | AI-ML
5 | .idea/workspace.xml
6 | .idea/vcs.xml
7 | .idea/modules.xml
8 | .idea/artificial-intelligence.iml
9 | .idea/misc.xml
10 | *.pyc
11 |
12 |
13 |
14 | # Byte-compiled / optimized / DLL files
15 | __pycache__/
16 | *.py[cod]
17 | *$py.class
18 |
19 | # C extensions
20 | *.so
21 |
22 | # Distribution / packaging
23 | .Python
24 | env/
25 | build/
26 | develop-eggs/
27 | dist/
28 | downloads/
29 | eggs/
30 | .eggs/
31 | lib/
32 | lib64/
33 | parts/
34 | sdist/
35 | var/
36 | wheels/
37 | *.egg-info/
38 | .installed.cfg
39 | *.egg
40 |
41 | # PyInstaller
42 | # Usually these files are written by a python script from a template
43 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
44 | *.manifest
45 | *.spec
46 |
47 | # Installer logs
48 | pip-log.txt
49 | pip-delete-this-directory.txt
50 |
51 | # Unit test / coverage reports
52 | htmlcov/
53 | .tox/
54 | .coverage
55 | .coverage.*
56 | .cache
57 | nosetests.xml
58 | coverage.xml
59 | *.cover
60 | .hypothesis/
61 |
62 | # Translations
63 | *.mo
64 | *.pot
65 |
66 | # Django stuff:
67 | *.log
68 | local_settings.py
69 |
70 | # Flask stuff:
71 | instance/
72 | .webassets-cache
73 |
74 | # Scrapy stuff:
75 | .scrapy
76 |
77 | # Sphinx documentation
78 | docs/_build/
79 |
80 | # PyBuilder
81 | target/
82 |
83 | # Jupyter Notebook
84 | .ipynb_checkpoints
85 |
86 | # pyenv
87 | .python-version
88 |
89 | # celery beat schedule file
90 | celerybeat-schedule
91 |
92 | # SageMath parsed files
93 | *.sage.py
94 |
95 | # dotenv
96 | .env
97 |
98 | # virtualenv
99 | .venv
100 | venv/
101 | ENV/
102 |
103 | # Spyder project settings
104 | .spyderproject
105 | .spyproject
106 |
107 | # Rope project settings
108 | .ropeproject
109 |
110 | # mkdocs documentation
111 | /site
112 |
113 | # mypy
114 | .mypy_cache/
115 |
--------------------------------------------------------------------------------
/projects/sudoku/PySudoku.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Thu Aug 31 19:28:33 2017
5 |
6 | @author: Anderson Banihirwe
7 | """
8 |
9 | import sys
10 | import os
11 | import random
12 | import pygame
13 | sys.path.append(os.path.join("utils"))
14 | import SudokuSquare
15 | from assets import *
16 |
17 | digits = '123456789'
18 | rows = 'ABCDEFGHI'
19 |
20 | def play(values_list):
21 | pygame.init()
22 |
23 |
24 | size = width, height = 700, 700
25 | screen = pygame.display.set_mode(size)
26 |
27 | background_image = pygame.image.load("./images/sudoku-board-bare.jpg").convert()
28 |
29 | clock = pygame.time.Clock()
30 |
31 | # The puzzleNumber sets a seed so either generate
32 | # a random number to fill in here or accept user
33 | # input for a duplicatable puzzle.
34 |
35 | for values in values_list:
36 | pygame.event.pump()
37 | theSquares = []
38 | initXLoc = 0
39 | initYLoc = 0
40 | startX, startY, editable, number = 0, 0, "N", 0
41 | for y in range(9):
42 | for x in range(9):
43 | if x in (0, 1, 2): startX = (x * 57) + 38
44 | if x in (3, 4, 5): startX = (x * 57) + 99
45 | if x in (6, 7, 8): startX = (x * 57) + 159
46 |
47 | if y in (0, 1, 2): startY = (y * 57) + 35
48 | if y in (3, 4, 5): startY = (y * 57) + 100
49 | if y in (6, 7, 8): startY = (y * 57) + 165
50 | col = digits[y]
51 | row = rows[x]
52 | string_number = values[row + col]
53 | if len(string_number) > 1 or string_number == '' or string_number == '.':
54 | number = None
55 | else:
56 | number = int(string_number)
57 | theSquares.append(SudokuSquare.SudokuSquare(number, startX, startY, editable, x, y))
58 |
59 | screen.blit(background_image, (0, 0))
60 | for num in theSquares:
61 | num.draw()
62 |
63 | pygame.display.flip()
64 | pygame.display.update()
65 | clock.tick(5)
66 |
67 |
68 | if __name__ == "__main__":
69 | main()
70 | sys.exit()
71 |
--------------------------------------------------------------------------------
/environments/README.md:
--------------------------------------------------------------------------------
1 |
2 | # How to Setup a Python Environment for Machine Learning and Deep Learning with Anaconda
3 |
4 | ## 1. Download the Anaconda Python package for your platform
5 |
6 | 1. Visit the [Anaconda homepage](https://www.continuum.io/).
7 | 2. Click “Anaconda” from the menu and click “Download” to go to the [download page](https://www.continuum.io/downloads).
8 | 
9 |
10 | 3. Choose the download suitable for your platform (Windows, OSX, or Linux):
11 | - Choose Python 3.6
12 | - Choose the Graphical Installer(Windows, OSX)
13 |
14 | 
15 |
16 | This will download the Anaconda Python package to your workstation.
17 |
18 | ## 2. Detailed Anaconda installation information
19 | This step assumes you have sufficient administrative privileges to install software on your system.
20 | For installation instructions, see the following:
21 |
22 | - **Installing on Windows** (https://docs.continuum.io/anaconda/install/windows)
23 | - **Installing on macOS** (https://docs.continuum.io/anaconda/install/mac-os)
24 | - **Installing on Linux** (https://docs.continuum.io/anaconda/install/linux)
25 |
26 | ## 3. Creating an environment from an environment.yml file
27 |
28 | In this step, we will install Python libraries used for deep learning, specifically: Theano, TensorFlow, and Keras, nltk.
29 | Most of machine learning and deep learning libraries needed are provided in the ```yaml (.yml)``` files.
30 |
31 | 1. Create the environment from the ```environment.yml``` file
32 | - **Linux CPU only**
33 | ```sh
34 | $ conda env create -f dl_env_linux.yml
35 | ```
36 | - **Linux With GPU support**
37 | ```sh
38 | $ conda env create -f dl_env_linux_gpu.yml
39 | ```
40 |
41 | - **Windows CPU only**
42 | ```sh
43 | $ conda env create -f dl_env_windows.yml
44 | ```
45 |
46 | - **macOS CPU only**
47 | ```sh
48 | $ conda env create -f dl_env_mac.yml
49 | ```
50 |
51 | 2. Activate the new environment:
52 |
53 | - Windows: ```activate myenv```
54 | - macOS and Linux: ```source activate myenv```
55 |
56 | NOTE: Replace myenv with the name of the environment.
57 |
58 | 3. Verify that the new environment was installed correctly:
59 |
60 | ```sh
61 | $ conda list
62 | ```
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | | **Linux/OSX** | [](https://travis-ci.org/andersy005/artificial-intelligence) |
2 | |---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
3 | | **Windows** | [](https://ci.appveyor.com/project/andersy005/artificial-intelligence/branch/master) |
4 |
5 |
6 | [](https://coveralls.io/github/andersy005/artificial-intelligence?branch=master)
7 |
8 | 
9 | # Artificial Intelligence - CPSC 4383
10 |
11 | Instructor: [ Mariofanna Milanova](http://ualr.edu/mgmilanova/index.html)
12 |
13 | This repo contains all my work: code base, notes, exercises and solutions to accompany Russell And Norvig's "Artificial Intelligence - A Modern Approach" and CPSC 4383/5383 Course.
14 |
15 | The screenshots and images are taken from, unless specified, [Artificial Intelligence: A Modern Approach](http://aima.cs.berkeley.edu/).
16 |
17 |
18 | >AI is defined as the study of agents that receive percepts from the environment and perform actions. Each such agent implements a function that maps percept sequences to actions.
19 |
20 |
21 | Implementations in Java, C++, and Python of many of the algorithms discussed in the textbook are available in the authors' [online code repository](http://aima.cs.berkeley.edu/code.html)
22 |
23 |
24 | ## Table of Contents
25 |
26 | - [ ] [Artificial Intelligence](https://github.com/andersy005/artificial-intelligence/tree/master/01-Artificial-Intelligence)
27 | - [ ] [Introduction](https://github.com/andersy005/artificial-intelligence/tree/master/01-Artificial-Intelligence/1-Introduction)
28 | - [ ] [Intelligent Agents](https://github.com/andersy005/artificial-intelligence/tree/master/01-Artificial-Intelligence/2-Intelligent-agents)
29 |
30 | - [ ] [Problem-solving]()
31 | - [ ] [Solving Problems by Searching]()
32 | - [ ] [Beyond Classical Search]()
33 | - [ ] [Adversarial Search]()
34 | - [ ] [Constraint Satisfaction]()
35 |
--------------------------------------------------------------------------------
/projects/TSP/GA/tsp_ga.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 | import statistics
4 | import itertools
5 | import functools
6 | import matplotlib.pyplot as plt
7 | import matplotlib
8 | matplotlib.style.use('seaborn')
9 | import numpy as np
10 |
11 |
12 |
13 |
14 | #------------------- Representing Cities--------------------------#
15 | class Point(complex):
16 | """Cities are represented as Points,
17 | which are a subclass of complex numbers."""
18 |
19 |
20 | x = property(lambda p: p.real)
21 | y = property(lambda p: p.imag)
22 |
23 | City = Point
24 |
25 |
26 | def Cities(n, width=900, height=600, seed=1234):
27 | "Make a set of n cities, each with random coordinates within a (width x height) rectangle."
28 | random.seed(seed * n)
29 | return frozenset((City(random.randrange(width), random.randrange(height))
30 | for c in range(n)))
31 |
32 |
33 | #-------------------Distance Between two cities ------------------#
34 | def distance(A, B):
35 | """Function to calculate the distance between two points"""
36 | return abs(A - B)
37 |
38 |
39 | #------------------------ Tours----------------------------------#
40 | def alltours(cities):
41 | """Return a list of tours, each a permutation of cities, but
42 | each one starting with the same city.
43 |
44 | So let's arbitrarily say that all tours must start with the first city in
45 | the set of cities. We'll just pull the first city out, and then tack
46 | it back on to all the permutations of the rest of the cities.
47 | This helps us keep all non-redundant tours only.
48 | """
49 | start = first(cities)
50 | return [[start] + Tour(rest)
51 | for rest in itertools.permutations(cities - {start})]
52 |
53 | def first(collection):
54 | """Start iterating over collection, and return the first element
55 | """
56 | return next(iter(collection))
57 |
58 | Tour = list # Tours are implemented as lists of cities.
59 |
60 |
61 | def tour_length(tours):
62 | "The total of distances between each pair of consecutive cities in the tour."
63 | dist_air = []
64 | for i in range(len(tours)):
65 | dist_air.append(sum([distance(tours[i][j], tours[i][j-1]) for j in range(len(tours[i]))]))
66 |
67 | return dist_air
68 |
69 |
70 |
71 | #---------------------- Plotting------------------------------------#
72 | def plot_tour(tour):
73 | "Plot the cities as circles and the tour as lines between them."
74 | plot_lines(list(tour) + [tour[0]])
75 |
76 | def plot_lines(points, style='bo-'):
77 | "Plot lines to connect a series of points."
78 | plt.plot([p.x for p in points], [p.y for p in points], style)
79 | plt.axis('scaled'); plt.axis('off')
80 | plt.show()
81 |
82 |
83 |
84 | if __name__ == "__main__":
85 | cities = Cities(5)
86 | #print(cities)
87 | #print(alltours(cities))
88 | tour_length(alltours(cities))
89 | for i in alltours(cities):
90 | plot_tour(i)
91 |
--------------------------------------------------------------------------------
/ci/install_python.ps1:
--------------------------------------------------------------------------------
1 | # Sample script to install Python and pip under Windows
2 | # Authors: Olivier Grisel, Jonathan Helmus and Kyle Kastner
3 | # License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
4 |
5 | $MINICONDA_URL = "http://repo.continuum.io/miniconda/"
6 | $BASE_URL = "https://www.python.org/ftp/python/"
7 |
8 |
9 | function DownloadMiniconda ($python_version, $platform_suffix) {
10 | $webclient = New-Object System.Net.WebClient
11 | if ($python_version -match "3.6") {
12 | $filename = "Miniconda3-latest-Windows-" + $platform_suffix + ".exe"
13 | } else {
14 | $filename = "Miniconda2-latest-Windows-" + $platform_suffix + ".exe"
15 | }
16 | $url = $MINICONDA_URL + $filename
17 |
18 | $basedir = $pwd.Path + "\"
19 | $filepath = $basedir + $filename
20 | if (Test-Path $filename) {
21 | Write-Host "Reusing" $filepath
22 | return $filepath
23 | }
24 |
25 | # Download and retry up to 3 times in case of network transient errors.
26 | Write-Host "Downloading" $filename "from" $url
27 | $retry_attempts = 2
28 | for($i=0; $i -lt $retry_attempts; $i++){
29 | try {
30 | $webclient.DownloadFile($url, $filepath)
31 | break
32 | }
33 | Catch [Exception]{
34 | Start-Sleep 1
35 | }
36 | }
37 | if (Test-Path $filepath) {
38 | Write-Host "File saved at" $filepath
39 | } else {
40 | # Retry once to get the error message if any at the last try
41 | $webclient.DownloadFile($url, $filepath)
42 | }
43 | return $filepath
44 | }
45 |
46 |
47 | function InstallMiniconda ($python_version, $architecture, $python_home) {
48 | Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
49 | if (Test-Path $python_home) {
50 | Write-Host $python_home "already exists, skipping."
51 | return $false
52 | }
53 | if ($architecture -match "32") {
54 | $platform_suffix = "x86"
55 | } else {
56 | $platform_suffix = "x86_64"
57 | }
58 |
59 | $filepath = DownloadMiniconda $python_version $platform_suffix
60 | Write-Host "Installing" $filepath "to" $python_home
61 | $install_log = $python_home + ".log"
62 | $args = "/S /D=$python_home"
63 | Write-Host $filepath $args
64 | Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
65 | if (Test-Path $python_home) {
66 | Write-Host "Python $python_version ($architecture) installation complete"
67 | } else {
68 | Write-Host "Failed to install Python in $python_home"
69 | Get-Content -Path $install_log
70 | Exit 1
71 | }
72 | }
73 |
74 |
75 | function InstallCondaPackages ($python_home, $spec) {
76 | $conda_path = $python_home + "\Scripts\conda.exe"
77 | $args = "install --yes " + $spec
78 | Write-Host ("conda " + $args)
79 | Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
80 | }
81 |
82 | function UpdateConda ($python_home) {
83 | $conda_path = $python_home + "\Scripts\conda.exe"
84 | Write-Host "Updating conda..."
85 | $args = "update --yes conda"
86 | Write-Host $conda_path $args
87 | Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
88 | }
89 |
90 |
91 | function main () {
92 | InstallMiniconda $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
93 | UpdateConda $env:PYTHON
94 | InstallCondaPackages $env:PYTHON "conda-build jinja2 anaconda-client"
95 | }
96 |
97 | main
98 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/assignments/Exercise 2.4.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "**Anderson Banihirwe**\n",
8 | "\n",
9 | "**August 21, 2017**\n",
10 | "\n",
11 | "**CPSC 4383**"
12 | ]
13 | },
14 | {
15 | "cell_type": "markdown",
16 | "metadata": {},
17 | "source": [
18 | "# Task 1: Exercise 2.4"
19 | ]
20 | },
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {},
24 | "source": [
25 | "Let us examine the rationality of various vacuum-cleaner agent functions ( Figure 2.2 ):\n",
26 | "\n",
27 | "\n",
28 | "\n",
29 | "A) Show that the simple vacuum-cleaner agent function described in Figure 2.3 is indeed rational under the assumptions listed on page 38\n",
30 | "\n",
31 | ">Page 38 describes an environment which is partially observable, deterministic and static; as such, the tabular agent in Fig. 2.3 can expect to maximize its utility in no more than four actions (the worst case is A: dirty, B: dirty; which results in either suck, right, suck, left, ... or suck, left, suck, right, ...).\n",
32 | "There is no time to e.g. build a model of dirt, since the dirt doesn't replentish itself.\n",
33 | "\n"
34 | ]
35 | },
36 | {
37 | "cell_type": "markdown",
38 | "metadata": {},
39 | "source": [
40 | "B) Describe a rational agent function for the modified performance measure that deducts one point for each movement. Does the corresponding agent program require internal state?"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {},
46 | "source": [
47 | ">The agent does require internal state: it should know, for instance, whether it has cleaned every square; and, if so, should stop."
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | "C) Discuss possible agent designs for the cases in which clean squares can become dirty and the geography of the environment is unknown. Does it make sense for the agent to learn from its experience in these cases? If so, what should it learn ."
55 | ]
56 | },
57 | {
58 | "cell_type": "markdown",
59 | "metadata": {},
60 | "source": [
61 | ">It should learn the geography of its environment to avoid wasting time trying to move off of it; it could maintain, furthermore, a dirt-distribution across the grid and favor those squares that tend to get dirty."
62 | ]
63 | }
64 | ],
65 | "metadata": {
66 | "kernelspec": {
67 | "display_name": "Python 3",
68 | "language": "python",
69 | "name": "python3"
70 | },
71 | "language_info": {
72 | "codemirror_mode": {
73 | "name": "ipython",
74 | "version": 3
75 | },
76 | "file_extension": ".py",
77 | "mimetype": "text/x-python",
78 | "name": "python",
79 | "nbconvert_exporter": "python",
80 | "pygments_lexer": "ipython3",
81 | "version": "3.6.2"
82 | },
83 | "toc": {
84 | "colors": {
85 | "hover_highlight": "#DAA520",
86 | "navigate_num": "#000000",
87 | "navigate_text": "#333333",
88 | "running_highlight": "#FF0000",
89 | "selected_highlight": "#FFD700",
90 | "sidebar_border": "#EEEEEE",
91 | "wrapper_background": "#FFFFFF"
92 | },
93 | "moveMenuLeft": true,
94 | "nav_menu": {
95 | "height": "30px",
96 | "width": "252px"
97 | },
98 | "navigate_menu": true,
99 | "number_sections": false,
100 | "sideBar": true,
101 | "threshold": 4,
102 | "toc_cell": false,
103 | "toc_section_display": "block",
104 | "toc_window_display": true,
105 | "widenNotebook": false
106 | }
107 | },
108 | "nbformat": 4,
109 | "nbformat_minor": 2
110 | }
111 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/agents.py:
--------------------------------------------------------------------------------
1 | """Implement Agents and Environments (Chapters 1-2).
2 | The class hierarchies are as follows:
3 | Thing ## A physical object that can exist in an environment
4 | Agent
5 | Wumpus
6 | Dirt
7 | Wall
8 | ...
9 | Environment ## An environment holds objects, runs simulations
10 | XYEnvironment
11 | VacuumEnvironment
12 | WumpusEnvironment
13 | An agent program is a callable instance, taking percepts and choosing actions
14 | SimpleReflexAgentProgram
15 | ...
16 | EnvGUI ## A window with a graphical representation of the Environment
17 | EnvToolbar ## contains buttons for controlling EnvGUI
18 | EnvCanvas ## Canvas to display the environment of an EnvGUI
19 | """
20 |
21 | import numpy as np
22 | import collections
23 | import copy
24 |
25 |
26 | class Thing:
27 | """This represents any physical object that can appear in an Environment.
28 | You subclass Thing to get the things you want. Each thing can have a
29 | .__name__ slot (used for output only)."""
30 | def __repr__(self):
31 | return '<{}>'.format(getattr(self, '__name__', self.__class__.__name__))
32 |
33 | def is_alive(self):
34 | """Things that are 'alive' should return true."""
35 | return hasattr(self, 'alive') and self.alive
36 |
37 | def show_state(self):
38 | """Display the agent's internal state. Subclasses should override."""
39 | print("I don't know how to show_state.")
40 |
41 | def display(self, canvas, x, y, width, height):
42 | """Display an image of this Thing on the canvas."""
43 | # Do we need this?
44 | pass
45 |
46 |
47 | class Agent(Thing):
48 | """An Agent is a subclass of Thing with one required slot,
49 | .program, which should hold a function that takes one argument, the
50 | percept, and returns an action. (What counts as a percept or action
51 | will depend on the specific environment in which the agent exists.)
52 | Note that 'program' is a slot, not a method. If it were a method,
53 | then the program could 'cheat' and look at aspects of the agent.
54 | It's not supposed to do that: the program can only look at the
55 | percepts. An agent program that needs a model of the world (and of
56 | the agent itself) will have to build and maintain its own model.
57 | There is an optional slot, .performance, which is a number giving
58 | the performance measure of the agent in its environment."""
59 |
60 | def __init__(self, program=None):
61 | self.alive = True
62 | self.bump = False
63 | self.holding = []
64 | self.performance = 0
65 | if program is None or not isinstance(program, collections.Callable):
66 | print("Can't find a valid program for {}, falling back to default.".format(
67 | self.__class__.__name__))
68 |
69 | def program(percept):
70 | return eval(input('Percept={}; action? '.format(percept)))
71 |
72 | self.program = program
73 |
74 | def can_grab(self, thing):
75 | """Returns True if this agent can grab this thing.
76 | Override for appropriate subclasses of Agent and Thing."""
77 | return False
78 |
79 | def TraceAgent(agent):
80 | """Wrap the agent's program to print its input and output. This will let
81 | you see what the agent is doing in the environment."""
82 | old_program = agent.program
83 |
84 | def new_program(percept):
85 | action = old_program(percept)
86 | print('{} perceives {} and does {}'.format(agent, percept, action))
87 | return action
88 |
89 | agent.program = new_program
90 | return agent
91 |
92 |
93 |
94 | __doc__ += """
95 | >>> a = Thing()
96 | >>> b = Agent()
97 | >>> b.alive
98 | """
99 |
100 |
101 |
--------------------------------------------------------------------------------
/projects/sudoku/utils/SudokuSquare.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Thu Aug 31 19:48:21 2017
5 |
6 | @author: Anderson Banihirwe
7 | """
8 |
9 | import pygame
10 | from pygame import *
11 |
12 |
13 | def AAfilledRoundedRect(surface, rect, color, radius=0.4):
14 | """
15 | Arguments:
16 | - surface : destination
17 | - rect : rectangle
18 | - color : rgb or rgba
19 | - radius : 0 <= radius <= 1
20 | """
21 |
22 | rect = Rect(rect)
23 | color = Color(*color)
24 | alpha = color.a
25 | color.a = 0
26 | pos = rect.topleft
27 | rect.topleft = 0,0
28 | rectangle = Surface(rect.size, SRCALPHA)
29 |
30 | circle = Surface([min(rect.size)*3]*2, SRCALPHA)
31 | draw.ellipse(circle, (0, 0, 0), circle.get_rect(), 0)
32 | circle = transform.smoothscale(circle, [int(min(rect.size) * radius)] * 2)
33 |
34 | radius = rectangle.blit(circle, (0, 0))
35 | radius.bottomright = rect.bottomright
36 | rectangle.blit(circle, radius)
37 | radius.topright = rect.topright
38 | rectangle.blit(circle, radius)
39 | radius.bottomleft = rect.bottomleft
40 | rectangle.blit(circle, radius)
41 |
42 | rectangle.fill((0,0,0), rect.inflate(-radius.w, 0))
43 | rectangle.fill((0,0,0), rect.inflate(0, -radius.h))
44 |
45 | rectangle.fill(color, special_flags=BLEND_RGBA_MAX)
46 | rectangle.fill((255,255,255, alpha), special_flags=BLEND_RGBA_MIN)
47 |
48 | return surface.blit(rectangle, pos)
49 |
50 |
51 |
52 | class SudokuSquare:
53 | """ A sudoku square class."""
54 | def __init__(self, number=None, offsetX=0, offsetY=0, edit="Y", xLoc=0, yLoc=0):
55 | if number != None:
56 | number = str(number)
57 | self.color = (2, 204, 186)
58 |
59 | else:
60 | number = ""
61 | self.color = (255, 255, 255)
62 |
63 | self.font = pygame.font.SysFont('opensans', 21)
64 | self.text = self.font.render(number, 1, (255, 255, 255))
65 | self.textpos = self.text.get_rect()
66 | self.textpos = self.textpos.move(offsetX + 17, offsetY + 4)
67 |
68 |
69 | self.edit = edit
70 | self.xLoc = xLoc
71 | self.yLoc = yLoc
72 | self.offsetX = offsetX
73 | self.offsetY = offsetY
74 |
75 |
76 | def draw(self):
77 | screen = pygame.display.get_surface()
78 | AAfilledRoundedRect(screen, (self.offsetX, self.offsetY, 45, 40), self.color)
79 |
80 | screen.blit(self.text, self.textpos)
81 |
82 |
83 | def checkCollide(self, collision):
84 | if len(collision) == 2:
85 | return self.collideRect.collidepoint(collision)
86 | elif len(collision) == 4:
87 | return self.collideRect.colliderect(collision)
88 | else:
89 | return False
90 |
91 |
92 | def highlight(self):
93 | self.collide.fill((190, 190, 255))
94 | self.draw()
95 |
96 |
97 | def unhighlight(self):
98 | self.collide.fill((255, 255, 255, 255))
99 | self.draw()
100 |
101 |
102 | def change(self, number):
103 | if number != None:
104 | number = str(number)
105 | else:
106 | number = ""
107 |
108 | if self.edit == "Y":
109 | self.text = self.font.render(number, 1, (0, 0, 0))
110 | self.draw()
111 | return 0
112 | else:
113 | return 1
114 |
115 |
116 | def currentLoc(self):
117 | return self.xLoc, self.yLoc
118 |
119 |
120 |
121 | if __name__=="__main__":
122 | pass
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/environments/dl_env_linux-v2.yml:
--------------------------------------------------------------------------------
1 | name: dl
2 | channels:
3 | - menpo
4 | - conda-forge
5 | - defaults
6 | dependencies:
7 | - asn1crypto=0.22.0=py36_0
8 | - backports.weakref=1.0rc1=py36_0
9 | - bkcharts=0.2=py36_0
10 | - blas=1.1=openblas
11 | - bleach=1.5.0=py36_0
12 | - bokeh=0.12.6=py36_0
13 | - bzip2=1.0.6=1
14 | - certifi=2017.7.27.1=py36_0
15 | - cffi=1.10.0=py36_0
16 | - chardet=3.0.4=py36_0
17 | - click=6.7=py36_0
18 | - cloudpickle=0.3.1=py36_0
19 | - cryptography=1.9=py36_0
20 | - cycler=0.10.0=py36_0
21 | - dask=0.15.1=py36_0
22 | - dbus=1.10.22=0
23 | - decorator=4.0.11=py36_0
24 | - distributed=1.18.0=py36_0
25 | - entrypoints=0.2.3=py36_1
26 | - expat=2.2.1=0
27 | - ffmpeg=3.2.4=1
28 | - flask=0.12.2=py36_0
29 | - flask-socketio=2.9.2=py36_0
30 | - fontconfig=2.12.1=4
31 | - freetype=2.7=1
32 | - gettext=0.19.7=1
33 | - glib=2.51.4=0
34 | - gmp=6.1.2=0
35 | - gst-plugins-base=1.8.0=0
36 | - gstreamer=1.8.0=2
37 | - h5py=2.7.0=np113py36_1
38 | - hdf5=1.8.18=0
39 | - heapdict=1.0.0=py36_0
40 | - html5lib=0.9999999=py36_0
41 | - icu=58.1=1
42 | - idna=2.5=py36_0
43 | - imageio=2.1.2=py36_0
44 | - ipykernel=4.6.1=py36_0
45 | - ipython=6.1.0=py36_0
46 | - ipython_genutils=0.2.0=py36_0
47 | - ipywidgets=7.0.0=py36_0
48 | - itsdangerous=0.24=py36_1
49 | - jedi=0.10.2=py36_0
50 | - jinja2=2.9.6=py36_0
51 | - jpeg=9b=0
52 | - jsonschema=2.5.1=py36_0
53 | - jupyter=1.0.0=py36_0
54 | - jupyter_client=5.1.0=py36_0
55 | - jupyter_console=5.1.0=py36_0
56 | - jupyter_core=4.3.0=py36_0
57 | - keras=2.0.6=py36_0
58 | - libffi=3.2.1=3
59 | - libgpuarray=0.6.9=0
60 | - libiconv=1.14=4
61 | - libpng=1.6.28=0
62 | - libsodium=1.0.10=0
63 | - libtiff=4.0.6=7
64 | - libxcb=1.12=1
65 | - libxml2=2.9.4=4
66 | - locket=0.2.0=py36_1
67 | - mako=1.0.7=py36_0
68 | - markupsafe=1.0=py36_0
69 | - matplotlib=2.0.2=py36_2
70 | - mistune=0.7.4=py36_0
71 | - mock=2.0.0=py36_0
72 | - moviepy=0.2.3.2=py36_0
73 | - msgpack-python=0.4.8=py36_0
74 | - nbconvert=5.2.1=py36_1
75 | - nbformat=4.3.0=py36_0
76 | - networkx=1.11=py36_0
77 | - nltk=3.2.4=py36_0
78 | - notebook=5.0.0=py36_0
79 | - numpy=1.13.1=py36_blas_openblas_200
80 | - olefile=0.44=py36_0
81 | - openblas=0.2.19=2
82 | - pandas=0.20.3=py36_1
83 | - pandoc=1.19.2=0
84 | - pandocfilters=1.4.1=py36_0
85 | - partd=0.3.8=py36_0
86 | - patsy=0.4.1=py36_0
87 | - pbr=3.1.1=py36_0
88 | - pcre=8.39=0
89 | - pexpect=4.2.1=py36_0
90 | - pickleshare=0.7.4=py36_0
91 | - pillow=4.2.1=py36_1
92 | - prompt_toolkit=1.0.15=py36_0
93 | - protobuf=3.3.2=py36_0
94 | - psutil=5.2.2=py36_0
95 | - ptyprocess=0.5.2=py36_0
96 | - pycparser=2.18=py36_0
97 | - pygments=2.2.0=py36_0
98 | - pygpu=0.6.9=np113py36_0
99 | - pyopenssl=16.2.0=py36_0
100 | - pyparsing=2.2.0=py36_0
101 | - pyqt=5.6.0=py36_4
102 | - pysocks=1.6.7=py36_0
103 | - python-dateutil=2.6.1=py36_0
104 | - python-engineio=1.7.0=py36_0
105 | - python-socketio=1.8.0=py36_0
106 | - pytz=2017.2=py36_0
107 | - pywavelets=0.5.2=np113py36_0
108 | - pyyaml=3.12=py36_1
109 | - pyzmq=16.0.2=py36_2
110 | - qt=5.6.2=3
111 | - qtconsole=4.3.1=py36_0
112 | - requests=2.18.4=py36_0
113 | - scikit-image=0.13.0=py36_1
114 | - scikit-learn=0.19.0=py36_blas_openblas_201
115 | - scipy=0.19.1=py36_blas_openblas_202
116 | - seaborn=0.8.0=py36_0
117 | - simplegeneric=0.8.1=py36_0
118 | - sip=4.18=py36_1
119 | - six=1.10.0=py36_1
120 | - sortedcontainers=1.5.7=py36_0
121 | - statsmodels=0.8.0=np113py36_0
122 | - tblib=1.3.2=py36_0
123 | - tensorflow=1.2.1=py36_0
124 | - terminado=0.6=py36_0
125 | - testpath=0.3=py36_0
126 | - theano=0.9.0=py36_1
127 | - toolz=0.8.2=py36_0
128 | - tornado=4.5.1=py36_0
129 | - tqdm=4.11.2=py36_0
130 | - traitlets=4.3.2=py36_0
131 | - urllib3=1.21.1=py36_1
132 | - wcwidth=0.1.7=py36_0
133 | - webencodings=0.5=py36_0
134 | - werkzeug=0.12.2=py36_0
135 | - widgetsnbextension=3.0.0=py36_0
136 | - x264=20131217=3
137 | - xorg-libxau=1.0.8=3
138 | - xorg-libxdmcp=1.1.2=3
139 | - yaml=0.1.6=0
140 | - zeromq=4.2.1=1
141 | - zict=0.1.2=py36_0
142 | - zlib=1.2.8=3
143 | - libgfortran=3.0.0=1
144 | - markdown=2.6.8=py36_0
145 | - openssl=1.0.2l=0
146 | - pip=9.0.1=py36_1
147 | - python=3.6.2=0
148 | - readline=6.2=2
149 | - setuptools=27.2.0=py36_0
150 | - sqlite=3.13.0=0
151 | - tk=8.5.18=0
152 | - wheel=0.29.0=py36_0
153 | - xz=5.2.3=0
154 | - opencv3=3.1.0=py36_0
155 | - pip:
156 | - ipython-genutils==0.2.0
157 | - jupyter-client==5.1.0
158 | - jupyter-console==5.1.0
159 | - jupyter-core==4.3.0
160 | - prompt-toolkit==1.0.15
161 |
--------------------------------------------------------------------------------
/environments/dl_env_linux_gpu-v2.yml:
--------------------------------------------------------------------------------
1 | name: dl-gpu
2 | channels:
3 | - menpo
4 | - conda-forge
5 | - defaults
6 | dependencies:
7 | - asn1crypto=0.22.0=py36_0
8 | - bkcharts=0.2=py36_0
9 | - blas=1.1=openblas
10 | - bleach=1.5.0=py36_0
11 | - bokeh=0.12.6=py36_0
12 | - certifi=2017.7.27.1=py36_0
13 | - chardet=3.0.4=py36_0
14 | - click=6.7=py36_0
15 | - cloudpickle=0.3.1=py36_0
16 | - cryptography=1.9=py36_0
17 | - cycler=0.10.0=py36_0
18 | - dask=0.15.1=py36_0
19 | - decorator=4.0.11=py36_0
20 | - distributed=1.18.0=py36_0
21 | - entrypoints=0.2.3=py36_1
22 | - flask=0.12.2=py36_0
23 | - flask-socketio=2.9.2=py36_0
24 | - fontconfig=2.12.1=4
25 | - freetype=2.7=1
26 | - gmp=6.1.2=0
27 | - h5py=2.7.0=np113py36_1
28 | - hdf5=1.8.18=1
29 | - heapdict=1.0.0=py36_0
30 | - html5lib=0.9999999=py36_0
31 | - icu=58.1=1
32 | - idna=2.5=py36_0
33 | - imageio=2.1.2=py36_0
34 | - ipykernel=4.6.1=py36_0
35 | - ipython=6.1.0=py36_0
36 | - ipython_genutils=0.2.0=py36_0
37 | - itsdangerous=0.24=py36_1
38 | - jedi=0.10.2=py36_0
39 | - jinja2=2.9.5=py36_0
40 | - jsonschema=2.5.1=py36_0
41 | - jupyter_client=5.1.0=py36_0
42 | - jupyter_contrib_core=0.3.1=py36_0
43 | - jupyter_contrib_nbextensions=0.2.8=py36_1
44 | - jupyter_core=4.3.0=py36_0
45 | - jupyter_highlight_selected_word=0.0.11=py36_0
46 | - jupyter_latex_envs=1.3.8.2=py36_1
47 | - jupyter_nbextensions_configurator=0.2.5=py36_0
48 | - keras=2.0.6=py36_0
49 | - libgpuarray=0.6.9=0
50 | - libpng=1.6.28=1
51 | - libsodium=1.0.10=0
52 | - libtiff=4.0.6=7
53 | - locket=0.2.0=py36_1
54 | - mako=1.0.7=py36_0
55 | - markupsafe=1.0=py36_0
56 | - matplotlib=2.0.2=py36_2
57 | - mistune=0.7.4=py36_0
58 | - moviepy=0.2.3.2=py36_0
59 | - msgpack-python=0.4.8=py36_0
60 | - nbconvert=5.2.1=py36_1
61 | - nbformat=4.3.0=py36_0
62 | - networkx=1.11=py36_0
63 | - nltk=3.2.4=py36_0
64 | - notebook=5.0.0=py36_0
65 | - numpy=1.13.1=py36_blas_openblas_200
66 | - olefile=0.44=py36_0
67 | - openblas=0.2.19=2
68 | - pandas=0.20.3=py36_1
69 | - pandoc=1.19.2=0
70 | - pandocfilters=1.4.1=py36_0
71 | - partd=0.3.8=py36_0
72 | - patsy=0.4.1=py36_0
73 | - pexpect=4.2.1=py36_0
74 | - pickleshare=0.7.3=py36_0
75 | - pillow=4.2.1=py36_1
76 | - prompt_toolkit=1.0.14=py36_0
77 | - psutil=5.2.1=py36_0
78 | - ptyprocess=0.5.2=py36_0
79 | - pygments=2.2.0=py36_0
80 | - pygpu=0.6.9=np113py36_0
81 | - pyopenssl=16.2.0=py36_0
82 | - pyparsing=2.2.0=py36_0
83 | - pysocks=1.6.7=py36_0
84 | - python-dateutil=2.6.1=py36_0
85 | - python-engineio=1.7.0=py36_0
86 | - python-socketio=1.8.0=py36_0
87 | - pytz=2017.2=py36_0
88 | - pywavelets=0.5.2=np113py36_0
89 | - pyyaml=3.12=py36_1
90 | - pyzmq=16.0.2=py36_2
91 | - qt=5.6.2=3
92 | - requests=2.18.4=py36_0
93 | - scikit-image=0.13.0=py36_1
94 | - scikit-learn=0.19.0=py36_blas_openblas_201
95 | - scipy=0.19.1=py36_blas_openblas_202
96 | - seaborn=0.8.0=py36_0
97 | - simplegeneric=0.8.1=py36_0
98 | - sortedcontainers=1.5.7=py36_0
99 | - statsmodels=0.8.0=np113py36_0
100 | - tblib=1.3.2=py36_0
101 | - terminado=0.6=py36_0
102 | - testpath=0.3=py36_0
103 | - theano=0.9.0=py36_1
104 | - toolz=0.8.2=py36_0
105 | - tornado=4.5.1=py36_0
106 | - tqdm=4.11.2=py36_0
107 | - traitlets=4.3.2=py36_0
108 | - urllib3=1.21.1=py36_1
109 | - wcwidth=0.1.7=py36_0
110 | - webencodings=0.5=py36_0
111 | - yaml=0.1.6=0
112 | - zeromq=4.2.1=1
113 | - zict=0.1.2=py36_0
114 | - accelerate_cudalib=2.0=0
115 | - backports=1.0=py36_0
116 | - backports.weakref=1.0rc1=py36_0
117 | - cffi=1.10.0=py36_0
118 | - cudatoolkit=8.0=1
119 | - cudnn=6.0.21=cuda8.0_0
120 | - dbus=1.10.20=0
121 | - expat=2.1.0=0
122 | - glib=2.50.2=1
123 | - gst-plugins-base=1.8.0=0
124 | - gstreamer=1.8.0=0
125 | - ipywidgets=6.0.0=py36_0
126 | - jpeg=9b=0
127 | - jupyter=1.0.0=py36_3
128 | - jupyter_console=5.1.0=py36_0
129 | - libffi=3.2.1=1
130 | - libgcc=5.2.0=0
131 | - libgfortran=3.0.0=1
132 | - libiconv=1.14=0
133 | - libprotobuf=3.2.0=0
134 | - libxcb=1.12=1
135 | - libxml2=2.9.4=0
136 | - llvmlite=0.19.0=py36_0
137 | - markdown=2.6.8=py36_0
138 | - mkl=2017.0.3=0
139 | - mkl-service=1.1.2=py36_3
140 | - nose=1.3.7=py36_1
141 | - numba=0.34.0=np113py36_0
142 | - openssl=1.0.2l=0
143 | - pcre=8.39=1
144 | - pip=9.0.1=py36_1
145 | - protobuf=3.2.0=py36_0
146 | - pycparser=2.17=py36_0
147 | - pyqt=5.6.0=py36_2
148 | - python=3.6.2=0
149 | - qtconsole=4.3.0=py36_0
150 | - readline=6.2=2
151 | - setuptools=27.2.0=py36_0
152 | - sip=4.18=py36_0
153 | - six=1.10.0=py36_0
154 | - snakeviz=0.4.1=py36_0
155 | - sqlite=3.13.0=0
156 | - tensorflow-gpu=1.2.1=py36cuda8.0cudnn6.0_0
157 | - tk=8.5.18=0
158 | - werkzeug=0.12.2=py36_0
159 | - wheel=0.29.0=py36_0
160 | - widgetsnbextension=2.0.0=py36_0
161 | - xz=5.2.2=1
162 | - zlib=1.2.8=3
163 | - ffmpeg=3.1.3=0
164 | - freeimage=3.17.0=0
165 | - opencv3=3.1.0=py36_0
166 | - pip:
167 | - ipython-genutils==0.2.0
168 | - jupyter-client==5.1.0
169 | - jupyter-console==5.1.0
170 | - jupyter-contrib-core==0.3.1
171 | - jupyter-contrib-nbextensions==0.2.8
172 | - jupyter-core==4.3.0
173 | - jupyter-highlight-selected-word==0.0.11
174 | - jupyter-latex-envs==1.3.8.2
175 | - jupyter-nbextensions-configurator==0.2.5
176 | - prompt-toolkit==1.0.14
177 | - tensorflow==1.2.1
178 |
179 |
--------------------------------------------------------------------------------
/projects/TSP/pyswarm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Sat Sep 2 15:36:28 2017
5 |
6 | @author: Anderson Banihirwe
7 |
8 | Simple Particle Swarm Optimization (PSO)
9 | """
10 |
11 | import random
12 | import math
13 | import time
14 | import numpy as np
15 |
16 | #---------- COST FUNCTION -----------------------------#
17 |
18 | # function to optimize (minimize)
19 | def cost_func(x):
20 | total = 0.0
21 | for i in range(len(x)):
22 | total += x[i]**2
23 |
24 | return total
25 |
26 |
27 |
28 | #------------MAIN----------------------------------------#
29 |
30 | class Particle:
31 | def __init__(self, x0):
32 | self.position_i = [] # particle position
33 | self.velocity_i = [] # particle velocity
34 | self.pos_best_i = [] # best position individual
35 | self.error_best_i = -1 # best error individual
36 | self.error_i = -1 # error individual
37 |
38 |
39 | for i in range(0, ndims):
40 | self.velocity_i.append(random.uniform(-1,1))
41 | self.position_i.append(x0[i])
42 |
43 | # evaluate current fitness
44 | def evaluate_fitness(self, costFunc):
45 | self.error_i = costFunc(self.position_i)
46 |
47 | # Check to see if the current position is an individual best
48 | if self.error_i < self.error_best_i or self.error_best_i == -1:
49 | self.pos_best_i = self.position_i
50 | self.error_best_i = self.error_i
51 |
52 |
53 | # update new particle velocity
54 | def update_velocity(self, pos_best_g):
55 | w = 0.5 # constant inertia weight (how much to weigh the previous velocity)
56 | c1 = 1 # cognitive constant
57 | c2 = 2 # social constant
58 |
59 | for i in range(0, ndims):
60 | r1 = random.random()
61 | r2 = random.random()
62 |
63 | vel_cognitive = c1 * r1 * (self.pos_best_i[i] - self.position_i[i])
64 | vel_social = c2 * r2 * (pos_best_g[i] - self.position_i[i])
65 | self.velocity_i[i] = w * self.velocity_i[i] + vel_cognitive + vel_social
66 |
67 |
68 | # update the particle position based off new velocity updates
69 | def update_position(self, bounds):
70 |
71 | for i in range(0, ndims):
72 | self.position_i[i] += self.velocity_i[i]
73 |
74 | # adjust maximum position if necessary
75 | if self.position_i[i] > bounds[i][1]:
76 | self.position_i[i] = bounds[i][1]
77 |
78 |
79 | # adjust minimum position if necessary
80 | if self.position_i[i] < bounds[i][0]:
81 | self.position_i[i] = bounds[i][0]
82 |
83 |
84 | class PSO():
85 | def __init__(self, costFunc, x0, bounds, nparticles, maxiter):
86 | global ndims
87 |
88 | ndims = len(x0)
89 | error_best_g = -1 # best error for group
90 | pos_best_g = [] # best position for group
91 |
92 | # establish the swarm
93 | swarm = []
94 | for i in range(0, nparticles):
95 | swarm.append(Particle(x0))
96 |
97 | # Find the time it takes to find the solution
98 |
99 | t0 = time.clock()
100 | # Begin optimization loop
101 | i = 0
102 | while i < maxiter:
103 |
104 | # cycle through particles in swarm and evaluate fitness
105 | for j in range(0, nparticles):
106 | swarm[j].evaluate_fitness(costFunc)
107 |
108 | # Determine if current particle is globally the best
109 | if swarm[j].error_i < error_best_g or error_best_g == -1:
110 | pos_best_g = list(swarm[j].position_i)
111 | error_best_g = float(swarm[j].error_i)
112 |
113 |
114 | # cycle through swarm and update velocities and positions
115 | for j in range(0, nparticles):
116 | swarm[j].update_velocity(pos_best_g)
117 | swarm[j].update_position(bounds)
118 |
119 | i+= 1
120 | t1 = time.clock()
121 |
122 | # Final Results
123 | print("---Optimal solution found in {:.3f} secs for {} particles\n".format(t1 - t0, nparticles))
124 | print("Best position : {}".format(pos_best_g))
125 | print("Best Error : {}".format(error_best_g))
126 | print("-------------------------------------------------------")
127 |
128 |
129 | if __name__ == "__main__":
130 |
131 | initial = [5, 5]
132 | bounds = [(-10, 10), (-10, 10)]
133 | PSO(cost_func, initial, bounds, nparticles=1000, maxiter=100)
134 |
135 |
--------------------------------------------------------------------------------
/projects/sudoku/solver.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Thu Aug 31 20:35:18 2017
5 |
6 | @author: Anderson Banihirwe
7 | """
8 |
9 | from itertools import product, combinations
10 |
11 | assignments = []
12 | rows = 'ABCDEFGHI'
13 | cols = '123456789'
14 |
15 |
16 | def assign_value(values, box, value):
17 | """
18 | Please use this function to update your values dictionary!
19 | Assigns a value to a given box. If it updates the board record it.
20 | """
21 | values[box] = value
22 | if len(value) == 1:
23 | assignments.append(values.copy())
24 | return values
25 |
26 |
27 | def naked_twins(values):
28 | """Eliminate values using the naked twins strategy.
29 | Args:
30 | values(dict): a dictionary of the form {'box_name': '123456789', ...}
31 | Returns:
32 | the values dictionary with the naked twins eliminated from peers.
33 | """
34 | twin_values = [box for box in values.keys() if len(values[box]) == 2]
35 | for box in twin_values:
36 | candidate = values[box]
37 | if len(candidate) != 2:
38 | continue
39 |
40 | box_units = units[box]
41 | for u in box_units:
42 | naked_pair_found = False
43 |
44 | # Find all instances of naked twins
45 | for b in u:
46 | if b != box and values[b] == candidate:
47 | naked_pair_found = True
48 |
49 | # Eliminate the naked twins as possibilities for their peers
50 | if naked_pair_found:
51 | for bx in u:
52 | if values[bx] != candidate:
53 | for d in candidate:
54 | values = assign_value(values, bx, values[bx].replace(d, ''))
55 |
56 | return values
57 |
58 |
59 | def cross(A, B):
60 | "Cross product of elements in A and elements in B."
61 | #return [s + t for s in A for t in B]
62 | return ['%s%s' % item for item in product(A, B)]
63 |
64 |
65 |
66 | boxes = cross(rows, cols)
67 |
68 | row_units = [cross(r, cols) for r in rows]
69 | column_units = [cross(rows, c) for c in cols]
70 | square_units = [cross(rs, cs) for rs in ('ABC', 'DEF', 'GHI') for cs in ('123', '456', '789')]
71 |
72 | # To solve the second question
73 | diagonal_units = [['A1', 'B2', 'C3', 'D4', 'E5', 'F6', 'G7', 'H8', 'I9'], ['A9', 'B8', 'C7', 'D6', 'E5', 'F4', 'G3', 'H2', 'I1']]
74 |
75 | unitlist = row_units + column_units + square_units + diagonal_units
76 | units = dict((s, [u for u in unitlist if s in u]) for s in boxes)
77 | peers = dict((s, set(sum(units[s], [])) - set([s])) for s in boxes)
78 |
79 |
80 | def grid_values(grid):
81 | "Convert grid into a dict of {square: char} with '.' for empties."
82 | chars = []
83 | digits = '123456789'
84 | for c in grid:
85 | if c in digits:
86 | chars.append(c)
87 | if c == '.':
88 | chars.append(digits)
89 | assert len(chars) == 81
90 | return dict(zip(boxes, chars))
91 |
92 |
93 | def display(values):
94 | "Display these values as a 2-D grid."
95 | width = 1 + max(len(values[s]) for s in boxes)
96 | line = '+'.join(['-' * (width * 3)] * 3)
97 | for r in rows:
98 | print(''.join(values[r + c].center(width) + ('|' if c in '36' else '')
99 | for c in cols))
100 | if r in 'CF': print(line)
101 | print
102 |
103 |
104 | def eliminate(values):
105 | """
106 | Go through all the boxes, and whenever there is a box with a value, eliminate this value from the values of all its peers.
107 | Input: A sudoku in dictionary form.
108 | Output: The resulting sudoku in dictionary form.
109 | """
110 | solved_values = [box for box in values.keys() if len(values[box]) == 1]
111 | for box in solved_values:
112 | digit = values[box]
113 | for peer in peers[box]:
114 | values = assign_value(values, peer, values[peer].replace(digit, ''))
115 | return values
116 |
117 |
118 | def only_choice(values):
119 | """
120 | Go through all the units, and whenever there is a unit with a value that only fits in one box, assign the value to this box.
121 | Input: A sudoku in dictionary form.
122 | Output: The resulting sudoku in dictionary form.
123 | """
124 | for unit in unitlist:
125 | for digit in '123456789':
126 | dplaces = [box for box in unit if digit in values[box]]
127 | if len(dplaces) == 1:
128 | values = assign_value(values, dplaces[0], digit)
129 | return values
130 |
131 |
132 | def reduce_puzzle(values):
133 | stalled = False
134 | while not stalled:
135 | solved_values_before = len([box for box in values.keys() if len(values[box]) == 1])
136 | values = eliminate(values)
137 | values = only_choice(values)
138 | values = naked_twins(values)
139 | solved_values_after = len([box for box in values.keys() if len(values[box]) == 1])
140 | stalled = solved_values_before == solved_values_after
141 | if len([box for box in values.keys() if len(values[box]) == 0]):
142 | return False
143 | return values
144 |
145 |
146 | def solve(grid):
147 | values = reduce_puzzle(grid_values(grid))
148 | if values is False:
149 | return False
150 | if solved(values):
151 | return values
152 | n, s = min((len(values[s]), s) for s in boxes if len(values[s]) > 1)
153 | for value in values[s]:
154 | new_sudoku = values.copy()
155 | new_sudoku[s] = value
156 | attempt = solve(new_sudoku)
157 | if attempt:
158 | return attempt
159 |
160 |
161 | def solved(values):
162 | return all(len(values[s]) == 1 for s in boxes)
163 |
164 |
165 | diag_sudoku_grid = '2.............62....1....7...6..8...3...9...7...6..4...4....8....52.............3'
166 | #diag_sudoku_grid = '8..........36......7..9.2...5...7.......457.....1...3...1....68..85...1..9....4..'
167 | #diag_sudoku_grid = '...............9..97.3......1..6.5....47.8..2.....2..6.31..4......8..167.87......'
168 | #diag_sudoku_grid = '..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'
169 | display(solve(diag_sudoku_grid))
170 |
171 | try:
172 | from visualizer import visualize_assignments
173 | visualize_assignments(assignments)
174 | except Exception as e:
175 | print(e)
176 | print('We could not visualize your board due to a pygame issue. Not a problem! It is not a requirement.')
177 |
--------------------------------------------------------------------------------
/projects/sudoku/solver_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Thu Aug 31 20:41:28 2017
5 |
6 | @author: Anderson Banihirwe
7 | """
8 |
9 | import solver
10 | import unittest
11 |
12 |
13 | class TestNakedTwins(unittest.TestCase):
14 | before_naked_twins_1 = {'I6': '4', 'H9': '3', 'I2': '6', 'E8': '1', 'H3': '5', 'H7': '8', 'I7': '1', 'I4': '8',
15 | 'H5': '6', 'F9': '7', 'G7': '6', 'G6': '3', 'G5': '2', 'E1': '8', 'G3': '1', 'G2': '8',
16 | 'G1': '7', 'I1': '23', 'C8': '5', 'I3': '23', 'E5': '347', 'I5': '5', 'C9': '1', 'G9': '5',
17 | 'G8': '4', 'A1': '1', 'A3': '4', 'A2': '237', 'A5': '9', 'A4': '2357', 'A7': '27',
18 | 'A6': '257', 'C3': '8', 'C2': '237', 'C1': '23', 'E6': '579', 'C7': '9', 'C6': '6',
19 | 'C5': '37', 'C4': '4', 'I9': '9', 'D8': '8', 'I8': '7', 'E4': '6', 'D9': '6', 'H8': '2',
20 | 'F6': '125', 'A9': '8', 'G4': '9', 'A8': '6', 'E7': '345', 'E3': '379', 'F1': '6',
21 | 'F2': '4', 'F3': '23', 'F4': '1235', 'F5': '8', 'E2': '37', 'F7': '35', 'F8': '9',
22 | 'D2': '1', 'H1': '4', 'H6': '17', 'H2': '9', 'H4': '17', 'D3': '2379', 'B4': '27',
23 | 'B5': '1', 'B6': '8', 'B7': '27', 'E9': '2', 'B1': '9', 'B2': '5', 'B3': '6', 'D6': '279',
24 | 'D7': '34', 'D4': '237', 'D5': '347', 'B8': '3', 'B9': '4', 'D1': '5'}
25 | possible_solutions_1 = [
26 | {'G7': '6', 'G6': '3', 'G5': '2', 'G4': '9', 'G3': '1', 'G2': '8', 'G1': '7', 'G9': '5', 'G8': '4', 'C9': '1',
27 | 'C8': '5', 'C3': '8', 'C2': '237', 'C1': '23', 'C7': '9', 'C6': '6', 'C5': '37', 'A4': '2357', 'A9': '8',
28 | 'A8': '6', 'F1': '6', 'F2': '4', 'F3': '23', 'F4': '1235', 'F5': '8', 'F6': '125', 'F7': '35', 'F8': '9',
29 | 'F9': '7', 'B4': '27', 'B5': '1', 'B6': '8', 'B7': '27', 'E9': '2', 'B1': '9', 'B2': '5', 'B3': '6', 'C4': '4',
30 | 'B8': '3', 'B9': '4', 'I9': '9', 'I8': '7', 'I1': '23', 'I3': '23', 'I2': '6', 'I5': '5', 'I4': '8', 'I7': '1',
31 | 'I6': '4', 'A1': '1', 'A3': '4', 'A2': '237', 'A5': '9', 'E8': '1', 'A7': '27', 'A6': '257', 'E5': '347',
32 | 'E4': '6', 'E7': '345', 'E6': '579', 'E1': '8', 'E3': '79', 'E2': '37', 'H8': '2', 'H9': '3', 'H2': '9',
33 | 'H3': '5', 'H1': '4', 'H6': '17', 'H7': '8', 'H4': '17', 'H5': '6', 'D8': '8', 'D9': '6', 'D6': '279',
34 | 'D7': '34', 'D4': '237', 'D5': '347', 'D2': '1', 'D3': '79', 'D1': '5'},
35 | {'I6': '4', 'H9': '3', 'I2': '6', 'E8': '1', 'H3': '5', 'H7': '8', 'I7': '1', 'I4': '8', 'H5': '6', 'F9': '7',
36 | 'G7': '6', 'G6': '3', 'G5': '2', 'E1': '8', 'G3': '1', 'G2': '8', 'G1': '7', 'I1': '23', 'C8': '5', 'I3': '23',
37 | 'E5': '347', 'I5': '5', 'C9': '1', 'G9': '5', 'G8': '4', 'A1': '1', 'A3': '4', 'A2': '237', 'A5': '9',
38 | 'A4': '2357', 'A7': '27', 'A6': '257', 'C3': '8', 'C2': '237', 'C1': '23', 'E6': '579', 'C7': '9', 'C6': '6',
39 | 'C5': '37', 'C4': '4', 'I9': '9', 'D8': '8', 'I8': '7', 'E4': '6', 'D9': '6', 'H8': '2', 'F6': '125',
40 | 'A9': '8', 'G4': '9', 'A8': '6', 'E7': '345', 'E3': '79', 'F1': '6', 'F2': '4', 'F3': '23', 'F4': '1235',
41 | 'F5': '8', 'E2': '3', 'F7': '35', 'F8': '9', 'D2': '1', 'H1': '4', 'H6': '17', 'H2': '9', 'H4': '17',
42 | 'D3': '79', 'B4': '27', 'B5': '1', 'B6': '8', 'B7': '27', 'E9': '2', 'B1': '9', 'B2': '5', 'B3': '6',
43 | 'D6': '279', 'D7': '34', 'D4': '237', 'D5': '347', 'B8': '3', 'B9': '4', 'D1': '5'}
44 | ]
45 |
46 | before_naked_twins_2 = {'A1': '23', 'A2': '4', 'A3': '7', 'A4': '6', 'A5': '8', 'A6': '5', 'A7': '23', 'A8': '9',
47 | 'A9': '1', 'B1': '6', 'B2': '9', 'B3': '8', 'B4': '4', 'B5': '37', 'B6': '1', 'B7': '237',
48 | 'B8': '5', 'B9': '237', 'C1': '23', 'C2': '5', 'C3': '1', 'C4': '23', 'C5': '379',
49 | 'C6': '2379', 'C7': '8', 'C8': '6', 'C9': '4', 'D1': '8', 'D2': '17', 'D3': '9',
50 | 'D4': '1235', 'D5': '6', 'D6': '237', 'D7': '4', 'D8': '27', 'D9': '2357', 'E1': '5',
51 | 'E2': '6', 'E3': '2', 'E4': '8', 'E5': '347', 'E6': '347', 'E7': '37', 'E8': '1', 'E9': '9',
52 | 'F1': '4', 'F2': '17', 'F3': '3', 'F4': '125', 'F5': '579', 'F6': '279', 'F7': '6',
53 | 'F8': '8', 'F9': '257', 'G1': '1', 'G2': '8', 'G3': '6', 'G4': '35', 'G5': '345',
54 | 'G6': '34', 'G7': '9', 'G8': '27', 'G9': '27', 'H1': '7', 'H2': '2', 'H3': '4', 'H4': '9',
55 | 'H5': '1', 'H6': '8', 'H7': '5', 'H8': '3', 'H9': '6', 'I1': '9', 'I2': '3', 'I3': '5',
56 | 'I4': '7', 'I5': '2', 'I6': '6', 'I7': '1', 'I8': '4', 'I9': '8'}
57 | possible_solutions_2 = [
58 | {'A1': '23', 'A2': '4', 'A3': '7', 'A4': '6', 'A5': '8', 'A6': '5', 'A7': '23', 'A8': '9', 'A9': '1', 'B1': '6',
59 | 'B2': '9', 'B3': '8', 'B4': '4', 'B5': '37', 'B6': '1', 'B7': '237', 'B8': '5', 'B9': '237', 'C1': '23',
60 | 'C2': '5', 'C3': '1', 'C4': '23', 'C5': '79', 'C6': '79', 'C7': '8', 'C8': '6', 'C9': '4', 'D1': '8',
61 | 'D2': '17', 'D3': '9', 'D4': '1235', 'D5': '6', 'D6': '237', 'D7': '4', 'D8': '27', 'D9': '2357', 'E1': '5',
62 | 'E2': '6', 'E3': '2', 'E4': '8', 'E5': '347', 'E6': '347', 'E7': '37', 'E8': '1', 'E9': '9', 'F1': '4',
63 | 'F2': '17', 'F3': '3', 'F4': '125', 'F5': '579', 'F6': '279', 'F7': '6', 'F8': '8', 'F9': '257', 'G1': '1',
64 | 'G2': '8', 'G3': '6', 'G4': '35', 'G5': '345', 'G6': '34', 'G7': '9', 'G8': '27', 'G9': '27', 'H1': '7',
65 | 'H2': '2', 'H3': '4', 'H4': '9', 'H5': '1', 'H6': '8', 'H7': '5', 'H8': '3', 'H9': '6', 'I1': '9', 'I2': '3',
66 | 'I3': '5', 'I4': '7', 'I5': '2', 'I6': '6', 'I7': '1', 'I8': '4', 'I9': '8'},
67 | {'A1': '23', 'A2': '4', 'A3': '7', 'A4': '6', 'A5': '8', 'A6': '5', 'A7': '23', 'A8': '9', 'A9': '1', 'B1': '6',
68 | 'B2': '9', 'B3': '8', 'B4': '4', 'B5': '3', 'B6': '1', 'B7': '237', 'B8': '5', 'B9': '237', 'C1': '23',
69 | 'C2': '5', 'C3': '1', 'C4': '23', 'C5': '79', 'C6': '79', 'C7': '8', 'C8': '6', 'C9': '4', 'D1': '8',
70 | 'D2': '17', 'D3': '9', 'D4': '1235', 'D5': '6', 'D6': '237', 'D7': '4', 'D8': '27', 'D9': '2357', 'E1': '5',
71 | 'E2': '6', 'E3': '2', 'E4': '8', 'E5': '347', 'E6': '347', 'E7': '37', 'E8': '1', 'E9': '9', 'F1': '4',
72 | 'F2': '17', 'F3': '3', 'F4': '125', 'F5': '579', 'F6': '279', 'F7': '6', 'F8': '8', 'F9': '257', 'G1': '1',
73 | 'G2': '8', 'G3': '6', 'G4': '35', 'G5': '345', 'G6': '34', 'G7': '9', 'G8': '27', 'G9': '27', 'H1': '7',
74 | 'H2': '2', 'H3': '4', 'H4': '9', 'H5': '1', 'H6': '8', 'H7': '5', 'H8': '3', 'H9': '6', 'I1': '9', 'I2': '3',
75 | 'I3': '5', 'I4': '7', 'I5': '2', 'I6': '6', 'I7': '1', 'I8': '4', 'I9': '8'}
76 | ]
77 |
78 | def test_naked_twins(self):
79 | self.assertTrue(solver.naked_twins(self.before_naked_twins_1) in self.possible_solutions_1,
80 | "Your naked_twins function produced an unexpected board.")
81 |
82 | def test_naked_twins2(self):
83 | self.assertTrue(solver.naked_twins(self.before_naked_twins_2) in self.possible_solutions_2,
84 | "Your naked_twins function produced an unexpected board.")
85 |
86 |
87 |
88 | class TestDiagonalSudoku(unittest.TestCase):
89 | diagonal_grid = '2.............62....1....7...6..8...3...9...7...6..4...4....8....52.............3'
90 | solved_diag_sudoku = {'G7': '8', 'G6': '9', 'G5': '7', 'G4': '3', 'G3': '2', 'G2': '4', 'G1': '6', 'G9': '5',
91 | 'G8': '1', 'C9': '6', 'C8': '7', 'C3': '1', 'C2': '9', 'C1': '4', 'C7': '5', 'C6': '3',
92 | 'C5': '2', 'C4': '8', 'E5': '9', 'E4': '1', 'F1': '1', 'F2': '2', 'F3': '9', 'F4': '6',
93 | 'F5': '5', 'F6': '7', 'F7': '4', 'F8': '3', 'F9': '8', 'B4': '7', 'B5': '1', 'B6': '6',
94 | 'B7': '2', 'B1': '8', 'B2': '5', 'B3': '3', 'B8': '4', 'B9': '9', 'I9': '3', 'I8': '2',
95 | 'I1': '7', 'I3': '8', 'I2': '1', 'I5': '6', 'I4': '5', 'I7': '9', 'I6': '4', 'A1': '2',
96 | 'A3': '7', 'A2': '6', 'E9': '7', 'A4': '9', 'A7': '3', 'A6': '5', 'A9': '1', 'A8': '8',
97 | 'E7': '6', 'E6': '2', 'E1': '3', 'E3': '4', 'E2': '8', 'E8': '5', 'A5': '4', 'H8': '6',
98 | 'H9': '4', 'H2': '3', 'H3': '5', 'H1': '9', 'H6': '1', 'H7': '7', 'H4': '2', 'H5': '8',
99 | 'D8': '9', 'D9': '2', 'D6': '8', 'D7': '1', 'D4': '4', 'D5': '3', 'D2': '7', 'D3': '6',
100 | 'D1': '5'}
101 |
102 | def test_solve(self):
103 | self.assertEqual(solver.solve(self.diagonal_grid), self.solved_diag_sudoku)
104 |
105 | if __name__ == '__main__':
106 | unittest.main()
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/1-Introduction/introduction.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "toc": "true"
7 | },
8 | "source": [
9 | "# Table of Contents\n",
10 | " "
11 | ]
12 | },
13 | {
14 | "cell_type": "markdown",
15 | "metadata": {},
16 | "source": [
17 | "# Introduction"
18 | ]
19 | },
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {},
23 | "source": [
24 | "## What is AI?"
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | ""
32 | ]
33 | },
34 | {
35 | "cell_type": "markdown",
36 | "metadata": {},
37 | "source": [
38 | "### Acting humamly: The Turing Test approach"
39 | ]
40 | },
41 | {
42 | "cell_type": "markdown",
43 | "metadata": {},
44 | "source": [
45 | "- **The Turing Test**, was proposed by Alan Turing (1950)\n",
46 | "- Designed to provide a satisfactory operational definition of intelligence.\n",
47 | "- A computer passes the test if a human interrogator, after posing some written questions, cannot tell whether the written responses come from a person or from a computer.\n",
48 | "- The computer would need to possess the following capabilities:\n",
49 | " - **natural language processing** to enable it to communicate successfully in English.\n",
50 | " - **knowledge representation** to store what it knows or hears.\n",
51 | " - **automated reasoning** to use the stored information to answer questions and to draw new conclusions.\n",
52 | " - **machine learning** to adapt to new circumstances and to detect and extrapolate patterns.\n",
53 | " \n",
54 | "- Turing's test deliberately avoided direct physical interaction between the interrogator and the computer, because physical simulation of a person is unnecessary for intelligence.\n",
55 | "\n",
56 | "- **The Total Turing Test** includes a video signal so that the interrogator can test the subject's perceptual abilities, as well the opportunity for the interrogator to pass physical objects through the hatch.\n",
57 | "- To pass the total turing test, the computer will need:\n",
58 | " - **computer vision** to perceive objects, and\n",
59 | " - **robotics** to manipulate objects and move about."
60 | ]
61 | },
62 | {
63 | "cell_type": "markdown",
64 | "metadata": {},
65 | "source": [
66 | "### Thinking humanly: The cognitive modeling approach"
67 | ]
68 | },
69 | {
70 | "cell_type": "markdown",
71 | "metadata": {},
72 | "source": [
73 | "- The interdisciplinary field of **cognitive science** brings together computer models from AI and experimental techniques from psychology to construct precise and testable theories of human mind."
74 | ]
75 | },
76 | {
77 | "cell_type": "markdown",
78 | "metadata": {},
79 | "source": [
80 | "### Thinking rationally: The \"laws of thought\" approach"
81 | ]
82 | },
83 | {
84 | "cell_type": "markdown",
85 | "metadata": {},
86 | "source": [
87 | "- Logicians in the 19th century developed a precise notation for statements about all kinds of objects in the world and the relations among them. \n",
88 | "- By 1965, programs existed that could, in principle, solve any solvable problem described in logical notation. (Although if no solution exists, the program might loop forever.) \n",
89 | "- The so-called logicist tradition within artificial intelligence hopes to build on such programs to create intelligent systems."
90 | ]
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {},
95 | "source": [
96 | "**There are two main obstacles to this approach.**\n",
97 | "- First, it is not easy to take informal knowledge and state it in the formal terms required by logical notation, particularly when the knowledge is less than 100% certain. \n",
98 | "- Second, there is a big difference between solving a problem “in principle” and solving it in practice. Even problems with just a few hundred facts can exhaust the computational resources of any computer unless it has some guidance as to which reasoning steps to try first. Although both of these obstacles apply to any attempt to build computational reasoning systems, they appeared first in the logicist tradition.\n"
99 | ]
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {},
104 | "source": [
105 | "### Acting rationally: The rational agent approach"
106 | ]
107 | },
108 | {
109 | "cell_type": "markdown",
110 | "metadata": {},
111 | "source": [
112 | "- An **agent** is just something that acts.\n",
113 | "- A **rational agent** is one that acts so as to achieve the best outcome or, when there is uncertainty, the best expected outcome.\n",
114 | "- The rational-agent approach has two advantages over the other approaches:\n",
115 | " - First, it is more general than the \"laws of thought\" approach because correct inference is just one of several possible mechanisms for achieving rationality.\n",
116 | " - Second, it is more amenable to scientific development than are approaches based on human behavior or human thought."
117 | ]
118 | },
119 | {
120 | "cell_type": "markdown",
121 | "metadata": {},
122 | "source": [
123 | "## The Foundations of AI"
124 | ]
125 | },
126 | {
127 | "cell_type": "markdown",
128 | "metadata": {},
129 | "source": [
130 | "- **Philosophers** (going back to 400 B. C .) made AI conceivable by considering the ideas that the mind is in some ways like a machine, that it operates on knowledge encoded in some internal language, and that thought can be used to choose what actions to take.\n",
131 | "- **Mathematicians** provided the tools to manipulate statements of logical certainty as well as uncertain, probabilistic statements. They also set the groundwork for understanding computation and reasoning about algorithms.\n",
132 | "- **Economists** formalized the problem of making decisions that maximize the expected outcome to the decision maker.\n",
133 | "- **Neuroscientists** discovered some facts about how the brain works and the ways in which it is similar to and different from computers.\n",
134 | "- **Psychologists** adopted the idea that humans and animals can be considered information-processing machines. Linguists showed that language use fits into this model.\n",
135 | "- **Computer engineers** provided the ever-more-powerful machines that make AI applications possible.\n",
136 | "- **Control theory** deals with designing devices that act optimally on the basis of feedback from the environment. Initially, the mathematical tools of control theory were quite different from AI, but the fields are coming closer together.\n"
137 | ]
138 | },
139 | {
140 | "cell_type": "markdown",
141 | "metadata": {},
142 | "source": [
143 | "## The history of AI\n",
144 | "- The history of AI has had cycles of success, misplaced optimism, and resulting cutbacks in enthusiasm and funding. There have also been cycles of introducing new creative approaches and systematically refining the best ones.\n",
145 | "- AI has advanced more rapidly in the past decade because of greater use of the scientific method in experimenting with and comparing approaches.\n",
146 | "- Recent progress in understanding the theoretical basis for intelligence has gone hand in hand with improvements in the capabilities of real systems. The subfields of AI have become more integrated, and AI has found common ground with other disciplines.\n"
147 | ]
148 | }
149 | ],
150 | "metadata": {
151 | "kernelspec": {
152 | "display_name": "Python 3",
153 | "language": "python",
154 | "name": "python3"
155 | },
156 | "language_info": {
157 | "codemirror_mode": {
158 | "name": "ipython",
159 | "version": 3
160 | },
161 | "file_extension": ".py",
162 | "mimetype": "text/x-python",
163 | "name": "python",
164 | "nbconvert_exporter": "python",
165 | "pygments_lexer": "ipython3",
166 | "version": "3.6.2"
167 | },
168 | "toc": {
169 | "colors": {
170 | "hover_highlight": "#DAA520",
171 | "navigate_num": "#000000",
172 | "navigate_text": "#333333",
173 | "running_highlight": "#FF0000",
174 | "selected_highlight": "#FFD700",
175 | "sidebar_border": "#EEEEEE",
176 | "wrapper_background": "#FFFFFF"
177 | },
178 | "moveMenuLeft": true,
179 | "nav_menu": {
180 | "height": "171px",
181 | "width": "252px"
182 | },
183 | "navigate_menu": true,
184 | "number_sections": true,
185 | "sideBar": true,
186 | "threshold": 4,
187 | "toc_cell": true,
188 | "toc_section_display": "block",
189 | "toc_window_display": true,
190 | "widenNotebook": false
191 | }
192 | },
193 | "nbformat": 4,
194 | "nbformat_minor": 2
195 | }
196 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/assignments/ AI in 2030_REPORT-summary.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "toc": "true"
7 | },
8 | "source": [
9 | "# Table of Contents\n",
10 | " "
11 | ]
12 | },
13 | {
14 | "cell_type": "markdown",
15 | "metadata": {},
16 | "source": [
17 | "# ARTIFICIAL INTELLIGENCE AND LIFE IN 2030\n"
18 | ]
19 | },
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {},
23 | "source": [
24 | "## Preface\n",
25 | "\n",
26 | "- The overarching purpose of the One Hundred year study's periodic expert review is to provide a collected and connected set of reflections about AI and its influences as the field advances."
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {},
32 | "source": [
33 | "## Executive Summary"
34 | ]
35 | },
36 | {
37 | "cell_type": "markdown",
38 | "metadata": {},
39 | "source": [
40 | "- AI is a science and a set of computational technologies that are inspired by --but typically operate quite differently from -- the ways people use their nervous systems and bodies to sense, learn, reason and take action.\n",
41 | "\n",
42 | "- While drawing on common research and technologies, AI systems are specialized to accomplish particular tasks. Each application requires years of focused research and a careful, unique construction.\n",
43 | "\n",
44 | "- While the rate of progress in AI has been patchy and unpredictable, there have been significant advances since the field's inception 60 years ago.\n",
45 | "\n",
46 | "- Substantial increases in the future uses of AI applications, including more self-driving cars, healthcare diagnostics and targeted treatment, and physical assistance for elder care can be expected.\n",
47 | "\n",
48 | "- Contrary to the more fantastic predictions for AI in the popular press, the Study Panel found no cause for concern that AI is an imminent threat to humankind. No machines with self-sustaining long-term goals and intent have been developed, nor are they likely to be developed in the near future. Instead, increasingly useful applications of AI, with potentially profound positive impacts on our society and economy are likely to emerge between now and 2030."
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {},
54 | "source": [
55 | "## Overview"
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "metadata": {},
61 | "source": [
62 | "Many have already grown\n",
63 | "accustomed to touching\n",
64 | "and talking to their\n",
65 | "smart phones. People’s\n",
66 | "future relationships with\n",
67 | "machines will become ever\n",
68 | "more nuanced, fluid, and\n",
69 | "personalized."
70 | ]
71 | },
72 | {
73 | "cell_type": "markdown",
74 | "metadata": {},
75 | "source": [
76 | "Society is now at a crucial\n",
77 | "juncture in determining\n",
78 | "how to deploy AI-based\n",
79 | "technologies in ways that\n",
80 | "promote rather than hinder\n",
81 | "democratic values such\n",
82 | "as freedom, equality, and\n",
83 | "transparency.\n"
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {},
89 | "source": [
90 | "Longer term, AI may be\n",
91 | "thought of as a radically\n",
92 | "different mechanism\n",
93 | "for wealth creation in\n",
94 | "which everyone should\n",
95 | "be entitled to a portion of\n",
96 | "the world’s AI-produced\n",
97 | "treasures.\n"
98 | ]
99 | },
100 | {
101 | "cell_type": "markdown",
102 | "metadata": {},
103 | "source": [
104 | "### What is next for AI research?"
105 | ]
106 | },
107 | {
108 | "cell_type": "markdown",
109 | "metadata": {},
110 | "source": [
111 | "The field of AI is shifting\n",
112 | "toward building intelligent\n",
113 | "systems that can\n",
114 | "collaborate effectively with\n",
115 | "people, including creative\n",
116 | "ways to develop interactive\n",
117 | "and scalable ways for\n",
118 | "people to teach robots.\n"
119 | ]
120 | },
121 | {
122 | "cell_type": "markdown",
123 | "metadata": {},
124 | "source": [
125 | "These trends drive the currently “hot” areas of AI research into both fundamental methods and application areas:\n",
126 | "Large-scale machine learning \n",
127 | "\n",
128 | "- **Large-scale machine learning** concerns the design of learning algorithms, as well as scaling existing algorithms, to work with extremely large data sets. Deep learning, a class of learning procedures, has facilitated object recognition.\n",
129 | "\n",
130 | "Large-scale machine learning\n",
131 | "Many of the basic problems in machine learning (such as supervised and\n",
132 | "unsupervised learning) are well-understood. A major focus of current efforts is to\n",
133 | "scale existing algorithms to work with extremely large data sets. For example, whereas\n",
134 | "traditional methods could afford to make several passes over the data set, modern\n",
135 | "ones are designed to make only a single pass; in some cases, only sublinear methods\n",
136 | "(those that only look at a fraction of the data) can be admitted.\n",
137 | "\n",
138 | "\n",
139 | "- **Deep learning**, a class of learning procedures, has facilitated object recognition in images, video labeling, and activity recognition, and is making significant inroads into other areas of perception, such as audio, speech, and natural language processing.\n",
140 | "\n",
141 | "- **Reinforcement learning** is a framework that shifts the focus of machine learning from pattern recognition to experience-driven sequential decision-making. It promises to carry AI applications forward toward taking actions in the real world. While largely confined to academia over the past several decades, it is now seeing some practical, real-world successes.\n",
142 | "\n",
143 | "Whereas traditional machine learning has mostly focused on pattern mining,\n",
144 | "reinforcement learning shifts the focus to decision making, and is a technology that\n",
145 | "will help AI to advance more deeply into the realm of learning about and executing\n",
146 | "actions in the real world. It has existed for several decades as a framework for\n",
147 | "experience-driven sequential decision-making, but the methods have not found great\n",
148 | "success in practice, mainly owing to issues of representation and scaling. However,\n",
149 | "the advent of deep learning has provided reinforcement learning with a “shot in the\n",
150 | "arm.” The recent success of AlphaGo, a computer program developed by Google\n",
151 | "Deepmind that beat the human Go champion in a five-game match, was due in large\n",
152 | "part to reinforcement learning. AlphaGo was trained by initializing an automated\n",
153 | "agent with a human expert database, but was subsequently refined by playing a large\n",
154 | "number of games against itself and applying reinforcement learning.\n",
155 | "\n",
156 | "- **Robotics** is currently concerned with how to train a robot to interact with the world around it in generalizable and predictable ways, how to facilitate manipulation of objects in interactive environments, and how to interact with people. Advances in robotics will rely on commensurate advances to improve the reliability and generality of computer vision and other forms of machine perception.\n",
157 | "\n",
158 | "- **Computer vision** is currently the most prominent form of machine perception. It has been the sub-area of AI most transformed by the rise of deep learning. For the first time, computers are able to perform some vision tasks better than people. Muchcurrent research is focused on automatic image and video captioning.\n"
159 | ]
160 | },
161 | {
162 | "cell_type": "markdown",
163 | "metadata": {},
164 | "source": [
165 | "## What is Artificial Intelligence?"
166 | ]
167 | },
168 | {
169 | "cell_type": "markdown",
170 | "metadata": {},
171 | "source": [
172 | "Intelligence lies on a\n",
173 | "multi-dimensional\n",
174 | "spectrum. According to\n",
175 | "this view, the difference\n",
176 | "between an arithmetic\n",
177 | "calculator and a human\n",
178 | "brain is not one of kind,\n",
179 | "but of scale, speed,\n",
180 | "degree of autonomy, and\n",
181 | "generality.\n"
182 | ]
183 | },
184 | {
185 | "cell_type": "markdown",
186 | "metadata": {},
187 | "source": [
188 | "## Section II: AI by Domain"
189 | ]
190 | },
191 | {
192 | "cell_type": "markdown",
193 | "metadata": {},
194 | "source": [
195 | "### Education"
196 | ]
197 | },
198 | {
199 | "cell_type": "markdown",
200 | "metadata": {},
201 | "source": [
202 | "Though quality education\n",
203 | "will always require active\n",
204 | "engagement by human\n",
205 | "teachers, AI promises to\n",
206 | "enhance education at\n",
207 | "all levels, especially by\n",
208 | "providing personalization\n",
209 | "at scale.\n"
210 | ]
211 | },
212 | {
213 | "cell_type": "markdown",
214 | "metadata": {},
215 | "source": [
216 | "The current absence of\n",
217 | "sophisticated use of AI\n",
218 | "technologies in schools,\n",
219 | "colleges, and universities\n",
220 | "may be explained by\n",
221 | "the lack of financial\n",
222 | "resources as well as the\n",
223 | "lack of data establishing\n",
224 | "the technologies’\n",
225 | "effectiveness.\n"
226 | ]
227 | }
228 | ],
229 | "metadata": {
230 | "kernelspec": {
231 | "display_name": "Python 3",
232 | "language": "python",
233 | "name": "python3"
234 | },
235 | "language_info": {
236 | "codemirror_mode": {
237 | "name": "ipython",
238 | "version": 3
239 | },
240 | "file_extension": ".py",
241 | "mimetype": "text/x-python",
242 | "name": "python",
243 | "nbconvert_exporter": "python",
244 | "pygments_lexer": "ipython3",
245 | "version": "3.6.2"
246 | },
247 | "toc": {
248 | "colors": {
249 | "hover_highlight": "#DAA520",
250 | "navigate_num": "#000000",
251 | "navigate_text": "#333333",
252 | "running_highlight": "#FF0000",
253 | "selected_highlight": "#FFD700",
254 | "sidebar_border": "#EEEEEE",
255 | "wrapper_background": "#FFFFFF"
256 | },
257 | "moveMenuLeft": true,
258 | "nav_menu": {
259 | "height": "171px",
260 | "width": "252px"
261 | },
262 | "navigate_menu": true,
263 | "number_sections": false,
264 | "sideBar": true,
265 | "threshold": 4,
266 | "toc_cell": true,
267 | "toc_section_display": "block",
268 | "toc_window_display": false,
269 | "widenNotebook": false
270 | }
271 | },
272 | "nbformat": 4,
273 | "nbformat_minor": 2
274 | }
275 |
--------------------------------------------------------------------------------
/01-Artificial-Intelligence/2-Intelligent-agents/intelligent-agents.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "toc": "true"
7 | },
8 | "source": [
9 | "# Table of Contents\n",
10 | " "
11 | ]
12 | },
13 | {
14 | "cell_type": "markdown",
15 | "metadata": {},
16 | "source": [
17 | "# Intelligent Agents"
18 | ]
19 | },
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {},
23 | "source": [
24 | "## Agents and Environments"
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | "- An **agent** is anything that can be viewed as perceiving its **environment** through **sensors** and acting upon that environment through **actuators**.\n",
32 | "\n",
33 | ""
34 | ]
35 | },
36 | {
37 | "cell_type": "markdown",
38 | "metadata": {},
39 | "source": [
40 | "- A human agent has eyes, ears, and other organs for sensors and hands, legs, vocal tract of actuators.\n",
41 | "- A robotic agent might have cameras and infrared range finders for sensors and various motors for actuators.\n",
42 | "- A software agent receives keystrokes, file contents, and network packets as sensory inputs and acts on environment by displaying on the screen, writing files, etc.\n",
43 | "\n",
44 | "- An agent's **percept sequence** is the complete history of everything that agent has ever perceived.\n",
45 | ">An agent's choice of action at any given instant can depend on the entire percept sequence observed to date, but not on anything it hasn't perceived.\n",
46 | "\n",
47 | "- Mathematically speaking, we say that an agent's behavior is described by the **agent function** that maps any given percept sequence to an action.\n",
48 | "- *Internally,* the agent function for an artificial agent will be implemented by an **agent program**. It is important to keep these two ideas distinct.\n",
49 | ">**The agent function** is an abstract mathematical description, **the agent program** is a concrete implementation, running within some physical system."
50 | ]
51 | },
52 | {
53 | "cell_type": "markdown",
54 | "metadata": {},
55 | "source": [
56 | "## Good Behavior: The Concept of Rationality"
57 | ]
58 | },
59 | {
60 | "cell_type": "markdown",
61 | "metadata": {},
62 | "source": [
63 | "- A **rational agent** is one that does the right thing—conceptually speaking, every entry in the table for the agent function is filled out correctly. Obviously, doing the right thing is better than doing the wrong thing, but what does it mean to do the right thing?\n",
64 | "\n",
65 | "- When an agent is plunked down in an environment, it generates a sequence of actions according to the percepts it receives. This sequence of actions causes the environment to go through a sequence of states. If the sequence is desirable, then the agent has performed well. This notion of desirability is captured by a **performance measure** that evaluates any given sequence of environment states.\n",
66 | "\n",
67 | ">As a generall rule, it is better to design performance measures according to what one actually wants in the environment, rather than according to how one thinks the agent should behave.\n"
68 | ]
69 | },
70 | {
71 | "cell_type": "markdown",
72 | "metadata": {},
73 | "source": [
74 | "### Rationality"
75 | ]
76 | },
77 | {
78 | "cell_type": "markdown",
79 | "metadata": {},
80 | "source": [
81 | "- Rationality at any given time depends on four things:\n",
82 | " - The performance measure that defines the criterion of success.\n",
83 | " - The agent's prior knowledge of the environment.\n",
84 | " - The actions that the agent can perform.\n",
85 | " - The agent's percept sequence to date.\n",
86 | " \n",
87 | "- This leads to a **definition of a rational agent**:\n",
88 | ">For each possible percept sequence, a rational agent should select an action that is ex-\n",
89 | "pected to maximize its performance measure, given the evidence provided by the percept\n",
90 | "sequence and whatever built-in knowledge the agent has.\n"
91 | ]
92 | },
93 | {
94 | "cell_type": "markdown",
95 | "metadata": {},
96 | "source": [
97 | "### Omniscience, learning, and autonomy"
98 | ]
99 | },
100 | {
101 | "cell_type": "markdown",
102 | "metadata": {},
103 | "source": [
104 | "- There is a distinction between **rationality** and **omniscience**.\n",
105 | " - An omniscient agent knows the *actual* outcome of its actions and can act accordingly; but omniscience is impossible in reality.\n",
106 | " \n",
107 | "- Rationality maximizes *expected* performance, while perfection maximizes *actual* performance.\n",
108 | "\n",
109 | "- Doing actions *in order to modify future percepts* is called **information gathering** and is an important part of rationality.\n",
110 | "\n",
111 | "- A rational agent should be **autonomous** - it should learn what it can to compensate for partial or incorrect prior knowledge."
112 | ]
113 | },
114 | {
115 | "cell_type": "markdown",
116 | "metadata": {},
117 | "source": [
118 | "## The Nature of Environments"
119 | ]
120 | },
121 | {
122 | "cell_type": "markdown",
123 | "metadata": {},
124 | "source": [
125 | "- **Task environments** are essentially the *problems* to which rational agents are the *solutions*. "
126 | ]
127 | },
128 | {
129 | "cell_type": "markdown",
130 | "metadata": {},
131 | "source": [
132 | "### Specifying the task environment"
133 | ]
134 | },
135 | {
136 | "cell_type": "markdown",
137 | "metadata": {},
138 | "source": [
139 | "The **PEAS** (Performance, Environment, Actuators, Sensors) description. In designing an\n",
140 | "agent, the first step must always be to specify the task environment as fully as possible.\n",
141 | "\n",
142 | "\n"
143 | ]
144 | },
145 | {
146 | "cell_type": "markdown",
147 | "metadata": {},
148 | "source": [
149 | "### Properties of task environments"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "metadata": {},
155 | "source": [
156 | "- The range of task environments that might rise in AI is obviously vast.\n",
157 | "- We can, however, identify a fairly small number of dimensions along which task environments can be categorized.\n",
158 | "\n",
159 | ""
160 | ]
161 | },
162 | {
163 | "cell_type": "markdown",
164 | "metadata": {},
165 | "source": [
166 | "- **Fully observable** vs **Partially observable**\n",
167 | " - **Fully observable**: if an agent's sensors give it access to the complete state of the environment at each point in time, then we say that the task environment is fully observable.\n",
168 | "\n",
169 | " - **Partially observable**: if noisy and inaccurate sensors or parts of the state are simply missing from the sensor data, then we say that the task environment is partially observable.\n",
170 | "\n",
171 | "\n",
172 | "- **Single agent** vs **multiagent**\n",
173 | "\n",
174 | "\n",
175 | "- **Deterministic** vs **Stochastic**\n",
176 | "\n",
177 | " - If the next state of the environment is completely determined by the current state and the action executed by the agent, the we say the environment is **deterministic**; otherwise, it is **stochastic**.\n",
178 | " \n",
179 | " - An environment is **uncertain** if it is not fully observable or not deterministic. \n",
180 | " \n",
181 | " - **NOTE**: the word “stochastic” generally implies that uncertainty about outcomes is quantified in terms of probabilities; a nondeterministic environment is one in which actions are characterized by their possible outcomes, but no probabilities are attached to them. Nondeterministic environment descriptions are usually associated with performance measures that require the agent to succeed for all possible outcomes of its actions.\n",
182 | " \n",
183 | "- **Episodic** vs **Sequential**\n",
184 | " - In an **episodic** task environment, the agent's experience is divided into atomic episodes. In each episode the agent receives a percept and then performs a single action. Crucially, the next episode does not depend on the actions taken in previous episodes. Many classification tasks are episodic. \n",
185 | " \n",
186 | " - In **Sequential** environments, the current decision could affect all future decisions. Chess and Taxi driving are sequential.\n",
187 | " \n",
188 | " - Episodic environments are much simpler than sequential environments because the agent does not need to think ahead.\n",
189 | "\n",
190 | "\n",
191 | "- **Discrete** vs **Continuous**\n",
192 | " \n",
193 | " - The discrete/continuous distinction applies to the **state** of the environment, to the way **time** is handled, and to the **precepts** and **actions** of the agent.\n",
194 | " \n",
195 | "- **Known** vs **unknown**\n",
196 | "\n",
197 | "\n",
198 | ""
199 | ]
200 | },
201 | {
202 | "cell_type": "markdown",
203 | "metadata": {},
204 | "source": [
205 | "## The Structure of Agents"
206 | ]
207 | },
208 | {
209 | "cell_type": "markdown",
210 | "metadata": {},
211 | "source": [
212 | "- The job of AI is to design an **agent program** that implements the agent function-the mapping from precepts to actions.\n",
213 | "\n",
214 | "- **agent=architecture+program**"
215 | ]
216 | },
217 | {
218 | "cell_type": "markdown",
219 | "metadata": {},
220 | "source": [
221 | "### Agent Programs"
222 | ]
223 | },
224 | {
225 | "cell_type": "markdown",
226 | "metadata": {},
227 | "source": [
228 | ""
229 | ]
230 | },
231 | {
232 | "cell_type": "markdown",
233 | "metadata": {},
234 | "source": [
235 | "## Key Points\n"
236 | ]
237 | },
238 | {
239 | "cell_type": "markdown",
240 | "metadata": {},
241 | "source": [
242 | "- An **agent** is something that perceives and acts in an environment. The agent function for an agent specifies the action taken by the agent in response to any percept sequence.\n",
243 | "- The **performance measure** evaluates the behavior of the agent in an environment. A rational agent acts so as to maximize the expected value of the performance measure, given the percept sequence it has seen so far.\n",
244 | "- A **task environment** specification includes the performance measure, the external environment, the actuators, and the sensors. In designing an agent, the first step must always be to specify the task environment as fully as possible.\n",
245 | "- Task environments vary along several significant dimensions. They can be fully or partially observable, single-agent or multiagent, deterministic or stochastic, episodic or sequential, static or dynamic, discrete or continuous, and known or unknown.\n",
246 | "- The **agent program** implements the agent function. There exists a variety of basic agent-program designs reflecting the kind of information made explicit and used in the decision process. The designs vary in efficiency, compactness, and flexibility. The appropriate design of the agent program depends on the nature of the environment.\n",
247 | "- **Simple reflex agents** respond directly to percepts, whereas **model-based reflex agents** maintain internal state to track aspects of the world that are not evident in the current percept. **Goal-based agents** act to achieve their goals, and **utility-based agents** try to maximize their own expected “happiness.”\n",
248 | "- All agents can improve their performance through **learning**.\n"
249 | ]
250 | }
251 | ],
252 | "metadata": {
253 | "kernelspec": {
254 | "display_name": "Python 3",
255 | "language": "python",
256 | "name": "python3"
257 | },
258 | "language_info": {
259 | "codemirror_mode": {
260 | "name": "ipython",
261 | "version": 3
262 | },
263 | "file_extension": ".py",
264 | "mimetype": "text/x-python",
265 | "name": "python",
266 | "nbconvert_exporter": "python",
267 | "pygments_lexer": "ipython3",
268 | "version": "3.6.2"
269 | },
270 | "toc": {
271 | "colors": {
272 | "hover_highlight": "#DAA520",
273 | "navigate_num": "#000000",
274 | "navigate_text": "#333333",
275 | "running_highlight": "#FF0000",
276 | "selected_highlight": "#FFD700",
277 | "sidebar_border": "#EEEEEE",
278 | "wrapper_background": "#FFFFFF"
279 | },
280 | "moveMenuLeft": true,
281 | "nav_menu": {
282 | "height": "189px",
283 | "width": "252px"
284 | },
285 | "navigate_menu": true,
286 | "number_sections": true,
287 | "sideBar": true,
288 | "threshold": 4,
289 | "toc_cell": true,
290 | "toc_section_display": "block",
291 | "toc_window_display": true,
292 | "widenNotebook": false
293 | }
294 | },
295 | "nbformat": 4,
296 | "nbformat_minor": 2
297 | }
298 |
--------------------------------------------------------------------------------
/02-Problem-Solving/03-Search/search.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "toc": "true"
7 | },
8 | "source": [
9 | "# Table of Contents\n",
10 | " "
11 | ]
12 | },
13 | {
14 | "cell_type": "markdown",
15 | "metadata": {},
16 | "source": [
17 | "# Solving Problems By Searching"
18 | ]
19 | },
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {},
23 | "source": [
24 | "- **Problem-solving agent** uses **atomic** representations - that is, states of the world are considered as wholes, with no internal structure visible to the problem solving algorithms.\n",
25 | "- **Goal-based agents** aka **Planning agents** use more advanced **factored** or **structured** representations.\n"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {},
31 | "source": [
32 | "## Question"
33 | ]
34 | },
35 | {
36 | "cell_type": "markdown",
37 | "metadata": {},
38 | "source": [
39 | ""
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {},
45 | "source": [
46 | "- When you solve this problem, try to think about how you did it. You probably simulated the scenario in your head, trying to send the farmer over with the goat, observing the consequences. If nothing got eaten, you might continue with the next action. Otherwise, you undo that move and try something else.\n",
47 | "- How can we get a machine to do this automatically? One of the things we need is a systematic approach that considers all the possibilities. We will see that search problems define the possibilities, and search algorithms explore these possibilities."
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | "## Application"
55 | ]
56 | },
57 | {
58 | "cell_type": "markdown",
59 | "metadata": {},
60 | "source": [
61 | ""
62 | ]
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {},
67 | "source": [
68 | "- Route finding is perhaps the most canonical example of a search problem. We are given as the input a map, a source point and a destination point. The goal is to output a sequence of actions (e.g., go straight, turn left, or turn right) that will take us from the source to the destination.\n",
69 | "- We might evaluate action sequences based on an objective (distance, time, or pleasantness)."
70 | ]
71 | },
72 | {
73 | "cell_type": "markdown",
74 | "metadata": {},
75 | "source": [
76 | ""
77 | ]
78 | },
79 | {
80 | "cell_type": "markdown",
81 | "metadata": {},
82 | "source": [
83 | "- In robot motion planning, the goal is get a robot to move from one position/pose to another. The desired output trajectory consists of individual actions, each action corresponding to moving or rotating the joints by a small amount.\n",
84 | "- Again, we might evaluate action sequences based on various resources like time or energy."
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "## Beyond reflex"
92 | ]
93 | },
94 | {
95 | "cell_type": "markdown",
96 | "metadata": {},
97 | "source": [
98 | ""
99 | ]
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {},
104 | "source": [
105 | "- Reflex-based models (e.g., linear predictors and neural networks) output either a $-1$ or $+1$ (for binary classification) or a real number (for regression).\n",
106 | "- While reflex-based models were appropriate for some applications such as sentiment classification or spam filtering, the applications we will look at today, such as solving puzzles, demand more.\n",
107 | "- To tackle these new problems, we will introduce search problems, our first instance of a **state-based model**.\n",
108 | "- In a search problem, in a sense, we are still building a predictor $f$ which takes an input $x$, but $f$ will now return an entire action sequence, not just a single action. Of course you should object: can't I just apply a reflex model iteratively to generate a sequence? While that is true, the search problems that we're trying to solve importantly require reasoning about the consequences of the entire action sequence, and cannot be tackled by myopically predicting one action at a time.\n",
109 | "- Tangent: Of course, saying \"cannot\" is a bit strong, since sometimes a search problem can be solved by a reflex-based model. You could have a massive lookup table that told you what the best action to take for any given situation. (It is interesting to think of this as a time/memory tradeoff where reflex-based models are performing an implicit kind of caching.) Going on a further tangent, one can even imagine compiling a state-based model into a reflex-based model; if you're walking around Stanford for the first time, you might have to really plan things out, but eventually it kind of becomes reflex.\n",
110 | "- There are many real-world examples of this paradigm, which we will describe next. For each example, the key is to decompose the output solution into a sequence of primitive actions. In addition, we need to think about how to evaluate different possible outputs."
111 | ]
112 | },
113 | {
114 | "cell_type": "markdown",
115 | "metadata": {
116 | "collapsed": true
117 | },
118 | "source": [
119 | "## Tree Search"
120 | ]
121 | },
122 | {
123 | "cell_type": "markdown",
124 | "metadata": {},
125 | "source": [
126 | ""
127 | ]
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {},
132 | "source": [
133 | ""
134 | ]
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "metadata": {},
139 | "source": [
140 | ""
141 | ]
142 | },
143 | {
144 | "cell_type": "markdown",
145 | "metadata": {},
146 | "source": [
147 | "- We will build what we will call a **search tree**. The root of the tree is the start state $S_{start}$, and the leaves are the end states ( $IsEnd(s)$ is true). Each edge leaving a node $s$ corresponds to a possible action $a\\in Actions(s)$ that could be performed in state $s$ . The edge is labeled with the action and its cost, written $a:Cost(s, a)$ . The action leads deterministically to the successor state $Succ(s, a)$, represented by the child node.\n",
148 | "\n",
149 | "- In summary, each root-to-leaf path represents a possible action sequence, and the sum of the costs of the edges is the cost of that path. The goal is to find the root-to-leaf path that has the minimum cost.\n",
150 | "- Note that in code, we usually do not build the search tree as a concrete data structure. The search tree is used merely to visualize the computation of the search algorithms and study the structure of the search problem.\n",
151 | "- For the boat crossing example, we have assumed each action (a safe river crossing) costs 1 unit of time. Invalid actions (ones that result in an eating event) cost $\\infty $ and the successor is marked in red. We disallow actions that return us to an earlier configuration. The green nodes are the end states. From this search tree, we see that there are exactly two solutions, each of which has a total cost of 7 steps."
152 | ]
153 | },
154 | {
155 | "cell_type": "markdown",
156 | "metadata": {},
157 | "source": [
158 | ""
159 | ]
160 | },
161 | {
162 | "cell_type": "markdown",
163 | "metadata": {},
164 | "source": [
165 | "- Let's consider another problem and practice modeling it as a search problem. Recall that this means specifying precisely what the states, actions, goals, costs, and successors are.\n",
166 | "- To avoid the ambiguity of natural language, we will do this directly in code, where we define a **SearchProblem** class and implement the methods: **startState**, **isEnd** and **succAndCost**."
167 | ]
168 | },
169 | {
170 | "cell_type": "markdown",
171 | "metadata": {},
172 | "source": [
173 | "## Backtracking Search"
174 | ]
175 | },
176 | {
177 | "cell_type": "markdown",
178 | "metadata": {},
179 | "source": [
180 | "- Now let's put modeling aside and suppose we are handed a search problem. How do we construct an algorithm for finding a minimum cost path (not necessarily unique)?\n",
181 | "- We will start with backtracking search, the simplest algorithm which just tries all paths. The algorithm is called recursively on the current state $s$ and the path path leading up to that state. If we have reached a goal, then we can update the minimum cost path with the current path. Otherwise, we consider all possible actions $a$ from state $s$ , and recursively search each of the possibilities.\n",
182 | "- Graphically, backtracking search performs a depth-first traversal of the search tree. What is the time and memory complexity of this algorithm?\n",
183 | "- To get a simple characterization, assume that the search tree has maximum depth $D$(each path consists of $D$ actions/edges) and that there are $b$ available actions per state (the branching factor is $b$).\n",
184 | "- It is easy to see that backtracking search only requires $O(D)$ memory (to maintain the stack for the recurrence), which is as good as it gets.\n",
185 | "- However, the running time is proportional to the number of nodes in the tree, since the algorithm needs to check each of them. The number of nodes is $1 + b + b^2 + \\cdots + b^D = \\frac{b^{D+1} - 1}{b-1} = O(b^D)$. Note that the total number of nodes in the search tree is on the same order as the number of leaves, so the cost is always dominated by the last level.\n",
186 | "- In general, there might not be a finite upper bound on the depth of a search tree. In this case, there are two options: (i) we can simply cap the maximum depth and give up after a certain point or (ii) we can disallow visits to the same state.\n",
187 | "\n",
188 | ""
189 | ]
190 | },
191 | {
192 | "cell_type": "markdown",
193 | "metadata": {},
194 | "source": [
195 | "## Depth-first search\n",
196 | "\n",
197 | "Depth-first search always expands the deepest node in the current frontier of the search tree.\n",
198 | "The progress of the search is illustrated in Figure 3.16. The search proceeds immediately\n",
199 | "to the deepest level of the search tree, where the nodes have no successors. As those nodes\n",
200 | "are expanded, they are dropped from the frontier, so then the search “backs up” to the next\n",
201 | "deepest node that still has unexplored successors.\n"
202 | ]
203 | },
204 | {
205 | "cell_type": "markdown",
206 | "metadata": {},
207 | "source": [
208 | ""
209 | ]
210 | },
211 | {
212 | "cell_type": "markdown",
213 | "metadata": {},
214 | "source": [
215 | "- Backtracking search will always work (i.e., find a minimum cost path), but there are cases where we can do it faster. But in order to do that, we need some additional assumptions — there is no free lunch.\n",
216 | "- Suppose we make the assumption that all the action costs are zero. In other words, all we care about is finding a valid action sequence that reaches the goal. Any such sequence will have the minimum cost: zero.\n",
217 | "- In this case, we can just modify backtracking search to not keep track of costs and then stop searching as soon as we reach a goal. The resulting algorithm is depth-first search (DFS), which should be familiar to you. The worst time and space complexity are of the same order as backtracking search. In particular, if there is no path to an end state, then we have to search the entire tree.\n",
218 | "- However, if there are many ways to reach the end state, then we can stop much earlier without exhausting the search tree. So DFS is great when there are an abundance of solutions."
219 | ]
220 | },
221 | {
222 | "cell_type": "markdown",
223 | "metadata": {},
224 | "source": [
225 | "## Breadth-first search\n",
226 | ""
227 | ]
228 | },
229 | {
230 | "cell_type": "markdown",
231 | "metadata": {},
232 | "source": [
233 | "- Breadth-first search is a simple strategy in which the root node is expanded first, then all the successors of the root node are expanded next, then their successors, and so on. In general, all the nodes are expanded at a given depth in the search tree before any nodes at the next level are expanded.\n",
234 | "\n",
235 | "- **Breadth-first search (BFS)**, which should also be familiar, makes a less stringent assumption, that all the action costs are the same non-negative number. This effectively means that all the paths of a given length have the same cost.\n",
236 | "- BFS maintains a queue of states to be explored. It pops a state off the queue, then pushes its successors back on the queue.\n",
237 | "- BFS will search all the paths consisting of one edge, two edges, three edges, etc., until it finds a path that reaches a end state. So if the solution has $d$ actions, then we only need to explore $O(b^d)$ nodes, thus taking that much time.\n",
238 | "- However, a potential show-stopper is that BFS also requires $O(b^d)$ space since the queue must contain all the nodes of a given level of the search tree. Can we do better?"
239 | ]
240 | },
241 | {
242 | "cell_type": "markdown",
243 | "metadata": {},
244 | "source": [
245 | ""
246 | ]
247 | },
248 | {
249 | "cell_type": "markdown",
250 | "metadata": {},
251 | "source": [
252 | "## DFS with iterative deepening"
253 | ]
254 | },
255 | {
256 | "cell_type": "markdown",
257 | "metadata": {},
258 | "source": [
259 | ""
260 | ]
261 | },
262 | {
263 | "cell_type": "markdown",
264 | "metadata": {},
265 | "source": [
266 | "- Yes, we can do better with a trick called **iterative deepening**. The idea is to modify DFS to make it stop after reaching a certain depth. Therefore, we can invoke this modified DFS to find whether a valid path exists with at most $d$ edges, which as discussed earlier takes $O(d)$ space and $O(b^d)$ time.\n",
267 | "- Now the trick is simply to invoke this modified DFS with cutoff depths of $1, 2, 3, \\dots$ until we find a solution or give up. This algorithm is called DFS with iterative deepening (DFS-ID). In this manner, we are guaranteed optimality when all action costs are equal (like BFS), but we enjoy the parsimonious space requirements of DFS.\n",
268 | "- One might worry that we are doing a lot of work, searching some nodes many times. However, keep in mind that both the number of leaves and the number of nodes in a search tree is $O(b^d)$ so asymptotically DFS with iterative deepening is the same time complexity as BFS."
269 | ]
270 | },
271 | {
272 | "cell_type": "markdown",
273 | "metadata": {},
274 | "source": [
275 | "## Tree Search Algorithms Summary\n"
276 | ]
277 | },
278 | {
279 | "cell_type": "markdown",
280 | "metadata": {},
281 | "source": [
282 | ""
283 | ]
284 | },
285 | {
286 | "cell_type": "markdown",
287 | "metadata": {},
288 | "source": [
289 | "- Here is a summary of all the tree search algorithms, the assumptions on the action costs, and the space and time complexities.\n",
290 | "- The take-away is that we can't avoid the exponential time complexity, but we can certainly have linear space complexity. Space is in some sense the more critical dimension in search problems. Memory cannot magically grow, whereas time \"grows\" just by running an algorithm for a longer period of time, or even by parallelizing it across multiple machines (e.g., where each processor gets its own subtree to search)."
291 | ]
292 | },
293 | {
294 | "cell_type": "code",
295 | "execution_count": null,
296 | "metadata": {
297 | "collapsed": true
298 | },
299 | "outputs": [],
300 | "source": []
301 | }
302 | ],
303 | "metadata": {
304 | "kernelspec": {
305 | "display_name": "Python 3",
306 | "language": "python",
307 | "name": "python3"
308 | },
309 | "language_info": {
310 | "codemirror_mode": {
311 | "name": "ipython",
312 | "version": 3
313 | },
314 | "file_extension": ".py",
315 | "mimetype": "text/x-python",
316 | "name": "python",
317 | "nbconvert_exporter": "python",
318 | "pygments_lexer": "ipython3",
319 | "version": "3.6.2"
320 | },
321 | "toc": {
322 | "colors": {
323 | "hover_highlight": "#DAA520",
324 | "navigate_num": "#000000",
325 | "navigate_text": "#333333",
326 | "running_highlight": "#FF0000",
327 | "selected_highlight": "#FFD700",
328 | "sidebar_border": "#EEEEEE",
329 | "wrapper_background": "#FFFFFF"
330 | },
331 | "moveMenuLeft": true,
332 | "nav_menu": {
333 | "height": "84px",
334 | "width": "252px"
335 | },
336 | "navigate_menu": true,
337 | "number_sections": true,
338 | "sideBar": true,
339 | "threshold": 4,
340 | "toc_cell": true,
341 | "toc_section_display": "block",
342 | "toc_window_display": true,
343 | "widenNotebook": false
344 | }
345 | },
346 | "nbformat": 4,
347 | "nbformat_minor": 2
348 | }
349 |
--------------------------------------------------------------------------------
/projects/Naive-Bayes/text-classification-naive-bayes.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "toc": "true"
7 | },
8 | "source": [
9 | " # Table of Contents\n",
10 | ""
11 | ]
12 | },
13 | {
14 | "cell_type": "markdown",
15 | "metadata": {},
16 | "source": [
17 | "# Document/Text Classification"
18 | ]
19 | },
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {},
23 | "source": [
24 | "This notebook is based on Scikit-learn example for [Classification of text documents using sparse features](http://scikit-learn.org/stable/auto_examples/text/document_classification_20newsgroups.html#example-text-document-classification-20newsgroups-py)."
25 | ]
26 | },
27 | {
28 | "cell_type": "code",
29 | "execution_count": 1,
30 | "metadata": {},
31 | "outputs": [],
32 | "source": [
33 | "import warnings\n",
34 | "warnings.filterwarnings(\"ignore\")\n",
35 | "\n",
36 | "import numpy as np\n",
37 | "import time \n",
38 | "%matplotlib inline\n",
39 | "import matplotlib\n",
40 | "matplotlib.style.use('seaborn')\n",
41 | "import matplotlib.pyplot as plt\n",
42 | "\n",
43 | "from sklearn import metrics"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {},
49 | "source": [
50 | "## Loading the data set"
51 | ]
52 | },
53 | {
54 | "cell_type": "markdown",
55 | "metadata": {},
56 | "source": [
57 | "The data set used for this example is the **20 Newsgroup** data set. The original data set can be found [here](http://qwone.com/~jason/20Newsgroups/).\n",
58 | "\n",
59 | "\n",
60 | "The 20 Newsgroups data set is a collection of approximately 20,000 newsgroup documents, partitioned (nearly) evenly across 20 different newsgroups. \n",
61 | "\n",
62 | "This data set is in-built in scikit, so we don’t need to download it explicitly."
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": 2,
68 | "metadata": {
69 | "collapsed": true
70 | },
71 | "outputs": [],
72 | "source": [
73 | "from sklearn.datasets import fetch_20newsgroups"
74 | ]
75 | },
76 | {
77 | "cell_type": "code",
78 | "execution_count": 3,
79 | "metadata": {
80 | "collapsed": true
81 | },
82 | "outputs": [],
83 | "source": [
84 | "data_train = fetch_20newsgroups(subset='train', shuffle=True, random_state=42)\n",
85 | "data_test = fetch_20newsgroups(subset='test', shuffle=True, random_state=42)"
86 | ]
87 | },
88 | {
89 | "cell_type": "code",
90 | "execution_count": 4,
91 | "metadata": {
92 | "collapsed": true
93 | },
94 | "outputs": [],
95 | "source": [
96 | "y_train, y_test = data_train.target, data_test.target"
97 | ]
98 | },
99 | {
100 | "cell_type": "markdown",
101 | "metadata": {},
102 | "source": [
103 | "- Check the target names (categories) and some data files."
104 | ]
105 | },
106 | {
107 | "cell_type": "code",
108 | "execution_count": 5,
109 | "metadata": {},
110 | "outputs": [
111 | {
112 | "name": "stdout",
113 | "output_type": "stream",
114 | "text": [
115 | "['alt.atheism', 'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware', 'comp.sys.mac.hardware', 'comp.windows.x', 'misc.forsale', 'rec.autos', 'rec.motorcycles', 'rec.sport.baseball', 'rec.sport.hockey', 'sci.crypt', 'sci.electronics', 'sci.med', 'sci.space', 'soc.religion.christian', 'talk.politics.guns', 'talk.politics.mideast', 'talk.politics.misc', 'talk.religion.misc']\n"
116 | ]
117 | }
118 | ],
119 | "source": [
120 | "# print all the categories\n",
121 | "categories = data_train.target_names\n",
122 | "print(categories)"
123 | ]
124 | },
125 | {
126 | "cell_type": "markdown",
127 | "metadata": {},
128 | "source": [
129 | "- Print the first line of the first data file."
130 | ]
131 | },
132 | {
133 | "cell_type": "code",
134 | "execution_count": 6,
135 | "metadata": {},
136 | "outputs": [
137 | {
138 | "data": {
139 | "text/plain": [
140 | "[\"From: lerxst@wam.umd.edu (where's my thing)\",\n",
141 | " 'Subject: WHAT car is this!?',\n",
142 | " 'Nntp-Posting-Host: rac3.wam.umd.edu',\n",
143 | " 'Organization: University of Maryland, College Park',\n",
144 | " 'Lines: 15',\n",
145 | " '',\n",
146 | " ' I was wondering if anyone out there could enlighten me on this car I saw',\n",
147 | " 'the other day. It was a 2-door sports car, looked to be from the late 60s/',\n",
148 | " 'early 70s. It was called a Bricklin. The doors were really small. In addition,',\n",
149 | " 'the front bumper was separate from the rest of the body. This is ',\n",
150 | " 'all I know. If anyone can tellme a model name, engine specs, years',\n",
151 | " 'of production, where this car is made, history, or whatever info you',\n",
152 | " 'have on this funky looking car, please e-mail.',\n",
153 | " '',\n",
154 | " 'Thanks,',\n",
155 | " '- IL',\n",
156 | " ' ---- brought to you by your neighborhood Lerxst ----',\n",
157 | " '',\n",
158 | " '',\n",
159 | " '',\n",
160 | " '',\n",
161 | " '']"
162 | ]
163 | },
164 | "execution_count": 6,
165 | "metadata": {},
166 | "output_type": "execute_result"
167 | }
168 | ],
169 | "source": [
170 | "data_train.data[0].split(\"\\n\")"
171 | ]
172 | },
173 | {
174 | "cell_type": "markdown",
175 | "metadata": {},
176 | "source": [
177 | "## Extracting features from text files."
178 | ]
179 | },
180 | {
181 | "cell_type": "markdown",
182 | "metadata": {},
183 | "source": [
184 | "- Text files are actually series of words (ordered). In order to run machine learning algorithms we need to convert the text files into numerical feature vectors.\n",
185 | "- We will be using [the-bag-of-words model](https://en.wikipedia.org/wiki/Bag-of-words_model) for this case.\n",
186 | "- We segment each text file into words (for English splitting by space), and count the number of times each word occurs in each document and finally assign each word an integer id. Each unique word in our dictionary will correspond to a feature (descriptive feature).\n",
187 | "\n",
188 | "\n",
189 | "- We use **```TfidVectorizer()```** which converts a collection of raw documents to a matrix of TF-IDF features. **Tf means term-frequency while tf-idf means term-frequency times inverse document-frequency**. This is a common term weighting scheme in information retrieval, that has also found good use in document classification. The goal of using tf-idf instead of the raw frequencies of occurrence of a token in a given document is to scale down the impact of tokens that occur very frequently in a given corpus and that are hence empirically less informative than features that occur in a small fraction of the training corpus."
190 | ]
191 | },
192 | {
193 | "cell_type": "markdown",
194 | "metadata": {},
195 | "source": [
196 | "### Extracting features from the training data using a sparse vectorizer"
197 | ]
198 | },
199 | {
200 | "cell_type": "code",
201 | "execution_count": 7,
202 | "metadata": {
203 | "collapsed": true
204 | },
205 | "outputs": [],
206 | "source": [
207 | "from sklearn.feature_extraction.text import HashingVectorizer, TfidfVectorizer"
208 | ]
209 | },
210 | {
211 | "cell_type": "code",
212 | "execution_count": 8,
213 | "metadata": {},
214 | "outputs": [],
215 | "source": [
216 | "vectorizer = TfidfVectorizer(sublinear_tf=True, max_df=0.5, stop_words='english')"
217 | ]
218 | },
219 | {
220 | "cell_type": "code",
221 | "execution_count": 9,
222 | "metadata": {},
223 | "outputs": [
224 | {
225 | "name": "stdout",
226 | "output_type": "stream",
227 | "text": [
228 | "n_samples: 11314, n_features: 129791\n"
229 | ]
230 | }
231 | ],
232 | "source": [
233 | "X_train = vectorizer.fit_transform(data_train.data)\n",
234 | "print(\"n_samples: %d, n_features: %d\" % X_train.shape)"
235 | ]
236 | },
237 | {
238 | "cell_type": "markdown",
239 | "metadata": {},
240 | "source": [
241 | "### Extracting features from the test data using the same vectorizer"
242 | ]
243 | },
244 | {
245 | "cell_type": "code",
246 | "execution_count": 10,
247 | "metadata": {},
248 | "outputs": [
249 | {
250 | "name": "stdout",
251 | "output_type": "stream",
252 | "text": [
253 | "n_samples: 7532, n_features: 129791\n"
254 | ]
255 | }
256 | ],
257 | "source": [
258 | "X_test = vectorizer.transform(data_test.data)\n",
259 | "print(\"n_samples: %d, n_features: %d\" % X_test.shape)"
260 | ]
261 | },
262 | {
263 | "cell_type": "markdown",
264 | "metadata": {},
265 | "source": [
266 | "## Training + Testing Naive Bayes algorithm"
267 | ]
268 | },
269 | {
270 | "cell_type": "code",
271 | "execution_count": 11,
272 | "metadata": {
273 | "collapsed": true
274 | },
275 | "outputs": [],
276 | "source": [
277 | "from sklearn.naive_bayes import MultinomialNB, BernoulliNB"
278 | ]
279 | },
280 | {
281 | "cell_type": "code",
282 | "execution_count": 12,
283 | "metadata": {
284 | "collapsed": true
285 | },
286 | "outputs": [],
287 | "source": [
288 | "clfs = [\n",
289 | " (\"MultinomialNB\", MultinomialNB(alpha=.01)),\n",
290 | " (\"BernoulliNB\", BernoulliNB(alpha=.01))\n",
291 | "]"
292 | ]
293 | },
294 | {
295 | "cell_type": "code",
296 | "execution_count": 23,
297 | "metadata": {
298 | "collapsed": true
299 | },
300 | "outputs": [],
301 | "source": [
302 | "def print_confusion_matrix(clf, x_test, y_test):\n",
303 | " \n",
304 | " # Get the predicted classifications for the test-set\n",
305 | " cls_pred = clf.predict(x_test)\n",
306 | " \n",
307 | " # Get the confusion matrix using sklearn\n",
308 | " cm = metrics.confusion_matrix(y_true=y_test,\n",
309 | " y_pred=cls_pred)\n",
310 | " \n",
311 | " # Print the confusion matrix as text\n",
312 | " #print(\"\\n\\n\")\n",
313 | " #print(cm)\n",
314 | " \n",
315 | " num_classes = len(categories)\n",
316 | " # Plot the confusion matrix.\n",
317 | " plt.imshow(cm, interpolation='nearest', cmap=plt.cm.jet)\n",
318 | " \n",
319 | " # Make various adjustments to the plot.\n",
320 | " plt.tight_layout()\n",
321 | " plt.colorbar()\n",
322 | " tick_marks = np.arange(num_classes)\n",
323 | " plt.xticks(tick_marks, range(num_classes))\n",
324 | " plt.yticks(tick_marks, range(num_classes))\n",
325 | " plt.xlabel('Predicted')\n",
326 | " plt.ylabel('True')\n",
327 | " plt.show()\n",
328 | "\n"
329 | ]
330 | },
331 | {
332 | "cell_type": "code",
333 | "execution_count": 24,
334 | "metadata": {},
335 | "outputs": [],
336 | "source": [
337 | "def train_and_test():\n",
338 | " \n",
339 | " for name, clf in clfs:\n",
340 | " clf.fit(X_train, y_train)\n",
341 | " predicted = clf.predict(X_test)\n",
342 | " score = clf.score(X_test, y_test)\n",
343 | " print(\"{} 's Accuracy = {} %\".format(name, round(score*100,4)))\n",
344 | " print(\"\\n\\n\\n{} 's Confusion Matrix\".format(name))\n",
345 | " print_confusion_matrix(clf, X_test, y_test)\n",
346 | " "
347 | ]
348 | },
349 | {
350 | "cell_type": "code",
351 | "execution_count": 25,
352 | "metadata": {},
353 | "outputs": [
354 | {
355 | "name": "stdout",
356 | "output_type": "stream",
357 | "text": [
358 | "MultinomialNB 's Accuracy = 83.7361 %\n",
359 | "\n",
360 | "\n",
361 | "\n",
362 | "MultinomialNB 's Confusion Matrix\n"
363 | ]
364 | },
365 | {
366 | "data": {
367 | "image/png": "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\nAAAASUVORK5CYII=\n",
368 | "text/plain": [
369 | ""
370 | ]
371 | },
372 | "metadata": {},
373 | "output_type": "display_data"
374 | },
375 | {
376 | "name": "stdout",
377 | "output_type": "stream",
378 | "text": [
379 | "BernoulliNB 's Accuracy = 77.111 %\n",
380 | "\n",
381 | "\n",
382 | "\n",
383 | "BernoulliNB 's Confusion Matrix\n"
384 | ]
385 | },
386 | {
387 | "data": {
388 | "image/png": "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\n",
389 | "text/plain": [
390 | ""
391 | ]
392 | },
393 | "metadata": {},
394 | "output_type": "display_data"
395 | },
396 | {
397 | "name": "stdout",
398 | "output_type": "stream",
399 | "text": [
400 | "CPU times: user 2.42 s, sys: 1.52 s, total: 3.93 s\n",
401 | "Wall time: 2.23 s\n"
402 | ]
403 | }
404 | ],
405 | "source": [
406 | "%%time\n",
407 | "train_and_test()"
408 | ]
409 | },
410 | {
411 | "cell_type": "code",
412 | "execution_count": 16,
413 | "metadata": {},
414 | "outputs": [
415 | {
416 | "data": {
417 | "application/json": {
418 | "Software versions": [
419 | {
420 | "module": "Python",
421 | "version": "3.6.2 64bit [GCC 4.8.2 20140120 (Red Hat 4.8.2-15)]"
422 | },
423 | {
424 | "module": "IPython",
425 | "version": "6.1.0"
426 | },
427 | {
428 | "module": "OS",
429 | "version": "Linux 4.4.0 53 generic x86_64 with debian stretch sid"
430 | },
431 | {
432 | "module": "numpy",
433 | "version": "1.12.1"
434 | },
435 | {
436 | "module": "matplotlib",
437 | "version": "2.0.2"
438 | },
439 | {
440 | "module": "sklearn",
441 | "version": "0.19.0"
442 | }
443 | ]
444 | },
445 | "text/html": [
446 | "| Software | Version |
|---|
| Python | 3.6.2 64bit [GCC 4.8.2 20140120 (Red Hat 4.8.2-15)] |
| IPython | 6.1.0 |
| OS | Linux 4.4.0 53 generic x86_64 with debian stretch sid |
| numpy | 1.12.1 |
| matplotlib | 2.0.2 |
| sklearn | 0.19.0 |
| Sun Sep 24 13:57:04 2017 CDT |
"
447 | ],
448 | "text/latex": [
449 | "\\begin{tabular}{|l|l|}\\hline\n",
450 | "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n",
451 | "Python & 3.6.2 64bit [GCC 4.8.2 20140120 (Red Hat 4.8.2-15)] \\\\ \\hline\n",
452 | "IPython & 6.1.0 \\\\ \\hline\n",
453 | "OS & Linux 4.4.0 53 generic x86\\_64 with debian stretch sid \\\\ \\hline\n",
454 | "numpy & 1.12.1 \\\\ \\hline\n",
455 | "matplotlib & 2.0.2 \\\\ \\hline\n",
456 | "sklearn & 0.19.0 \\\\ \\hline\n",
457 | "\\hline \\multicolumn{2}{|l|}{Sun Sep 24 13:57:04 2017 CDT} \\\\ \\hline\n",
458 | "\\end{tabular}\n"
459 | ],
460 | "text/plain": [
461 | "Software versions\n",
462 | "Python 3.6.2 64bit [GCC 4.8.2 20140120 (Red Hat 4.8.2-15)]\n",
463 | "IPython 6.1.0\n",
464 | "OS Linux 4.4.0 53 generic x86_64 with debian stretch sid\n",
465 | "numpy 1.12.1\n",
466 | "matplotlib 2.0.2\n",
467 | "sklearn 0.19.0\n",
468 | "Sun Sep 24 13:57:04 2017 CDT"
469 | ]
470 | },
471 | "execution_count": 16,
472 | "metadata": {},
473 | "output_type": "execute_result"
474 | }
475 | ],
476 | "source": [
477 | "%load_ext version_information\n",
478 | "%version_information numpy, matplotlib, sklearn"
479 | ]
480 | }
481 | ],
482 | "metadata": {
483 | "kernelspec": {
484 | "display_name": "Python 3",
485 | "language": "python",
486 | "name": "python3"
487 | },
488 | "language_info": {
489 | "codemirror_mode": {
490 | "name": "ipython",
491 | "version": 3
492 | },
493 | "file_extension": ".py",
494 | "mimetype": "text/x-python",
495 | "name": "python",
496 | "nbconvert_exporter": "python",
497 | "pygments_lexer": "ipython3",
498 | "version": "3.6.2"
499 | },
500 | "toc": {
501 | "nav_menu": {},
502 | "number_sections": true,
503 | "sideBar": true,
504 | "skip_h1_title": false,
505 | "toc_cell": true,
506 | "toc_position": {},
507 | "toc_section_display": "block",
508 | "toc_window_display": true
509 | }
510 | },
511 | "nbformat": 4,
512 | "nbformat_minor": 2
513 | }
514 |
--------------------------------------------------------------------------------