{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## February 19\n", "More planning. \n", "\n", "- Air Cargo\n", "- Spare Tire\n", "- Three Block Tower\n", "- Shopping\n", "- Socks and Shoes\n", "- Cake " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from planning import *\n", "from notebook import psource" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Air Cargo Problem\n", "\n", "In the Air Cargo problem, we start with cargo at two airports, SFO and JFK. Our goal is to send each cargo to the other airport. We have two airplanes to help us accomplish the task. The problem can be defined with three actions: Load, Unload and Fly. Let us look how the air_cargo problem has been defined in the module.\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "

\n", "\n", "
def air_cargo():\n",
       "    """\n",
       "    [Figure 10.1] AIR-CARGO-PROBLEM\n",
       "\n",
       "    An air-cargo shipment problem for delivering cargo to different locations,\n",
       "    given the starting location and airplanes.\n",
       "\n",
       "    Example:\n",
       "    >>> from planning import *\n",
       "    >>> ac = air_cargo()\n",
       "    >>> ac.goal_test()\n",
       "    False\n",
       "    >>> ac.act(expr('Load(C2, P2, JFK)'))\n",
       "    >>> ac.act(expr('Load(C1, P1, SFO)'))\n",
       "    >>> ac.act(expr('Fly(P1, SFO, JFK)'))\n",
       "    >>> ac.act(expr('Fly(P2, JFK, SFO)'))\n",
       "    >>> ac.act(expr('Unload(C2, P2, SFO)'))\n",
       "    >>> ac.goal_test()\n",
       "    False\n",
       "    >>> ac.act(expr('Unload(C1, P1, JFK)'))\n",
       "    >>> ac.goal_test()\n",
       "    True\n",
       "    >>>\n",
       "    """\n",
       "\n",
       "    return PlanningProblem(init='At(C1, SFO) & At(C2, JFK) & At(P1, SFO) & At(P2, JFK) & Cargo(C1) & Cargo(C2) & Plane(P1) & Plane(P2) & Airport(SFO) & Airport(JFK)', \n",
       "                goals='At(C1, JFK) & At(C2, SFO)',\n",
       "                actions=[Action('Load(c, p, a)', \n",
       "                                precond='At(c, a) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)',\n",
       "                                effect='In(c, p) & ~At(c, a)'),\n",
       "                         Action('Unload(c, p, a)',\n",
       "                                precond='In(c, p) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)',\n",
       "                                effect='At(c, a) & ~In(c, p)'),\n",
       "                         Action('Fly(p, f, to)',\n",
       "                                precond='At(p, f) & Plane(p) & Airport(f) & Airport(to)',\n",
       "                                effect='At(p, to) & ~At(p, f)')])\n",
       "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "psource(air_cargo)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**At(c, a):** The cargo **'c'** is at airport **'a'**.\n", "\n", "**~At(c, a):** The cargo **'c'** is _not_ at airport **'a'**.\n", "\n", "**In(c, p):** Cargo **'c'** is in plane **'p'**.\n", "\n", "**~In(c, p):** Cargo **'c'** is _not_ in plane **'p'**.\n", "\n", "**Cargo(c):** Declare **'c'** as cargo.\n", "\n", "**Plane(p):** Declare **'p'** as plane.\n", "\n", "**Airport(a):** Declare **'a'** as airport.\n", "\n", "\n", "\n", "In the `initial_state`, we have cargo C1, plane P1 at airport SFO and cargo C2, plane P2 at airport JFK. \n", "Our goal state is to have cargo C1 at airport JFK and cargo C2 at airport SFO. We will discuss on how to achieve this. Let us now define an object of the `air_cargo` problem:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "airCargo = air_cargo()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "airCargo.goal_test()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[At(C1, SFO),\n", " At(C2, JFK),\n", " At(P1, SFO),\n", " At(P2, JFK),\n", " Cargo(C1),\n", " Cargo(C2),\n", " Plane(P1),\n", " Plane(P2),\n", " Airport(SFO),\n", " Airport(JFK)]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "airCargo.init" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[At(C1, JFK), At(C2, SFO)]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "airCargo.goals" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It returns False because the goal state is not yet reached. Now, we define the sequence of actions that it should take in order to achieve the goal.\n", "The actions are then carried out on the `airCargo` PlanningProblem.\n", "\n", "The actions available to us are the following: Load, Unload, Fly\n", "\n", "**Load(c, p, a):** Load cargo **'c'** into plane **'p'** from airport **'a'**.\n", "\n", "**Fly(p, f, t):** Fly the plane **'p'** from airport **'f'** to airport **'t'**.\n", "\n", "**Unload(c, p, a):** Unload cargo **'c'** from plane **'p'** to airport **'a'**.\n", "\n", "This problem can have multiple valid solutions.\n", "One such solution is shown below." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "solution = [expr(\"Load(C1 , P1, SFO)\"),\n", " expr(\"Fly(P1, SFO, JFK)\"),\n", " expr(\"Unload(C1, P1, JFK)\"),\n", " expr(\"Load(C2, P2, JFK)\"),\n", " expr(\"Fly(P2, JFK, SFO)\"),\n", " expr(\"Unload (C2, P2, SFO)\")] \n", "\n", "for action in solution:\n", " airCargo.act(action)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "airCargo.goal_test()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Cargo(C1),\n", " Cargo(C2),\n", " Plane(P1),\n", " Plane(P2),\n", " Airport(SFO),\n", " Airport(JFK),\n", " NotAt(C1, SFO),\n", " At(P1, JFK),\n", " NotAt(P1, SFO),\n", " At(C1, JFK),\n", " NotIn(C1, P1),\n", " NotAt(C2, JFK),\n", " At(P2, SFO),\n", " NotAt(P2, JFK),\n", " At(C2, SFO),\n", " NotIn(C2, P2)]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "airCargo.init" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Spare Tire Problem\n", "\n", "Let's consider the problem of changing a flat tire of a car. \n", "The goal is to mount a spare tire onto the car's axle, given that we have a flat tire on the axle and a spare tire in the trunk. " ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "

\n", "\n", "
def spare_tire():\n",
       "    """[Figure 10.2] SPARE-TIRE-PROBLEM\n",
       "\n",
       "    A problem involving changing the flat tire of a car\n",
       "    with a spare tire from the trunk.\n",
       "\n",
       "    Example:\n",
       "    >>> from planning import *\n",
       "    >>> st = spare_tire()\n",
       "    >>> st.goal_test()\n",
       "    False\n",
       "    >>> st.act(expr('Remove(Spare, Trunk)'))\n",
       "    >>> st.act(expr('Remove(Flat, Axle)'))\n",
       "    >>> st.goal_test()\n",
       "    False\n",
       "    >>> st.act(expr('PutOn(Spare, Axle)'))\n",
       "    >>> st.goal_test()\n",
       "    True\n",
       "    >>>\n",
       "    """\n",
       "\n",
       "    return PlanningProblem(init='Tire(Flat) & Tire(Spare) & At(Flat, Axle) & At(Spare, Trunk)',\n",
       "                goals='At(Spare, Axle) & At(Flat, Ground)',\n",
       "                actions=[Action('Remove(obj, loc)',\n",
       "                                precond='At(obj, loc)',\n",
       "                                effect='At(obj, Ground) & ~At(obj, loc)'),\n",
       "                         Action('PutOn(t, Axle)',\n",
       "                                precond='Tire(t) & At(t, Ground) & ~At(Flat, Axle)',\n",
       "                                effect='At(t, Axle) & ~At(t, Ground)'),\n",
       "                         Action('LeaveOvernight',\n",
       "                                precond='',\n",
       "                                effect='~At(Spare, Ground) & ~At(Spare, Axle) & ~At(Spare, Trunk) & \\\n",
       "                                        ~At(Flat, Ground) & ~At(Flat, Axle) & ~At(Flat, Trunk)')])\n",
       "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "psource(spare_tire)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**At(obj, loc):** object **'obj'** is at location **'loc'**.\n", "\n", "**~At(obj, loc):** object **'obj'** is _not_ at location **'loc'**.\n", "\n", "**Tire(t):** Declare a tire of type **'t'**.\n", "\n", "Let us now define an object of `spare_tire` problem:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "spareTire = spare_tire()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "spareTire.goal_test()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, it hasn't completed the goal. \n", "We now define a possible solution that can help us reach the goal of having a spare tire mounted onto the car's axle. \n", "The actions are then carried out on the `spareTire` PlanningProblem.\n", "\n", "The actions available to us are the following: Remove, PutOn\n", "\n", "**Remove(obj, loc):** Remove the tire **'obj'** from the location **'loc'**.\n", "\n", "**PutOn(t, Axle):** Attach the tire **'t'** on the Axle.\n", "\n", "**LeaveOvernight():** We live in a particularly bad neighborhood and all tires, flat or not, are stolen if we leave them overnight.\n" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "solution = [expr(\"Remove(Flat, Axle)\"),\n", " expr(\"Remove(Spare, Trunk)\"),\n", " expr(\"PutOn(Spare, Axle)\")]\n", "\n", "for action in solution:\n", " spareTire.act(action)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "spareTire.goal_test()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is another way to solve the problem:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "spareTire = spare_tire()\n", "\n", "solution = [expr('Remove(Spare, Trunk)'),\n", " expr('Remove(Flat, Axle)'),\n", " expr('PutOn(Spare, Axle)')]\n", "\n", "for action in solution:\n", " spareTire.act(action)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "spareTire.goal_test()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Tire(Flat),\n", " Tire(Spare),\n", " NotAt(Spare, Trunk),\n", " At(Flat, Ground),\n", " NotAt(Flat, Axle),\n", " At(Spare, Axle),\n", " NotAt(Spare, Ground)]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "spareTire.init" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that both solutions work, which means that the problem can be solved irrespective of the order in which the Remove actions take place, as long as both Remove actions take place before the PutOn action.\n", "\n", "We have successfully mounted a spare tire onto the axle.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Three Block Tower Problem\n", "This problem's domain consists of a set of cube-shaped blocks sitting on a table. \n", "The blocks can be stacked, but only one block can fit directly on top of another.\n", "A robot arm can pick up a block and move it to another position, either on the table or on top of another block. \n", "The arm can pick up only one block at a time, so it cannot pick up a block that has another one on it. \n", "The goal will always be to build one or more stacks of blocks. \n", "In our case, we consider only three blocks.\n", "The particular configuration we will use is called the Sussman anomaly after Prof. Gerry Sussman." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "

\n", "\n", "
def three_block_tower():\n",
       "    """\n",
       "    [Figure 10.3] THREE-BLOCK-TOWER\n",
       "\n",
       "    A blocks-world problem of stacking three blocks in a certain configuration,\n",
       "    also known as the Sussman Anomaly.\n",
       "\n",
       "    Example:\n",
       "    >>> from planning import *\n",
       "    >>> tbt = three_block_tower()\n",
       "    >>> tbt.goal_test()\n",
       "    False\n",
       "    >>> tbt.act(expr('MoveToTable(C, A)'))\n",
       "    >>> tbt.act(expr('Move(B, Table, C)'))\n",
       "    >>> tbt.goal_test()\n",
       "    False\n",
       "    >>> tbt.act(expr('Move(A, Table, B)'))\n",
       "    >>> tbt.goal_test()\n",
       "    True\n",
       "    >>>\n",
       "    """\n",
       "\n",
       "    return PlanningProblem(init='On(A, Table) & On(B, Table) & On(C, A) & Block(A) & Block(B) & Block(C) & Clear(B) & Clear(C)',\n",
       "                goals='On(A, B) & On(B, C)',\n",
       "                actions=[Action('Move(b, x, y)',\n",
       "                                precond='On(b, x) & Clear(b) & Clear(y) & Block(b) & Block(y)',\n",
       "                                effect='On(b, y) & Clear(x) & ~On(b, x) & ~Clear(y)'),\n",
       "                         Action('MoveToTable(b, x)',\n",
       "                                precond='On(b, x) & Clear(b) & Block(b)',\n",
       "                                effect='On(b, Table) & Clear(x) & ~On(b, x)')])\n",
       "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "psource(three_block_tower)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**On(b, x):** The block **'b'** is on **'x'**. **'x'** can be a table or a block.\n", "\n", "**~On(b, x):** The block **'b'** is _not_ on **'x'**. **'x'** can be a table or a block.\n", "\n", "**Block(b):** Declares **'b'** as a block.\n", "\n", "**Clear(x):** To indicate that there is nothing on **'x'** and it is free to be moved around.\n", "\n", "**~Clear(x):** To indicate that there is something on **'x'** and it cannot be moved.\n", " \n", " Let us now define an object of `three_block_tower` problem:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "threeBlockTower = three_block_tower()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "threeBlockTower.goal_test()" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[On(A, Table),\n", " On(B, Table),\n", " On(C, A),\n", " Block(A),\n", " Block(B),\n", " Block(C),\n", " Clear(B),\n", " Clear(C)]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "threeBlockTower.init" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[On(A, B), On(B, C)]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "threeBlockTower.goals" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, it hasn't completed the goal. \n", "We now define a sequence of actions that can stack three blocks in the required order. \n", "The actions are then carried out on the `threeBlockTower` PlanningProblem.\n", "\n", "The actions available to us are the following: MoveToTable, Move\n", "\n", "**MoveToTable(b, x): ** Move box **'b'** stacked on **'x'** to the table, given that box **'b'** is clear.\n", "\n", "**Move(b, x, y): ** Move box **'b'** stacked on **'x'** to the top of **'y'**, given that both **'b'** and **'y'** are clear.\n" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "solution = [expr(\"MoveToTable(C, A)\"),\n", " expr(\"Move(B, Table, C)\"),\n", " expr(\"Move(A, Table, B)\")]\n", "\n", "for action in solution:\n", " threeBlockTower.act(action)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Block(A),\n", " Block(B),\n", " Block(C),\n", " On(C, Table),\n", " Clear(A),\n", " NotOn(C, A),\n", " On(B, C),\n", " Clear(Table),\n", " NotOn(B, Table),\n", " NotClear(C),\n", " On(A, B),\n", " Clear(Table),\n", " NotOn(A, Table),\n", " NotClear(B)]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "threeBlockTower.init" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "threeBlockTower.goal_test()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Shopping Problem\n", "This problem requires us to acquire a carton of milk, a banana and a drill.\n", "Initially, we start from home and it is known to us that milk and bananas are available in the supermarket and the hardware store sells drills.\n", "Let's take a look at the definition of the `shopping_problem` in the module." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "

\n", "\n", "
def shopping_problem():\n",
       "    """\n",
       "    SHOPPING-PROBLEM\n",
       "\n",
       "    A problem of acquiring some items given their availability at certain stores.\n",
       "\n",
       "    Example:\n",
       "    >>> from planning import *\n",
       "    >>> sp = shopping_problem()\n",
       "    >>> sp.goal_test()\n",
       "    False\n",
       "    >>> sp.act(expr('Go(Home, HW)'))\n",
       "    >>> sp.act(expr('Buy(Drill, HW)'))\n",
       "    >>> sp.act(expr('Go(HW, SM)'))\n",
       "    >>> sp.act(expr('Buy(Banana, SM)'))\n",
       "    >>> sp.goal_test()\n",
       "    False\n",
       "    >>> sp.act(expr('Buy(Milk, SM)'))\n",
       "    >>> sp.goal_test()\n",
       "    True\n",
       "    >>>\n",
       "    """\n",
       "\n",
       "    return PlanningProblem(init='At(Home) & Sells(SM, Milk) & Sells(SM, Banana) & Sells(HW, Drill)',\n",
       "                goals='Have(Milk) & Have(Banana) & Have(Drill)', \n",
       "                actions=[Action('Buy(x, store)',\n",
       "                                precond='At(store) & Sells(store, x)',\n",
       "                                effect='Have(x)'),\n",
       "                         Action('Go(x, y)',\n",
       "                                precond='At(x)',\n",
       "                                effect='At(y) & ~At(x)')])\n",
       "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "psource(shopping_problem)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**At(x):** Indicates that we are currently at **'x'** where **'x'** can be Home, SM (supermarket) or HW (Hardware store).\n", "\n", "**~At(x):** Indicates that we are currently _not_ at **'x'**.\n", "\n", "**Sells(s, x):** Indicates that item **'x'** can be bought from store **'s'**.\n", "\n", "**Have(x):** Indicates that we possess the item **'x'**." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "shoppingProblem = shopping_problem()" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[At(Home), Sells(SM, Milk), Sells(SM, Banana), Sells(HW, Drill)]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shoppingProblem.init" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Have(Milk), Have(Banana), Have(Drill)]" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shoppingProblem.goal_test()\n", "shoppingProblem.goals" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's look at the possible actions\n", "\n", "**Buy(x, store):** Buy an item **'x'** from a **'store'** given that the **'store'** sells **'x'**.\n", "\n", "**Go(x, y):** Go to destination **'y'** starting from source **'x'**.\n", "\n", "We now define a valid solution that will help us reach the goal.\n", "The sequence of actions will then be carried out onto the `shoppingProblem` PlanningProblem." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "solution = [expr('Go(Home, SM)'),\n", " expr('Buy(Milk, SM)'),\n", " expr('Buy(Banana, SM)'),\n", " expr('Go(SM, HW)'),\n", " expr('Buy(Drill, HW)')]\n", "\n", "for action in solution:\n", " shoppingProblem.act(action)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shoppingProblem.goal_test()" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Sells(SM, Milk),\n", " Sells(SM, Banana),\n", " Sells(HW, Drill),\n", " NotAt(Home),\n", " Have(Milk),\n", " Have(Banana),\n", " At(HW),\n", " NotAt(SM),\n", " Have(Drill)]" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shoppingProblem.init" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Socks and Shoes\n", "This is a simple problem of putting on a pair of socks and shoes.\n", "The problem is defined in the module as given below." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "

\n", "\n", "
def socks_and_shoes():\n",
       "    """\n",
       "    SOCKS-AND-SHOES-PROBLEM\n",
       "\n",
       "    A task of wearing socks and shoes on both feet\n",
       "\n",
       "    Example:\n",
       "    >>> from planning import *\n",
       "    >>> ss = socks_and_shoes()\n",
       "    >>> ss.goal_test()\n",
       "    False\n",
       "    >>> ss.act(expr('RightSock'))\n",
       "    >>> ss.act(expr('RightShoe'))\n",
       "    >>> ss.act(expr('LeftSock'))\n",
       "    >>> ss.goal_test()\n",
       "    False\n",
       "    >>> ss.act(expr('LeftShoe'))\n",
       "    >>> ss.goal_test()\n",
       "    True\n",
       "    >>>\n",
       "    """\n",
       "\n",
       "    return PlanningProblem(init='',\n",
       "                goals='RightShoeOn & LeftShoeOn',\n",
       "                actions=[Action('RightShoe',\n",
       "                                precond='RightSockOn',\n",
       "                                effect='RightShoeOn'),\n",
       "                        Action('RightSock',\n",
       "                                precond='',\n",
       "                                effect='RightSockOn'),\n",
       "                        Action('LeftShoe',\n",
       "                                precond='LeftSockOn',\n",
       "                                effect='LeftShoeOn'),\n",
       "                        Action('LeftSock',\n",
       "                                precond='',\n",
       "                                effect='LeftSockOn')])\n",
       "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "psource(socks_and_shoes)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**LeftSockOn:** Indicates that we have already put on the left sock.\n", "\n", "**RightSockOn:** Indicates that we have already put on the right sock.\n", "\n", "**LeftShoeOn:** Indicates that we have already put on the left shoe.\n", "\n", "**RightShoeOn:** Indicates that we have already put on the right shoe.\n" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "socksShoes = socks_and_shoes()" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socksShoes.goal_test()" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "solution = [expr('RightSock'),\n", " expr('RightShoe'),\n", " expr('LeftSock'),\n", " expr('LeftShoe')]\n", "\n", "for action in solution:\n", " socksShoes.act(action)\n", " \n", "socksShoes.goal_test()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cake Problem\n", "This problem requires us to reach the state of having a cake and having eaten a cake simlutaneously, given a single cake.\n", "Let's first take a look at the definition of the `have_cake_and_eat_cake_too` problem in the module." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "

\n", "\n", "
def have_cake_and_eat_cake_too():\n",
       "    """\n",
       "    [Figure 10.7] CAKE-PROBLEM\n",
       "\n",
       "    A problem where we begin with a cake and want to \n",
       "    reach the state of having a cake and having eaten a cake.\n",
       "    The possible actions include baking a cake and eating a cake.\n",
       "\n",
       "    Example:\n",
       "    >>> from planning import *\n",
       "    >>> cp = have_cake_and_eat_cake_too()\n",
       "    >>> cp.goal_test()\n",
       "    False\n",
       "    >>> cp.act(expr('Eat(Cake)'))\n",
       "    >>> cp.goal_test()\n",
       "    False\n",
       "    >>> cp.act(expr('Bake(Cake)'))\n",
       "    >>> cp.goal_test()\n",
       "    True\n",
       "    >>>\n",
       "    """\n",
       "\n",
       "    return PlanningProblem(init='Have(Cake)',\n",
       "                goals='Have(Cake) & Eaten(Cake)',\n",
       "                actions=[Action('Eat(Cake)',\n",
       "                                precond='Have(Cake)',\n",
       "                                effect='Eaten(Cake) & ~Have(Cake)'),\n",
       "                         Action('Bake(Cake)',\n",
       "                                precond='~Have(Cake)',\n",
       "                                effect='Have(Cake)')])\n",
       "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "psource(have_cake_and_eat_cake_too)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since this problem doesn't involve variables, states can be considered similar to symbols in propositional logic.\n", "\n", "**Have(Cake):** Declares that we have a **'Cake'**.\n", "\n", "**~Have(Cake):** Declares that we _don't_ have a **'Cake'**." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "cakeProblem = have_cake_and_eat_cake_too()" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cakeProblem.goal_test()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us look at the possible actions.\n", "\n", "**Bake(x):** To bake **' x '**.\n", "\n", "**Eat(x):** To eat **' x '**.\n", "\n", "We now define a valid solution that can help us reach the goal.\n", "The sequence of actions will then be acted upon the `cakeProblem` PlanningProblem." ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "solution = [expr(\"Eat(Cake)\"),\n", " expr(\"Bake(Cake)\")]\n", "\n", "for action in solution:\n", " cakeProblem.act(action)\n", " \n", "cakeProblem.goal_test()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One might wonder if the order of the actions matters for this problem. It did not matter\n", "in the spare tire problem.\n", "Let's see for ourselves." ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "ename": "Exception", "evalue": "Action 'Bake(Cake)' pre-conditions not satisfied", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mException\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0maction\u001b[0m \u001b[0;32min\u001b[0m \u001b[0msolution\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mcakeProblem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mact\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/home/classes/cs470/hws/aima/planning.py\u001b[0m in \u001b[0;36mact\u001b[0;34m(self, action)\u001b[0m\n\u001b[1;32m 58\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Action '{}' not found\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0maction_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 59\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mlist_action\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheck_precond\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 60\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Action '{}' pre-conditions not satisfied\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 61\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlist_action\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclauses\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mException\u001b[0m: Action 'Bake(Cake)' pre-conditions not satisfied" ] } ], "source": [ "cakeProblem = have_cake_and_eat_cake_too()\n", "\n", "solution = [expr('Bake(Cake)'),\n", " expr('Eat(Cake)')]\n", "\n", "for action in solution:\n", " cakeProblem.act(action)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It raises an exception.\n", "Indeed, according to the problem, we cannot bake a cake if we already have one.\n", "In planning terms, '~Have(Cake)' is a precondition to the action 'Bake(Cake)'.\n", "Hence, this solution is invalid." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "nbformat": 4, "nbformat_minor": 2 }