from inspect import getsource
from utils import argmax, argmin
from games import TicTacToe, alphabeta_player, random_player, Fig52Extended, infinity
from logic import parse_definite_clause, standardize_variables, unify, subst
from learning import DataSet
from IPython.display import HTML, display
from collections import Counter, defaultdict
import matplotlib.pyplot as plt
import numpy as np
import os, struct
import array
import time
#______________________________________________________________________________
# Magic Words
def pseudocode(algorithm):
"""Print the pseudocode for the given algorithm."""
from urllib.request import urlopen
from IPython.display import Markdown
algorithm = algorithm.replace(' ', '-')
url = "https://raw.githubusercontent.com/aimacode/aima-pseudocode/master/md/{}.md".format(algorithm)
f = urlopen(url)
md = f.read().decode('utf-8')
md = md.split('\n', 1)[-1].strip()
md = '#' + md
return Markdown(md)
def psource(*functions):
"""Print the source code for the given function(s)."""
source_code = '\n\n'.join(getsource(fn) for fn in functions)
try:
from pygments.formatters import HtmlFormatter
from pygments.lexers import PythonLexer
from pygments import highlight
display(HTML(highlight(source_code, PythonLexer(), HtmlFormatter(full=True))))
except ImportError:
print(source_code)
# ______________________________________________________________________________
# Iris Visualization
def show_iris(i=0, j=1, k=2):
"""Plots the iris dataset in a 3D plot.
The three axes are given by i, j and k,
which correspond to three of the four iris features."""
from mpl_toolkits.mplot3d import Axes3D
plt.rcParams.update(plt.rcParamsDefault)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
iris = DataSet(name="iris")
buckets = iris.split_values_by_classes()
features = ["Sepal Length", "Sepal Width", "Petal Length", "Petal Width"]
f1, f2, f3 = features[i], features[j], features[k]
a_setosa = [v[i] for v in buckets["setosa"]]
b_setosa = [v[j] for v in buckets["setosa"]]
c_setosa = [v[k] for v in buckets["setosa"]]
a_virginica = [v[i] for v in buckets["virginica"]]
b_virginica = [v[j] for v in buckets["virginica"]]
c_virginica = [v[k] for v in buckets["virginica"]]
a_versicolor = [v[i] for v in buckets["versicolor"]]
b_versicolor = [v[j] for v in buckets["versicolor"]]
c_versicolor = [v[k] for v in buckets["versicolor"]]
for c, m, sl, sw, pl in [('b', 's', a_setosa, b_setosa, c_setosa),
('g', '^', a_virginica, b_virginica, c_virginica),
('r', 'o', a_versicolor, b_versicolor, c_versicolor)]:
ax.scatter(sl, sw, pl, c=c, marker=m)
ax.set_xlabel(f1)
ax.set_ylabel(f2)
ax.set_zlabel(f3)
plt.show()
# ______________________________________________________________________________
# MNIST
def load_MNIST(path="aima-data/MNIST/Digits", fashion=False):
import os, struct
import array
import numpy as np
from collections import Counter
if fashion:
path = "aima-data/MNIST/Fashion"
plt.rcParams.update(plt.rcParamsDefault)
plt.rcParams['figure.figsize'] = (10.0, 8.0)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
train_img_file = open(os.path.join(path, "train-images-idx3-ubyte"), "rb")
train_lbl_file = open(os.path.join(path, "train-labels-idx1-ubyte"), "rb")
test_img_file = open(os.path.join(path, "t10k-images-idx3-ubyte"), "rb")
test_lbl_file = open(os.path.join(path, 't10k-labels-idx1-ubyte'), "rb")
magic_nr, tr_size, tr_rows, tr_cols = struct.unpack(">IIII", train_img_file.read(16))
tr_img = array.array("B", train_img_file.read())
train_img_file.close()
magic_nr, tr_size = struct.unpack(">II", train_lbl_file.read(8))
tr_lbl = array.array("b", train_lbl_file.read())
train_lbl_file.close()
magic_nr, te_size, te_rows, te_cols = struct.unpack(">IIII", test_img_file.read(16))
te_img = array.array("B", test_img_file.read())
test_img_file.close()
magic_nr, te_size = struct.unpack(">II", test_lbl_file.read(8))
te_lbl = array.array("b", test_lbl_file.read())
test_lbl_file.close()
#print(len(tr_img), len(tr_lbl), tr_size)
#print(len(te_img), len(te_lbl), te_size)
train_img = np.zeros((tr_size, tr_rows*tr_cols), dtype=np.int16)
train_lbl = np.zeros((tr_size,), dtype=np.int8)
for i in range(tr_size):
train_img[i] = np.array(tr_img[i*tr_rows*tr_cols : (i+1)*tr_rows*tr_cols]).reshape((tr_rows*te_cols))
train_lbl[i] = tr_lbl[i]
test_img = np.zeros((te_size, te_rows*te_cols), dtype=np.int16)
test_lbl = np.zeros((te_size,), dtype=np.int8)
for i in range(te_size):
test_img[i] = np.array(te_img[i*te_rows*te_cols : (i+1)*te_rows*te_cols]).reshape((te_rows*te_cols))
test_lbl[i] = te_lbl[i]
return(train_img, train_lbl, test_img, test_lbl)
digit_classes = [str(i) for i in range(10)]
fashion_classes = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
"Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
def show_MNIST(labels, images, samples=8, fashion=False):
if not fashion:
classes = digit_classes
else:
classes = fashion_classes
num_classes = len(classes)
for y, cls in enumerate(classes):
idxs = np.nonzero([i == y for i in labels])
idxs = np.random.choice(idxs[0], samples, replace=False)
for i , idx in enumerate(idxs):
plt_idx = i * num_classes + y + 1
plt.subplot(samples, num_classes, plt_idx)
plt.imshow(images[idx].reshape((28, 28)))
plt.axis("off")
if i == 0:
plt.title(cls)
plt.show()
def show_ave_MNIST(labels, images, fashion=False):
if not fashion:
item_type = "Digit"
classes = digit_classes
else:
item_type = "Apparel"
classes = fashion_classes
num_classes = len(classes)
for y, cls in enumerate(classes):
idxs = np.nonzero([i == y for i in labels])
print(item_type, y, ":", len(idxs[0]), "images.")
ave_img = np.mean(np.vstack([images[i] for i in idxs[0]]), axis = 0)
#print(ave_img.shape)
plt.subplot(1, num_classes, y+1)
plt.imshow(ave_img.reshape((28, 28)))
plt.axis("off")
plt.title(cls)
plt.show()
# ______________________________________________________________________________
# MDP
def make_plot_grid_step_function(columns, rows, U_over_time):
"""ipywidgets interactive function supports single parameter as input.
This function creates and return such a function by taking as input
other parameters."""
def plot_grid_step(iteration):
data = U_over_time[iteration]
data = defaultdict(lambda: 0, data)
grid = []
for row in range(rows):
current_row = []
for column in range(columns):
current_row.append(data[(column, row)])
grid.append(current_row)
grid.reverse() # output like book
fig = plt.imshow(grid, cmap=plt.cm.bwr, interpolation='nearest')
plt.axis('off')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
for col in range(len(grid)):
for row in range(len(grid[0])):
magic = grid[col][row]
fig.axes.text(row, col, "{0:.2f}".format(magic), va='center', ha='center')
plt.show()
return plot_grid_step
def make_visualize(slider):
"""Takes an input a sliderand returns callback function
for timer and animation."""
def visualize_callback(Visualize, time_step):
if Visualize is True:
for i in range(slider.min, slider.max + 1):
slider.value = i
time.sleep(float(time_step))
return visualize_callback
# ______________________________________________________________________________
_canvas = """
""" # noqa
class Canvas:
"""Inherit from this class to manage the HTML canvas element in jupyter notebooks.
To create an object of this class any_name_xyz = Canvas("any_name_xyz")
The first argument given must be the name of the object being created.
IPython must be able to refernce the variable name that is being passed."""
def __init__(self, varname, width=800, height=600, cid=None):
self.name = varname
self.cid = cid or varname
self.width = width
self.height = height
self.html = _canvas.format(self.cid, self.width, self.height, self.name)
self.exec_list = []
display_html(self.html)
def mouse_click(self, x, y):
"""Override this method to handle mouse click at position (x, y)"""
raise NotImplementedError
def mouse_move(self, x, y):
raise NotImplementedError
def execute(self, exec_str):
"""Stores the command to be exectued to a list which is used later during update()"""
if not isinstance(exec_str, str):
print("Invalid execution argument:", exec_str)
self.alert("Recieved invalid execution command format")
prefix = "{0}_canvas_object.".format(self.cid)
self.exec_list.append(prefix + exec_str + ';')
def fill(self, r, g, b):
"""Changes the fill color to a color in rgb format"""
self.execute("fill({0}, {1}, {2})".format(r, g, b))
def stroke(self, r, g, b):
"""Changes the colors of line/strokes to rgb"""
self.execute("stroke({0}, {1}, {2})".format(r, g, b))
def strokeWidth(self, w):
"""Changes the width of lines/strokes to 'w' pixels"""
self.execute("strokeWidth({0})".format(w))
def rect(self, x, y, w, h):
"""Draw a rectangle with 'w' width, 'h' height and (x, y) as the top-left corner"""
self.execute("rect({0}, {1}, {2}, {3})".format(x, y, w, h))
def rect_n(self, xn, yn, wn, hn):
"""Similar to rect(), but the dimensions are normalized to fall between 0 and 1"""
x = round(xn * self.width)
y = round(yn * self.height)
w = round(wn * self.width)
h = round(hn * self.height)
self.rect(x, y, w, h)
def line(self, x1, y1, x2, y2):
"""Draw a line from (x1, y1) to (x2, y2)"""
self.execute("line({0}, {1}, {2}, {3})".format(x1, y1, x2, y2))
def line_n(self, x1n, y1n, x2n, y2n):
"""Similar to line(), but the dimensions are normalized to fall between 0 and 1"""
x1 = round(x1n * self.width)
y1 = round(y1n * self.height)
x2 = round(x2n * self.width)
y2 = round(y2n * self.height)
self.line(x1, y1, x2, y2)
def arc(self, x, y, r, start, stop):
"""Draw an arc with (x, y) as centre, 'r' as radius from angles 'start' to 'stop'"""
self.execute("arc({0}, {1}, {2}, {3}, {4})".format(x, y, r, start, stop))
def arc_n(self, xn, yn, rn, start, stop):
"""Similar to arc(), but the dimensions are normalized to fall between 0 and 1
The normalizing factor for radius is selected between width and height by
seeing which is smaller."""
x = round(xn * self.width)
y = round(yn * self.height)
r = round(rn * min(self.width, self.height))
self.arc(x, y, r, start, stop)
def clear(self):
"""Clear the HTML canvas"""
self.execute("clear()")
def font(self, font):
"""Changes the font of text"""
self.execute('font("{0}")'.format(font))
def text(self, txt, x, y, fill=True):
"""Display a text at (x, y)"""
if fill:
self.execute('fill_text("{0}", {1}, {2})'.format(txt, x, y))
else:
self.execute('stroke_text("{0}", {1}, {2})'.format(txt, x, y))
def text_n(self, txt, xn, yn, fill=True):
"""Similar to text(), but with normalized coordinates"""
x = round(xn * self.width)
y = round(yn * self.height)
self.text(txt, x, y, fill)
def alert(self, message):
"""Immediately display an alert"""
display_html(''.format(message))
def update(self):
"""Execute the JS code to execute the commands queued by execute()"""
exec_code = ""
self.exec_list = []
display_html(exec_code)
def display_html(html_string):
display(HTML(html_string))
################################################################################
class Canvas_TicTacToe(Canvas):
"""Play a 3x3 TicTacToe game on HTML canvas"""
def __init__(self, varname, player_1='human', player_2='random',
width=300, height=350, cid=None):
valid_players = ('human', 'random', 'alphabeta')
if player_1 not in valid_players or player_2 not in valid_players:
raise TypeError("Players must be one of {}".format(valid_players))
Canvas.__init__(self, varname, width, height, cid)
self.ttt = TicTacToe()
self.state = self.ttt.initial
self.turn = 0
self.strokeWidth(5)
self.players = (player_1, player_2)
self.font("20px Arial")
self.draw_board()
def mouse_click(self, x, y):
player = self.players[self.turn]
if self.ttt.terminal_test(self.state):
if 0.55