{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## NYU Artificial Intelligence, programming session 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Part I Analogies and semantic networks"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We consider the following Analogy problem (taken from Evan's paper). As indicated by the figure, the idea is to find the figure among 1 to 5 which to (c) what (b) is to (a) (the example is taken from the 1942 edition of the Psychological Test for College Freshmen of the American Council on Education)\n",
" \n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise 1. Evans\n",
"\n",
"Write a short python code to solve this problem. We will store the objects as dictionnary with the following fields: a name (unique identifier for each figure, you can choose it), a shape (for the moment, triangle, square and disk or circle), a size (we will consider three sizes : small, medium or large) we will add three more descriptive fields : \n",
"- __fill__ (indicating whether the shape is filled (in which case there can't be any other shape inside), \n",
"- __inside__ (which links the an object to the object that contains it (hence stores a pointer to the corresponding dictionnary), in other words, the current figure )\n",
"- __above__ (stores a pointer to the figure that is located below. I.e. the current figure is above the figure linked by __above__)\n",
"\n",
"We will store each image as a list of the figures it contains. \n",
"\n",
"#### Exercise I.1. Generate a representation for the images shown above.\n",
"(here we will manually encode the representation although as indicated in the paper of Evans, the translation from the image through its list representation could easily be implemented by a simple scanner)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise I.2. We now want to write a short program that will be able to solve the analogy problem above. \n",
"\n",
"For this, the idea is to implement a diagram similar to the one shown below. We decompose each figure into its objects. We then study how those objects change from (a) to (b) and apply the corresponding transformations to each of the object from the second image. Then compare with the figures 1 to 5 (following the idea of the diagram below) in order to find the matching figure.\n",
"\n",
"Start by drawing the diagram (with pen and paper) relating (a) to (b) as shown below. Then apply the corresponding transformations to the new figure. \n",
"\n",
"Note that although you can start by assuming no scaling for simplicity, from (a) --> (b) it is a priori not clear whether it is the larger triangle which was retained or if it is the smaller one that was scaled up after deleting the small one. Ultimately your code should take the possibilities into account (i.e. this will actually be needed in I.3). \n",
"\n",
""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise I.2 Use the code that you wrote above to solve the following analogy problem from Evan's\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise I.4. A slightly more complex example\n",
"\n",
"Apply your algorithm to solve the following Analogy problem\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise I.5. A slightly more complex example (Part II)\n",
"\n",
"Apply your algorithm to solve the following Analogy problem\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise I.6. The first ambiguities (part I)\n",
"\n",
"Refine your pipeline so that it can handle the ambiguous Analogy below.\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise I.7. The first ambiguities (part II)\n",
"\n",
"Refine the solution you provided for the previous exercises in order to solve the new analogy below. \n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise I.8. Bonus (part II)\n",
"\n",
"We now consider a more ambiguous problem where there is no direct matching in the sense described above. The example is again taken from Evan's seminal paper on ANALOGY. \n",
"\n",
"\n",
"\n",
"\n",
"__Hint:__ Start by trying the above/below relations encoded in the transformation between figure (a) and (b). if you can't get any match, one appoach consists in substituting one transformation for another (e.g. after checking that the original relation (above-below or vertical swap) cannot be applied, one can for example check the substitution of the vertical transformation for an horizontal one.)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Part II Rational agents\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"We consider the vacuum cleaner world shown below. This world can be characterized as follows:\n",
"\n",
"- The state of the environment is defined jointly by both the vacuum cleaner location and the dirt location. I.e. the agent is in either of two locations, each of which might contain dirt. In total there are thus $2\\times 2^2 = 8$ (i.e. the vacuum cleaner can be in either of the two cells (exclusively) and there can be dirt everywhere) possible world states. \n",
"\n",
"- In this environment, each state has 3 associated actions: Left, Right and Suck (Larger envinronement will include the additional Up and Down moves)\n",
"\n",
"- Any state can be defined as the initial state\n",
"- The actions have their respective effects except moving left in the leftmost square and moving right in the rightmost square\n",
"\n",
"- The objective of the vacuum cleaner is for all the cells to be clean\n",
"\n",
"- In this framework, we will consider that each step costs 1 so the total cost of a path is the number of steps in the path. \n",
"\n",
"\n",
"\n",
"\n",
"#### Exercise II.1. \n",
"\n",
"Implement a performance measure environment simulator for the vacuum cleaner world. Your environment should be modular so that the sensors actuators and environment characteristics (size, shape, dirt placement can be changed easily)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise II.2\n",
"\n",
"Implement a simple reflex agent for the environment you just defined. Run the environment with this agent for all possible initial dirt configurations and agent locations. Record the performance score for each configuration and the overall average score. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise II.3\n",
"\n",
"Consider a modified version of the vacuum environment in which geography of the environment (its extent, boundaries and obstacles) is unknown, as is the initial dirt configuration. (The agent can now go _Up_ and _Down_ as well as _Left_ and _Right_)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exercise II.4\n",
"\n",
"Extend the environments from above to the following stochastic frameworks:\n",
" \n",
" - 25% of the time, the \"Suck\" action fails to clean the floor if it is dirty an deposit dirt onto the floor if the floor is clean\n",
" - At each time step, each clean square has a 10% chance of becoming dirty"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Part III Search Agents\n",
"\n",
"In this third part, we will review the basic search algorithms and implement simple search agents. When trying to solve a general problem, the simplest approach is to discretize the space into the complete set of candidate solutions (which can be extremely greedy) and explore this space, through search algorithms to find an optimal solution (examples of applications involve route finding, equation solving, ...).\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### III.1. Revisions\n",
"\n",
"In this first question, we will review basic search algorithms\n",
"\n",
"There are several approaches at building trees in Python. The most common approach is to define the tree as a separate data structure (through a Node type for example). See below. "
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"class Node(object):\n",
"\n",
" def __init__(self, data): # initialize the node without children\n",
"\n",
" self._data = data\n",
" self._children = []\n",
"\n",
" def getChildren(self):\n",
"\n",
" return self._children\n",
" \n",
" def getData(self):\n",
" \n",
" return self._data\n",
" \n",
" def addChild(self, child):\n",
" \n",
" self._children = self._children.append(child)\n",
" \n",
" \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### III.1.a Building a tree\n",
"\n",
"Using the code above, store the tree given below as a tree object using the node class (or any other efficient approach you like). \n",
"\n",
"Note : you can tag the nodes as you like "
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"