{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Intelligent Agents #\n", "\n", "This notebook serves as supporting material for topics covered in **Chapter 2 - Intelligent Agents** from the book *Artificial Intelligence: A Modern Approach.* This notebook uses implementations from [agents.py](https://github.com/aimacode/aima-python/blob/master/agents.py) module. Let's start by importing everything from agents module." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from agents import *\n", "from notebook import psource" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## CONTENTS\n", "\n", "* Overview\n", "* Agent\n", "* Environment\n", "* Simple Agent and Environment\n", "* Agents in a 2-D Environment\n", "* Wumpus Environment\n", "\n", "## OVERVIEW\n", "\n", "An agent, as defined in 2.1, is anything that can perceive its environment through sensors, and act upon that environment through actuators based on its agent program. This can be a dog, a robot, or even you. As long as you can perceive the environment and act on it, you are an agent. This notebook will explain how to implement a simple agent, create an environment, and implement a program that helps the agent act on the environment based on its percepts.\n", "\n", "## AGENT\n", "\n", "Let us now see how we define an agent. Run the next cell to see how `Agent` is defined in agents module." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "
\n", "class Agent(Thing):\n",
" """An Agent is a subclass of Thing with one required slot,\n",
" .program, which should hold a function that takes one argument, the\n",
" percept, and returns an action. (What counts as a percept or action\n",
" will depend on the specific environment in which the agent exists.)\n",
" Note that 'program' is a slot, not a method. If it were a method,\n",
" then the program could 'cheat' and look at aspects of the agent.\n",
" It's not supposed to do that: the program can only look at the\n",
" percepts. An agent program that needs a model of the world (and of\n",
" the agent itself) will have to build and maintain its own model.\n",
" There is an optional slot, .performance, which is a number giving\n",
" the performance measure of the agent in its environment."""\n",
"\n",
" def __init__(self, program=None):\n",
" self.alive = True\n",
" self.bump = False\n",
" self.holding = []\n",
" self.performance = 0\n",
" if program is None or not isinstance(program, collections.Callable):\n",
" print("Can't find a valid program for {}, falling back to default.".format(\n",
" self.__class__.__name__))\n",
"\n",
" def program(percept):\n",
" return eval(input('Percept={}; action? '.format(percept)))\n",
"\n",
" self.program = program\n",
"\n",
" def can_grab(self, thing):\n",
" """Return True if this agent can grab this thing.\n",
" Override for appropriate subclasses of Agent and Thing."""\n",
" return False\n",
"
class Environment:\n",
" """Abstract class representing an Environment. 'Real' Environment classes\n",
" inherit from this. Your Environment will typically need to implement:\n",
" percept: Define the percept that an agent sees.\n",
" execute_action: Define the effects of executing an action.\n",
" Also update the agent.performance slot.\n",
" The environment keeps a list of .things and .agents (which is a subset\n",
" of .things). Each agent has a .performance slot, initialized to 0.\n",
" Each thing has a .location slot, even though some environments may not\n",
" need this."""\n",
"\n",
" def __init__(self):\n",
" self.things = []\n",
" self.agents = []\n",
"\n",
" def thing_classes(self):\n",
" return [] # List of classes that can go into environment\n",
"\n",
" def percept(self, agent):\n",
" """Return the percept that the agent sees at this point. (Implement this.)"""\n",
" raise NotImplementedError\n",
"\n",
" def execute_action(self, agent, action):\n",
" """Change the world to reflect this action. (Implement this.)"""\n",
" raise NotImplementedError\n",
"\n",
" def default_location(self, thing):\n",
" """Default location to place a new thing with unspecified location."""\n",
" return None\n",
"\n",
" def exogenous_change(self):\n",
" """If there is spontaneous change in the world, override this."""\n",
" pass\n",
"\n",
" def is_done(self):\n",
" """By default, we're done when we can't find a live agent."""\n",
" return not any(agent.is_alive() for agent in self.agents)\n",
"\n",
" def step(self):\n",
" """Run the environment for one time step. If the\n",
" actions and exogenous changes are independent, this method will\n",
" do. If there are interactions between them, you'll need to\n",
" override this method."""\n",
" if not self.is_done():\n",
" actions = []\n",
" for agent in self.agents:\n",
" if agent.alive:\n",
" actions.append(agent.program(self.percept(agent)))\n",
" else:\n",
" actions.append("")\n",
" for (agent, action) in zip(self.agents, actions):\n",
" self.execute_action(agent, action)\n",
" self.exogenous_change()\n",
"\n",
" def run(self, steps=1000):\n",
" """Run the Environment for given number of time steps."""\n",
" for step in range(steps):\n",
" if self.is_done():\n",
" return\n",
" self.step()\n",
"\n",
" def list_things_at(self, location, tclass=Thing):\n",
" """Return all things exactly at a given location."""\n",
" return [thing for thing in self.things\n",
" if thing.location == location and isinstance(thing, tclass)]\n",
"\n",
" def some_things_at(self, location, tclass=Thing):\n",
" """Return true if at least one of the things at location\n",
" is an instance of class tclass (or a subclass)."""\n",
" return self.list_things_at(location, tclass) != []\n",
"\n",
" def add_thing(self, thing, location=None):\n",
" """Add a thing to the environment, setting its location. For\n",
" convenience, if thing is an agent program we make a new agent\n",
" for it. (Shouldn't need to override this.)"""\n",
" if not isinstance(thing, Thing):\n",
" thing = Agent(thing)\n",
" if thing in self.things:\n",
" print("Can't add the same thing twice")\n",
" else:\n",
" thing.location = location if location is not None else self.default_location(thing)\n",
" self.things.append(thing)\n",
" if isinstance(thing, Agent):\n",
" thing.performance = 0\n",
" self.agents.append(thing)\n",
"\n",
" def delete_thing(self, thing):\n",
" """Remove a thing from the environment."""\n",
" try:\n",
" self.things.remove(thing)\n",
" except ValueError as e:\n",
" print(e)\n",
" print(" in Environment delete_thing")\n",
" print(" Thing to be removed: {} at {}".format(thing, thing.location))\n",
" print(" from list: {}".format([(thing, thing.location) for thing in self.things]))\n",
" if thing in self.agents:\n",
" self.agents.remove(thing)\n",
"
Percept: | \n", "Feel Food | \n", "Feel Water | \n", "Feel Nothing | \n", "
Action: | \n", "eat | \n", "drink | \n", "move down | \n", "
Percept: | \n", "Feel Food | \n", "Feel Water | \n", "Feel Nothing | \n", "||||||
Action: | \n", "eat | \n", "drink | \n", "\n",
"
| \n",
"