From 8c2e4133b170e3de5e103da418db32b134c98b92 Mon Sep 17 00:00:00 2001 From: Marianna Date: Sat, 14 Jul 2018 01:32:01 +0300 Subject: [PATCH 1/7] Added angelic search to planning code --- planning.py | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 259 insertions(+), 5 deletions(-) diff --git a/planning.py b/planning.py index 9492e2c8b..759c60991 100644 --- a/planning.py +++ b/planning.py @@ -1253,7 +1253,7 @@ def act(self, action): raise Exception("Action '{}' not found".format(action.name)) self.init = list_action.do_action(self.jobs, self.resources, self.init, args).clauses - def refinements(hla, state, library): # TODO - refinements may be (multiple) HLA themselves ... + def refinements(hla, state, library): # refinements may be (multiple) HLA themselves ... """ state is a Problem, containing the current state kb library is a dictionary containing details for every possible refinement. eg: @@ -1292,7 +1292,6 @@ def refinements(hla, state, library): # TODO - refinements may be (multiple) HL e = Expr(hla.name, hla.args) indices = [i for i, x in enumerate(library['HLA']) if expr(x).op == hla.name] for i in indices: - # TODO multiple refinements precond = [] for p in library['precond'][i]: if p[0] == '~': @@ -1305,9 +1304,8 @@ def refinements(hla, state, library): # TODO - refinements may be (multiple) HL effect.append(expr('Not' + e[1:])) else: effect.append(expr(e)) - action = HLA(library['steps'][i][0], precond, effect) - if action.check_precond(state.init, action.args): - yield action + action = [HLA(library['steps'][i][j], precond, effect) for j in range(len(library['steps'][i]))] + yield [h for h in action if h.check_precond(state.init, h.args)] def hierarchical_search(problem, hierarchy): """ @@ -1346,6 +1344,160 @@ def result(problem, action): else: return problem + + + def angelic_search(problem, hierarchy, initialPlan): + """ + [Figure 11.8] A hierarchical planning algorithm that uses angelic semantics to identify and + commit to high-level plans that work while avoiding high-level plans that don’t. + The predicate MAKING-PROGRESS checks to make sure that we aren’t stuck in an infinite regression + of refinements. + At top level, call ANGELIC -SEARCH with [Act ] as the initialPlan . + + initialPlan contains a sequence of HLA's with angelic semantics + + The possible effects of an angelic HLA in initialPlan are : + ~ : effect remove + $+: effect possibly add + $-: effect possibly remove + $$: possibly add or remove + """ + frontier = deque(initialPlan) + n=0 + while n<4: + if not frontier: + return None + plan = frontier.popleft() # sequence of Nodes? (HLA/Angelic HLA as actions) + opt_reachable_set = Problem.reach_opt(problem.init, plan) + pes_reachable_set = Problem.reach_pes(problem.init, plan) + if problem.intersects_goal(opt_reachable_set): # all reachable states + if Problem.is_primitive( plan, hierarchy ): + return ([x for x in plan.action]) + guaranteed = problem.intersects_goal(pes_reachable_set) + if guaranteed and Problem.making_progress(plan, plan): + final_state = guaranteed[0] # any element of guaranteed + #print('decompose') + return Problem.decompose(hierarchy, problem, plan, final_state, pes_reachable_set) + hla = None # there should be at least one HLA/Angelic_HLA, otherwise plan would be primitive. + j=-1 + for i in range(len(plan.action)): + if type(plan.action[i]) is HLA or type(plan.action[i]) is Angelic_HLA: + hla = plan.action[i] + j=i + break + + if j>0: + prefix = plan.action[:j-1] + outcome = Problem.result(problem, prefix[-1]) + else: + prefix = [] + outcome = copy.deepcopy(problem) + if j < len(plan.action)-1: + suffix = plan.action[j+1:] + else: + suffix = [] + for sequence in Problem.refinements(hla, outcome, hierarchy): # find refinements + frontier.append(Angelic_Node(outcome.init, plan, prefix + sequence+ suffix, prefix+sequence+suffix)) + + + n+=1 + + def intersects_goal(problem, reachable_set): + """ + Find the intersection of the reachable states and the goal + """ + return [y for x in list(reachable_set.keys()) for y in reachable_set[x] if all(goal in y for goal in problem.goals)] + + + def is_primitive(plan, library): + """ + checks if the hla is primitive action + """ + for hla in plan.action: + indices = [i for i, x in enumerate(library['HLA']) if expr(x).op == hla.name] + for i in indices: + if library["steps"][i]: + return False + return True + + + + def reach_opt(init, plan): + """ + Finds the optimistic reachable set of the sequence of actions in plan + """ + reachable_set = {0: [init]} + optimistic_description = plan.action #list of angelic actions with optimistic description + return Problem.find_reachable_set(reachable_set, optimistic_description) + + + def reach_pes(init, plan): + """ + Finds the pessimistic reachable set of the sequence of actions in plan + """ + reachable_set = {0: [init]} + pessimistic_description = plan.action_pes # list of angelic actions with pessimistic description + return Problem.find_reachable_set(reachable_set, pessimistic_description) + + def find_reachable_set(reachable_set, action_description): + """ + Finds the reachable states of the action_description when applied in each state of reachable set. + """ + for i in range(len(action_description)): + reachable_set[i+1]=[] + if type(action_description[i]) is Angelic_HLA: + possible_actions = action_description[i].angelic_action() + else: + possible_actions = action_description + for action in possible_actions: + for state in reachable_set[i]: + if action.check_precond(state , action.args) : + if action.effect[0] : + new_state = action(state, action.args).clauses + reachable_set[i+1].append(new_state) + else: + reachable_set[i+1].append(state) + return reachable_set + + + + def making_progress(plan, initialPlan): + """ + Not correct + """ + if (len(plan.action)==1): + return False + return True + + def decompose(hierarchy, s_0, plan, s_f, reachable_set): + solution = [] + while plan.action_pes: + action = plan.action_pes.pop() + i = max(reachable_set.keys()) + if (i==0): + return solution + s_i = Problem.find_previous_state(s_f, reachable_set,i, action) + problem = Problem(s_i, s_f , plan.action) + j=0 + for x in Problem.angelic_search(problem, hierarchy, [Angelic_Node(s_i, Node(None), [action],[action])]): + solution.insert(j,x) + j+=1 + s_f = s_i + return solution + + + def find_previous_state(s_f, reachable_set, i, action): + """ + Given a final state s_f and an action finds a state s_i in reachable_set + such that when action is applied to state s_i returns s_f. + """ + s_i = reachable_set[i-1][0] + for state in reachable_set[i-1]: + if s_f in [x for x in Problem.reach_pes(state, Angelic_Node(state, None, [action],[action]))[1]]: + s_i =state + break + return s_i + def job_shop_problem(): """ @@ -1435,3 +1587,105 @@ def go_to_sfo(): } return Problem(init='At(Home)', goals='At(SFO)', actions=actions), library + + +class Angelic_HLA(HLA): + """ + Define Actions for the real-world (that may be refined further), under angelic semantics + """ + + def __init__(self, action, precond , effect, duration =0, consume = None, use = None): + super().__init__(action, precond, effect, duration, consume, use) + + + def convert(self, clauses): + """Converts strings into Exprs""" + lib = {'~': 'Not', + '$+': 'PosYes', + '$-': 'PosNot', + '$$' : 'PosYesNot'} + + if isinstance(clauses, Expr): + clauses = conjuncts(clauses) + for i in range(len(clauses)): + for ch in lib.keys(): + if clauses[i].op == ch: + clauses[i] = expr( lib[ch] + str(clauses[i].args[0])) + + elif isinstance(clauses, str): + for ch in lib.keys(): + clauses = clauses.replace(ch, lib[ch]) + if len(clauses) > 0: + clauses = expr(clauses) + + try: + clauses = conjuncts(clauses) + except AttributeError: + pass + + return clauses + + + + + def angelic_action(self): + """ + example: + """ + #print(self.effect) + + effects=[[]] + for clause in self.effect: + if clause.op[:9] == 'PosYesNot': + effects = effects*3 + n=3 + w=9 + elif clause.op[:6] == 'PosYes': + effects =effects* 2 + n=2 + w=6 + elif clause.op[:6] == 'PosNot': + effects = effects* 2 + n=2 + w=3 + else: + n=1 + w=0 + it=range(1) + if len(effects)!=0: + it = range(len(effects)//n) + for i in it: + if effects[i]: + if clause.args: + effects[i] = expr(str(effects[i]) + '&' + str(Expr(clause.op[w:],clause.args[0]))) + if n==3: + effects[i+len(effects)//3]= expr(str(effects[i+len(effects)//3]) + '&' + str(Expr(clause.op[6:],clause.args[0]))) + else: + effects[i] = expr(str(effects[i]) + '&' + str(expr(clause.op[w:]))) + if n==3: effects[i+len(effects)//3] = expr(str(effects[i+len(effects)//3]) + '&' + str(expr(clause.op[6:]))) + + else: + if clause.args: + effects[i] = Expr(clause.op[w:], clause.args[0]) + if n==3: effects[i+len(effects)//3] = Expr(clause.op[6:], clause.args[0]) + + else: + effects[i] = expr(clause.op[w:]) + if n==3: effects[i+len(effects)//3] = expr(clause.op[6:]) + #print('effects', effects) + + return [ HLA(Expr(self.name, self.args), self.precond, effects[i] ) for i in range(len(effects)) ] + + +class Angelic_Node(Node): + """ + Extends the class Node. + self.action: contains the optimistic description of an angelic HLA + self.action_pes: contains the pessimistic description of an angelic HLA + """ + + def __init__(self, state, parent=None, action_opt=None, action_pes=None, path_cost=0): + super().__init__(state, parent, action_opt, path_cost) + self.action_pes = action_pes + + From 7368b9bb790594f2679dba42ea9b853f4d7db543 Mon Sep 17 00:00:00 2001 From: Marianna Date: Sat, 14 Jul 2018 01:34:40 +0300 Subject: [PATCH 2/7] Added unit tests for angelic search --- tests/test_planning.py | 177 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 168 insertions(+), 9 deletions(-) diff --git a/tests/test_planning.py b/tests/test_planning.py index 5b6943ee3..aa53de45e 100644 --- a/tests/test_planning.py +++ b/tests/test_planning.py @@ -283,17 +283,176 @@ def test_job_shop_problem(): def test_refinements(): - library = {'HLA': ['Go(Home,SFO)','Taxi(Home, SFO)'], - 'steps': [['Taxi(Home, SFO)'],[]], - 'precond': [['At(Home)'],['At(Home)']], - 'effect': [['At(SFO)'],['At(SFO)'],['~At(Home)'],['~At(Home)']]} + library = { + 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'], + 'steps': [['Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], [], [], []], + 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']], + 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~At(SFOLongTermParking)'], ['~At(Home)']] } + go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') - taxi_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') + taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') - prob = Problem('At(Home)', 'At(SFO)', [go_SFO, taxi_SFO]) + prob = Problem('At(Home) & Have(Car)', 'At(SFO)', [go_SFO, taxi_SFO]) result = [i for i in Problem.refinements(go_SFO, prob, library)] - assert(len(result) == 1) - assert(result[0].name == 'Taxi') - assert(result[0].args == (expr('Home'), expr('SFO'))) + + for sequence in Problem.refinements(go_SFO, prob, library): + print ('ref',[(s.name, s.args) for s in sequence]) + + assert(len(result) == 2) + assert(result[0][0].name == 'Drive') + assert(result[0][0].args == (expr('Home'), expr('SFOLongTermParking'))) + assert(result[0][1].name == 'Shuttle') + assert(result[0][1].args == (expr('SFOLongTermParking'), expr('SFO'))) + assert(result[1][0].name == 'Taxi') + assert(result[1][0].args == expr('Home'), expr('SFO')) + + +def test_convert_angelic_HLA(): + """ + Converts angelic HLA's into expressions that correspond to their actions + ~ : Delete (Not) + $+ : Possibly add (PosYes) + $-: Possibly delete (PosNo) + $$: Possibly add / delete (PosYesNo) + """ + ang1 = Angelic_HLA('Test', precond = None, effect = '~A') + ang2 = Angelic_HLA('Test', precond = None, effect = '$+A') + ang3 = Angelic_HLA('Test', precond = None, effect = '$-A') + ang4 = Angelic_HLA('Test', precond = None, effect = '$$A') + + assert(ang1.convert(ang1.effect) == [expr('NotA')]) + assert(ang2.convert(ang2.effect) == [expr('PosYesA')]) + assert(ang3.convert(ang3.effect) == [expr('PosNotA')]) + assert(ang4.convert(ang4.effect) == [expr('PosYesNotA')]) + + +def test_is_primitive(): + """ + Tests if a plan is consisted out of primitive HLA's (angelic HLA's) + """ + library = { + 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'], + 'steps': [['Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], [], [], []], + 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']], + 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~At(SFOLongTermParking)'], ['~At(Home)']] } + + angelic_opt_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & $-At(Home)' ) + angelic_pes_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & ~At(Home)' ) + taxi_SFO = HLA('Taxi(Home, SFO)', precond = 'At(Home)', effect = 'At(SFO)') + drive_SFOLongTermParking = HLA('Drive(Home,SFOLongTermParking)', precond='At(Home) & Car', effect='At(SFOLongTermParking) & ~At(Home)') + shuttle_SFO = HLA('Shuttle(SFOLongTermParking,SFO)', precond = 'At(SFOLongTermParking)', effect = 'At(SFO) & ~At(SFOLongTermParking)') + + plan1 = Angelic_Node('At(Home)', None, [angelic_opt_description], [angelic_pes_description]) + plan2 = Angelic_Node('At(Home)', None, [taxi_SFO]) + plan3 = Angelic_Node('At(Home)', None, [drive_SFOLongTermParking, shuttle_SFO]) + + assert(not Problem.is_primitive(plan1, library)) + assert(Problem.is_primitive(plan2, library)) + + assert(Problem.is_primitive(plan3, library)) + + +def test_angelic_action(): + """ + Finds the HLA actions that correspond to the HLA actions with angelic semantics + + h1 : precondition positive: B _______ (add A) or (add A and remove B) + effect: add A and possibly remove B + + h2 : precondition positive: A _______ (add A and add C) or (delete A and add C) or (add C) or (add A and delete C) or + effect: possibly add/remove A and possibly add/remove C (delete A and delete C) or (delete C) or (add A) or (delete A) or [] + + """ + h_1 = Angelic_HLA( expr('h1'), 'B' , 'A & $-B') + h_2 = Angelic_HLA( expr('h2'), 'A', '$$A & $$C') + action_1 = Angelic_HLA.angelic_action(h_1) + action_2 = Angelic_HLA.angelic_action(h_2) + + assert ([a.effect for a in action_1] == [ [expr('A'),expr('NotB')], [expr('A')]] ) + assert ([a.effect for a in action_2] == [[expr('A') , expr('C')], [expr('NotA'), expr('C')], [expr('C')], [expr('A'), expr('NotC')], [expr('NotA'), expr('NotC')], [expr('NotC')], [expr('A')], [expr('NotA')], [None] ] ) + + +def test_optimistic_reachable_set(): + + h_1 = Angelic_HLA( 'h1', 'B' , '$+A & $-B ') + h_2 = Angelic_HLA( 'h2', 'A', '$$A & $$C') + f_1 = HLA('h1', 'B', 'A & ~B') + f_2 = HLA('h2', 'A', 'A & C') + problem = Problem('B', 'A', [f_1,f_2] ) + plan = Angelic_Node(problem.init, None, [h_1,h_2], [h_1,h_2]) + opt_reachable_set = Problem.reach_opt(problem.init, plan ) + assert(opt_reachable_set[1] == [[expr('A'), expr('NotB')], [expr('NotB')],[expr('B'), expr('A')], [expr('B')]]) + assert( problem.intersects_goal(opt_reachable_set) ) + + +def test_pesssimistic_reachable_set(): + """ + Given a problem initial state and a plan + """ + h_1 = Angelic_HLA( 'h1', 'B' , '$+A & $-B ') + h_2 = Angelic_HLA( 'h2', 'A', '$$A & $$C') + f_1 = HLA('h1', 'B', 'A & ~B') + f_2 = HLA('h2', 'A', 'A & C') + problem = Problem('B', 'A', [f_1,f_2] ) + plan = Angelic_Node(problem.init, None, [h_1,h_2], [h_1,h_2]) + pes_reachable_set = Problem.reach_pes(problem.init, plan ) + assert(pes_reachable_set[1] == [[expr('A'), expr('NotB')], [expr('NotB')],[expr('B'), expr('A')], [expr('B')]]) + assert(problem.intersects_goal(pes_reachable_set)) + + +def test_find_reachable_set(): + h_1 = Angelic_HLA( 'h1', 'B' , '$+A & $-B ') + f_1 = HLA('h1', 'B', 'A & ~B') + problem = Problem('B', 'A', [f_1] ) + plan = Angelic_Node(problem.init, None, [h_1], [h_1]) + reachable_set = {0: [problem.init]} + action_description = [h_1] + + reachable_set = Problem.find_reachable_set(reachable_set, action_description) + assert(reachable_set[1] == [[expr('A'), expr('NotB')], [expr('NotB')],[expr('B'), expr('A')], [expr('B')]]) + + + +def test_intersects_goal(): + problem_1 = Problem('At(SFO)', 'At(SFO)', []) + problem_2 = Problem('At(Home) & Have(Cash) & Have(Car) ', 'At(SFO) & Have(Cash)', []) + reachable_set_1 = {0: [problem_1.init]} + reachable_set_2 = {0: [problem_2.init]} + + assert(Problem.intersects_goal(problem_1, reachable_set_1)) + assert(not Problem.intersects_goal(problem_2, reachable_set_2)) + + +def test_making_progress(): + """ + function not yet implemented + """ + assert(True) + +def test_angelic_search(): + + library = { + 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'], + 'steps': [['Drive(Home, SFOLongTermParking)' , 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], [], [], []], + 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']], + 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~At(SFOLongTermParking)'], ['~At(Home)']] + } + + go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') + taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home) & Cash', effect='At(SFO) & ~At(Home)') + drive_SFOLongTermParking = HLA('Drive(Home,SFOLongTermParking)', precond='At(Home) & Car', effect='At(SFOLongTermParking) & ~At(Home)') + shuttle_SFO = HLA('Shuttle(SFOLongTermParking,SFO)', precond = 'At(SFOLongTermParking)', effect = 'At(SFO) & ~At(SFOLongTermParking)') + + prob = Problem('At(Home) & Have(Cash) & Have(Car) ', 'At(SFO) & Have(Cash)', [go_SFO, taxi_SFO, drive_SFOLongTermParking,shuttle_SFO]) + + angelic_opt_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & $-At(Home)' ) + angelic_pes_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & ~At(Home)' ) + + + initialPlan = [Angelic_Node(prob.init, None, [angelic_opt_description], [angelic_pes_description])] + assert( Problem.angelic_search(prob, library, initialPlan) ) + + + From dc41ef8ed2455d6328a48e066711080563d1203c Mon Sep 17 00:00:00 2001 From: Marianna Date: Sat, 14 Jul 2018 01:36:33 +0300 Subject: [PATCH 3/7] Created notebook planning_angelic_search.ipynb --- planning_angelic_search.ipynb | 327 ++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 planning_angelic_search.ipynb diff --git a/planning_angelic_search.ipynb b/planning_angelic_search.ipynb new file mode 100644 index 000000000..315809e9d --- /dev/null +++ b/planning_angelic_search.ipynb @@ -0,0 +1,327 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Angelic Search \n", + "\n", + "Search using angelic semantics (is a hierarchical search), where the agent chooses the implementation of the HLA's.
\n", + "The algorithms input is: problem, hierarchy and initialPlan\n", + "- problem is of type Problem \n", + "- hierarchy is a dictionary consisting of all the actions. \n", + "- initialPlan is an approximate description(optimistic and pessimistic) of the agents choices for the implementation.
\n", + " It is a nested list, containing sequence a of actions with their optimistic and pessimistic\n", + " description " + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [], + "source": [ + "from planning import * " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Angelic search algorithm consists of three parts. \n", + "- Search using angelic semantics\n", + "- Decompose\n", + "- a search in the space of refinements, in a similar way with hierarchical search\n", + "\n", + "### Searching using angelic semantics\n", + "- Find the reachable set (optimistic and pessimistic) of the sequence of angelic HLA in initialPlan\n", + " - If the optimistic reachable set doesn't intersect the goal, then there is no solution\n", + " - If the pessimistic reachable set intersects the goal, then we call decompose, in order to find the sequence of actions that lead us to the goal. \n", + " - If the optimistic reachable set intersects the goal, but the pessimistic doesn't we do some further refinements, in order to see if there is a sequence of actions that achieves the goal. \n", + " \n", + "### Search in space of refinements\n", + "- We create a search tree, that has root the action and children it's refinements\n", + "- We extend frontier by adding each refinement, so that we keep looping till we find all primitive actions\n", + "- If we achieve that we return the path of the solution (search tree), else there is no solution and we return None.\n", + "\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Decompose \n", + "- Finds recursively the sequence of states and actions that lead us from initial state to goal.\n", + "- For each of the above actions we find their refinements,if they are not primitive, by calling the angelic_search function. \n", + " If there are not refinements return None\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example\n", + "\n", + "Suppose that somebody wants to get to the airport. \n", + "The possible ways to do so is either get a taxi, or drive to the airport.
\n", + "Those two actions have some preconditions and some effects. \n", + "If you get the taxi, you need to have cash, whereas if you drive you need to have a car.
\n", + "Thus we define the following hierarchy of possible actions.\n", + "\n", + "##### hierarchy" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "library = {\n", + " 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'],\n", + " 'steps': [['Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], [], [], []],\n", + " 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']],\n", + " 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~At(SFOLongTermParking)'], ['~At(Home)']]\n", + " }" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "the possible actions are the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)')\n", + "taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home) & Have(Cash)', effect='At(SFO) & ~At(Home)')\n", + "drive_SFOLongTermParking = HLA('Drive(Home,SFOLongTermParking)', precond='At(Home) & Have(Car)', effect='At(SFOLongTermParking) & ~At(Home)')\n", + "shuttle_SFO = HLA('Shuttle(SFOLongTermParking,SFO)', precond = 'At(SFOLongTermParking)', effect = 'At(SFO) & ~At(SFOLongTermParking)')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Suppose that (our preconditionds are that) we are Home and we have cash and car and our goal is to get to SFO and maintain our cash, and our possible actions are the above.
\n", + "##### Then our problem is: " + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [], + "source": [ + "prob = Problem('At(Home) & Have(Cash) & Have(Car)', 'At(SFO) & Have(Cash)', [go_SFO, taxi_SFO, drive_SFOLongTermParking,shuttle_SFO])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An agent gives us some approximate information about the plan we will follow:
\n", + "(initialPlan is a list with two nested lists, containing the optimistic and pessimistic descriptions respectively, of the sequence of angelic HLA's)\n", + "##### InitialPlan" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [], + "source": [ + "angelic_opt_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & $-At(Home)' ) \n", + "angelic_pes_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & ~At(Home)' ) \n", + "\n", + "initialPlan = [Angelic_Node(prob.init, None, [angelic_opt_description], [angelic_pes_description])] \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We want to find the optimistic and pessimistic reachable set of initialPlan_1 when applied to the problem:\n", + "##### Optimistic/Pessimistic reachable set" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[At(Home), Have(Cash), Have(Car)], [Have(Cash), Have(Car), At(SFO), NotAt(Home)], [Have(Cash), Have(Car), NotAt(Home)], [At(Home), Have(Cash), Have(Car), At(SFO)], [At(Home), Have(Cash), Have(Car)]] \n", + "\n", + "[[At(Home), Have(Cash), Have(Car)], [Have(Cash), Have(Car), At(SFO), NotAt(Home)], [Have(Cash), Have(Car), NotAt(Home)]]\n" + ] + } + ], + "source": [ + "opt_reachable_set = Problem.reach_opt(prob.init, initialPlan[0])\n", + "pes_reachable_set = Problem.reach_pes(prob.init, initialPlan[0])\n", + "print([x for y in opt_reachable_set.keys() for x in opt_reachable_set[y]], '\\n')\n", + "print([x for y in pes_reachable_set.keys() for x in pes_reachable_set[y]])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Refinements" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Drive', 'Shuttle']\n", + "[{'precond': [At(Home), Have(Car)], 'name': 'Drive', 'completed': False, 'args': (Home, SFOLongTermParking), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}, {'precond': [At(Home), Have(Car)], 'name': 'Shuttle', 'completed': False, 'args': (SFOLongTermParking, SFO), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}] \n", + "\n", + "['Taxi']\n", + "[{'precond': [At(Home)], 'name': 'Taxi', 'completed': False, 'args': (Home, SFO), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}] \n", + "\n" + ] + } + ], + "source": [ + "for sequence in Problem.refinements(go_SFO, prob, library):\n", + " print([x.name for x in sequence])\n", + " print([x.__dict__ for x in sequence ], '\\n')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run the angelic search\n", + "##### Top level call" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('Drive', (Home, SFOLongTermParking)), ('Shuttle', (SFOLongTermParking, SFO))] \n", + "\n", + "[{'precond': [At(Home), Have(Car)], 'name': 'Drive', 'completed': False, 'args': (Home, SFOLongTermParking), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}, {'precond': [At(Home), Have(Car)], 'name': 'Shuttle', 'completed': False, 'args': (SFOLongTermParking, SFO), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}]\n" + ] + } + ], + "source": [ + "plan= Problem.angelic_search(prob, library, initialPlan)\n", + "print([(x.name, x.args) for x in plan], '\\n')\n", + "print([x.__dict__ for x in plan])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 2\n", + "(using decompose)" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [], + "source": [ + "library = {\n", + " 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Get(Ticket)' , 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'],\n", + " 'steps': [['Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], ['Get(Ticket)'],[], [], []],\n", + " 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'],['At(SFOLongTermPark)',' Have(Cash)'], ['At(SFOLongTermParking) & Have(Ticket)'], ['At(Home)']],\n", + " 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['Have(Ticket)'] ,['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~Have(Cash)'] ,['~At(SFOLongTermParking)'], ['~At(Home)','~Have(Cash)']]\n", + " }" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "possible actions" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [], + "source": [ + "go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)')\n", + "taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home) & Have(Cash)', effect='At(SFO) & ~At(Home)')\n", + "drive_SFOLongTermParking = HLA('Drive(Home,SFOLongTermParking)', precond='At(Home) & Have(Car)', effect='At(SFOLongTermParking) & ~At(Home)')\n", + "get_ticket = HLA('Get(Ticket)', precond = 'At(SFOLongTermPark) & Have(Cash)', effect = 'Have(Ticket) & ~Have(Cash)')\n", + "shuttle_SFO = HLA('Shuttle(SFOLongTermParking,SFO)', precond = 'At(SFOLongTermParking)', effect = 'At(SFO) & ~At(SFOLongTermParking)')" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('Shuttle', (SFOLongTermParking, SFO)), ('Get', (Ticket,))] \n", + "\n", + "[{'precond': [At(Home), Have(Car)], 'name': 'Shuttle', 'completed': False, 'args': (SFOLongTermParking, SFO), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}, {'precond': [At(Home), Have(Car)], 'name': 'Get', 'completed': False, 'args': (Ticket,), 'duration': 0, 'uses': {}, 'effect': [At(SFOLongTermParking)], 'consumes': {}}]\n" + ] + } + ], + "source": [ + "prob = Problem('At(Home) & Have(Cash) & Have(Car)', 'At(SFO)', [go_SFO, taxi_SFO, drive_SFOLongTermParking,get_ticket,shuttle_SFO])\n", + "initialPlan = [Angelic_Node(prob.init, None, [angelic_opt_description], [angelic_pes_description])]\n", + "plan = Problem.angelic_search(prob, library, initialPlan)\n", + "print([(x.name, x.args) for x in plan], '\\n')\n", + "print([x.__dict__ for x in plan])" + ] + } + ], + "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.5.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} From 70832509ba29cd7b80fdbc4d470e98053e16ecbe Mon Sep 17 00:00:00 2001 From: Marianna Date: Wed, 18 Jul 2018 14:44:34 +0300 Subject: [PATCH 4/7] Changes in refinements and tests --- planning.py | 93 ++++++++++++++++--------------------- tests/test_planning.py | 102 +++++++++++++++++++---------------------- 2 files changed, 88 insertions(+), 107 deletions(-) diff --git a/planning.py b/planning.py index 759c60991..8fb7b3f54 100644 --- a/planning.py +++ b/planning.py @@ -1274,38 +1274,32 @@ def refinements(hla, state, library): # refinements may be (multiple) HLA thems ], # empty refinements indicate a primitive action 'precond': [ - ['At(Home)', 'Have(Car)'], + ['At(Home) & Have(Car)'], ['At(Home)'], - ['At(Home)', 'Have(Car)'], + ['At(Home) & Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)'] ], 'effect': [ - ['At(SFO)', '~At(Home)'], - ['At(SFO)', '~At(Home)'], - ['At(SFOLongTermParking)', '~At(Home)'], - ['At(SFO)', '~At(SFOLongTermParking)'], - ['At(SFO)', '~At(Home)'] + ['At(SFO) & ~At(Home)'], + ['At(SFO) & ~At(Home)'], + ['At(SFOLongTermParking) & ~At(Home)'], + ['At(SFO) & ~At(SFOLongTermParking)'], + ['At(SFO) & ~At(Home)'] ] } """ e = Expr(hla.name, hla.args) indices = [i for i, x in enumerate(library['HLA']) if expr(x).op == hla.name] for i in indices: - precond = [] - for p in library['precond'][i]: - if p[0] == '~': - precond.append(expr('Not' + p[1:])) - else: - precond.append(expr(p)) - effect = [] - for e in library['effect'][i]: - if e[0] == '~': - effect.append(expr('Not' + e[1:])) - else: - effect.append(expr(e)) - action = [HLA(library['steps'][i][j], precond, effect) for j in range(len(library['steps'][i]))] - yield [h for h in action if h.check_precond(state.init, h.args)] + actions = [] + for j in range(len(library['steps'][i])): + # find the index of the step [j] of the HLA + index_step = [k for k,x in enumerate(library['HLA']) if x == library['steps'][i][j]][0] + precond = library['precond'][index_step][0] # preconditions of step [j] + effect = library['effect'][index_step][0] # effect of step [j] + actions.append(HLA(library['steps'][i][j], precond, effect)) + yield actions def hierarchical_search(problem, hierarchy): """ @@ -1336,14 +1330,12 @@ def hierarchical_search(problem, hierarchy): print("...") frontier.append(Node(plan.state, plan.parent, sequence)) - def result(problem, action): + def result(state, actions): """The outcome of applying an action to the current problem""" - if action is not None: - problem.act(action) - return problem - else: - return problem - + for a in actions: + if a.check_precond(state, a.args): + state = a(state, a.args).clauses + return state def angelic_search(problem, hierarchy, initialPlan): @@ -1363,14 +1355,13 @@ def angelic_search(problem, hierarchy, initialPlan): $$: possibly add or remove """ frontier = deque(initialPlan) - n=0 - while n<4: + while True: if not frontier: return None - plan = frontier.popleft() # sequence of Nodes? (HLA/Angelic HLA as actions) + plan = frontier.popleft() # sequence of HLA/Angelic HLA's opt_reachable_set = Problem.reach_opt(problem.init, plan) pes_reachable_set = Problem.reach_pes(problem.init, plan) - if problem.intersects_goal(opt_reachable_set): # all reachable states + if problem.intersects_goal(opt_reachable_set): if Problem.is_primitive( plan, hierarchy ): return ([x for x in plan.action]) guaranteed = problem.intersects_goal(pes_reachable_set) @@ -1378,30 +1369,14 @@ def angelic_search(problem, hierarchy, initialPlan): final_state = guaranteed[0] # any element of guaranteed #print('decompose') return Problem.decompose(hierarchy, problem, plan, final_state, pes_reachable_set) - hla = None # there should be at least one HLA/Angelic_HLA, otherwise plan would be primitive. - j=-1 - for i in range(len(plan.action)): - if type(plan.action[i]) is HLA or type(plan.action[i]) is Angelic_HLA: - hla = plan.action[i] - j=i - break - - if j>0: - prefix = plan.action[:j-1] - outcome = Problem.result(problem, prefix[-1]) - else: - prefix = [] - outcome = copy.deepcopy(problem) - if j < len(plan.action)-1: - suffix = plan.action[j+1:] - else: - suffix = [] + (hla, index) = Problem.find_hla(plan, hierarchy) # there should be at least one HLA/Angelic_HLA, otherwise plan would be primitive. + prefix = plan.action[:index-1] + suffix = plan.action[index+1:] + outcome = Problem(Problem.result(problem.init, prefix), problem.goals , problem.actions ) for sequence in Problem.refinements(hla, outcome, hierarchy): # find refinements frontier.append(Angelic_Node(outcome.init, plan, prefix + sequence+ suffix, prefix+sequence+suffix)) - n+=1 - def intersects_goal(problem, reachable_set): """ Find the intersection of the reachable states and the goal @@ -1459,7 +1434,19 @@ def find_reachable_set(reachable_set, action_description): reachable_set[i+1].append(state) return reachable_set - + def find_hla(plan, hierarchy): + """ + Finds the the first HLA action in plan.action, which is not primitive + and its corresponding index in plan.action + """ + hla = None + index = len(plan.action) + for i in range(len(plan.action)): # find the first HLA in plan, that is not primitive + if not Problem.is_primitive(Node(plan.state, plan.parent, [plan.action[i]]), hierarchy): + hla = plan.action[i] + index = i + break + return (hla, index) def making_progress(plan, initialPlan): """ diff --git a/tests/test_planning.py b/tests/test_planning.py index aa53de45e..92cd1dfce 100644 --- a/tests/test_planning.py +++ b/tests/test_planning.py @@ -281,32 +281,50 @@ def test_job_shop_problem(): assert p.goal_test() -def test_refinements(): - - library = { +# hierarchies +library_1 = { 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'], 'steps': [['Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], [], [], []], - 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']], - 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~At(SFOLongTermParking)'], ['~At(Home)']] } - + 'precond': [['At(Home) & Have(Car)'], ['At(Home)'], ['At(Home) & Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']], + 'effect': [['At(SFO) & ~At(Home)'], ['At(SFO) & ~At(Home) & ~Have(Cash)'], ['At(SFOLongTermParking) & ~At(Home)'], ['At(SFO) & ~At(LongTermParking)'], ['At(SFO) & ~At(Home) & ~Have(Cash)']] } + + +# HLA's +go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') +taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home) & ~Have(Cash)') +drive_SFOLongTermParking = HLA('Drive(Home, SFOLongTermParking)', 'At(Home) & Have(Car)','At(SFOLongTermParking) & ~At(Home)' ) +shuttle_SFO = HLA('Shuttle(SFOLongTermParking, SFO)', 'At(SFOLongTermParking)', 'At(SFO) & ~At(LongTermParking)') - go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') - taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') +# Angelic HLA's +angelic_opt_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & $-At(Home)' ) +angelic_pes_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & ~At(Home)' ) - prob = Problem('At(Home) & Have(Car)', 'At(SFO)', [go_SFO, taxi_SFO]) +# Angelic Nodes +plan1 = Angelic_Node('At(Home)', None, [angelic_opt_description], [angelic_pes_description]) +plan2 = Angelic_Node('At(Home)', None, [taxi_SFO]) +plan3 = Angelic_Node('At(Home)', None, [drive_SFOLongTermParking, shuttle_SFO]) - result = [i for i in Problem.refinements(go_SFO, prob, library)] - for sequence in Problem.refinements(go_SFO, prob, library): - print ('ref',[(s.name, s.args) for s in sequence]) +def test_refinements(): + + prob = Problem('At(Home) & Have(Car)', 'At(SFO)', [go_SFO]) + result = [i for i in Problem.refinements(go_SFO, prob, library_1)] + + assert(result[0][0].name == drive_SFOLongTermParking.name) + assert(result[0][0].args == drive_SFOLongTermParking.args) + assert(result[0][0].precond == drive_SFOLongTermParking.precond) + assert(result[0][0].effect == drive_SFOLongTermParking.effect) + + assert(result[0][1].name == shuttle_SFO.name) + assert(result[0][1].args == shuttle_SFO.args) + assert(result[0][1].precond == shuttle_SFO.precond) + assert(result[0][1].effect == shuttle_SFO.effect) - assert(len(result) == 2) - assert(result[0][0].name == 'Drive') - assert(result[0][0].args == (expr('Home'), expr('SFOLongTermParking'))) - assert(result[0][1].name == 'Shuttle') - assert(result[0][1].args == (expr('SFOLongTermParking'), expr('SFO'))) - assert(result[1][0].name == 'Taxi') - assert(result[1][0].args == expr('Home'), expr('SFO')) + + assert(result[1][0].name == taxi_SFO.name) + assert(result[1][0].args == taxi_SFO.args) + assert(result[1][0].precond == taxi_SFO.precond) + assert(result[1][0].effect == taxi_SFO.effect) def test_convert_angelic_HLA(): @@ -332,26 +350,9 @@ def test_is_primitive(): """ Tests if a plan is consisted out of primitive HLA's (angelic HLA's) """ - library = { - 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'], - 'steps': [['Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], [], [], []], - 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']], - 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~At(SFOLongTermParking)'], ['~At(Home)']] } - - angelic_opt_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & $-At(Home)' ) - angelic_pes_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & ~At(Home)' ) - taxi_SFO = HLA('Taxi(Home, SFO)', precond = 'At(Home)', effect = 'At(SFO)') - drive_SFOLongTermParking = HLA('Drive(Home,SFOLongTermParking)', precond='At(Home) & Car', effect='At(SFOLongTermParking) & ~At(Home)') - shuttle_SFO = HLA('Shuttle(SFOLongTermParking,SFO)', precond = 'At(SFOLongTermParking)', effect = 'At(SFO) & ~At(SFOLongTermParking)') - - plan1 = Angelic_Node('At(Home)', None, [angelic_opt_description], [angelic_pes_description]) - plan2 = Angelic_Node('At(Home)', None, [taxi_SFO]) - plan3 = Angelic_Node('At(Home)', None, [drive_SFOLongTermParking, shuttle_SFO]) - - assert(not Problem.is_primitive(plan1, library)) - assert(Problem.is_primitive(plan2, library)) - - assert(Problem.is_primitive(plan3, library)) + assert(not Problem.is_primitive(plan1, library_1)) + assert(Problem.is_primitive(plan2, library_1)) + assert(Problem.is_primitive(plan3, library_1)) def test_angelic_action(): @@ -375,7 +376,9 @@ def test_angelic_action(): def test_optimistic_reachable_set(): - + """ + Find optimistic reachable set given a problem initial state and a plan + """ h_1 = Angelic_HLA( 'h1', 'B' , '$+A & $-B ') h_2 = Angelic_HLA( 'h2', 'A', '$$A & $$C') f_1 = HLA('h1', 'B', 'A & ~B') @@ -389,7 +392,7 @@ def test_optimistic_reachable_set(): def test_pesssimistic_reachable_set(): """ - Given a problem initial state and a plan + Find pessimistic reachable set given a problem initial state and a plan """ h_1 = Angelic_HLA( 'h1', 'B' , '$+A & $-B ') h_2 = Angelic_HLA( 'h2', 'A', '$$A & $$C') @@ -432,19 +435,10 @@ def test_making_progress(): assert(True) def test_angelic_search(): - - library = { - 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'], - 'steps': [['Drive(Home, SFOLongTermParking)' , 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], [], [], []], - 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']], - 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~At(SFOLongTermParking)'], ['~At(Home)']] - } - - go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') - taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home) & Cash', effect='At(SFO) & ~At(Home)') - drive_SFOLongTermParking = HLA('Drive(Home,SFOLongTermParking)', precond='At(Home) & Car', effect='At(SFOLongTermParking) & ~At(Home)') - shuttle_SFO = HLA('Shuttle(SFOLongTermParking,SFO)', precond = 'At(SFOLongTermParking)', effect = 'At(SFO) & ~At(SFOLongTermParking)') - + """ + Test angelic search for problem, hierarchy, initialPlan + """ + prob = Problem('At(Home) & Have(Cash) & Have(Car) ', 'At(SFO) & Have(Cash)', [go_SFO, taxi_SFO, drive_SFOLongTermParking,shuttle_SFO]) angelic_opt_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & $-At(Home)' ) From ff7763d9d28e7f4efd522a7769670211d5e19910 Mon Sep 17 00:00:00 2001 From: Marianna Date: Wed, 18 Jul 2018 18:52:37 +0300 Subject: [PATCH 5/7] Modification in test_planning.py --- tests/test_planning.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/tests/test_planning.py b/tests/test_planning.py index 92cd1dfce..08e59ae2e 100644 --- a/tests/test_planning.py +++ b/tests/test_planning.py @@ -289,6 +289,14 @@ def test_job_shop_problem(): 'effect': [['At(SFO) & ~At(Home)'], ['At(SFO) & ~At(Home) & ~Have(Cash)'], ['At(SFOLongTermParking) & ~At(Home)'], ['At(SFO) & ~At(LongTermParking)'], ['At(SFO) & ~At(Home) & ~Have(Cash)']] } +library_2 = { + 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Bus(Home, MetroStop)', 'Metro(MetroStop, SFO)' , 'Metro(MetroStop, SFO)', 'Metro1(MetroStop, SFO)', 'Metro2(MetroStop, SFO)' ,'Taxi(Home, SFO)'], + 'steps': [['Bus(Home, MetroStop)', 'Metro(MetroStop, SFO)'], ['Taxi(Home, SFO)'], [], ['Metro1(MetroStop, SFO)'], ['Metro2(MetroStop, SFO)'],[],[],[]], + 'precond': [['At(Home)'], ['At(Home)'], ['At(Home)'], ['At(MetroStop)'], ['At(MetroStop)'],['At(MetroStop)'], ['At(MetroStop)'] ,['At(Home) & Have(Cash)']], + 'effect': [['At(SFO) & ~At(Home)'], ['At(SFO) & ~At(Home) & ~Have(Cash)'], ['At(MetroStop) & ~At(Home)'], ['At(SFO) & ~At(MetroStop)'], ['At(SFO) & ~At(MetroStop)'], ['At(SFO) & ~At(MetroStop)'] , ['At(SFO) & ~At(MetroStop)'] ,['At(SFO) & ~At(Home) & ~Have(Cash)']] + } + + # HLA's go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)') taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home) & ~Have(Cash)') @@ -438,15 +446,34 @@ def test_angelic_search(): """ Test angelic search for problem, hierarchy, initialPlan """ - - prob = Problem('At(Home) & Have(Cash) & Have(Car) ', 'At(SFO) & Have(Cash)', [go_SFO, taxi_SFO, drive_SFOLongTermParking,shuttle_SFO]) + #test_1 + prob_1 = Problem('At(Home) & Have(Cash) & Have(Car) ', 'At(SFO) & Have(Cash)', [go_SFO, taxi_SFO, drive_SFOLongTermParking,shuttle_SFO]) angelic_opt_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & $-At(Home)' ) angelic_pes_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & ~At(Home)' ) + initialPlan = [Angelic_Node(prob_1.init, None, [angelic_opt_description], [angelic_pes_description])] + solution = Problem.angelic_search(prob_1, library_1, initialPlan) + + assert( len(solution) == 2 ) + + assert(solution[0].name == drive_SFOLongTermParking.name) + assert(solution[0].args == drive_SFOLongTermParking.args) - initialPlan = [Angelic_Node(prob.init, None, [angelic_opt_description], [angelic_pes_description])] - assert( Problem.angelic_search(prob, library, initialPlan) ) + assert(solution[1].name == shuttle_SFO.name) + assert(solution[1].args == shuttle_SFO.args) + + #test_2 + solution_2 = Problem.angelic_search(prob_1, library_2, initialPlan) + + assert( len(solution_2) == 2 ) + + assert(solution_2[0].name == 'Bus') + assert(solution_2[0].args == (expr('Home'), expr('MetroStop'))) + + assert(solution_2[1].name == 'Metro1') + assert(solution_2[1].args == (expr('MetroStop'), expr('SFO'))) + From 0604602a4a14a905fdf2cac1b99122a66770b24c Mon Sep 17 00:00:00 2001 From: Marianna Date: Sat, 21 Jul 2018 21:41:21 +0300 Subject: [PATCH 6/7] Added comments in making progress and angelic action --- planning.ipynb | 2 +- planning.py | 128 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 95 insertions(+), 35 deletions(-) diff --git a/planning.ipynb b/planning.ipynb index ca54bcde2..82be3da14 100644 --- a/planning.ipynb +++ b/planning.ipynb @@ -5900,7 +5900,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.1" + "version": "3.5.3" } }, "nbformat": 4, diff --git a/planning.py b/planning.py index 8fb7b3f54..4dc743437 100644 --- a/planning.py +++ b/planning.py @@ -1450,7 +1450,11 @@ def find_hla(plan, hierarchy): def making_progress(plan, initialPlan): """ - Not correct + Not correct + + Normally should from infinite regression of refinements + + Only case covered: when plan contains one action (then there is no regression to be done) """ if (len(plan.action)==1): return False @@ -1558,18 +1562,18 @@ def go_to_sfo(): [] ], 'precond': [ - ['At(Home)', 'Have(Car)'], + ['At(Home) & Have(Car)'], ['At(Home)'], - ['At(Home)', 'Have(Car)'], + ['At(Home) & Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)'] ], 'effect': [ - ['At(SFO)', '~At(Home)'], - ['At(SFO)', '~At(Home)'], - ['At(SFOLongTermParking)', '~At(Home)'], - ['At(SFO)', '~At(SFOLongTermParking)'], - ['At(SFO)', '~At(Home)'] + ['At(SFO) & ~At(Home)'], + ['At(SFO) & ~At(Home)'], + ['At(SFOLongTermParking) & ~At(Home)'], + ['At(SFO) & ~At(SFOLongTermParking)'], + ['At(SFO) & ~At(Home)'] ] } @@ -1586,7 +1590,16 @@ def __init__(self, action, precond , effect, duration =0, consume = None, use = def convert(self, clauses): - """Converts strings into Exprs""" + """ + Converts strings into Exprs + An HLA with angelic semantics can achieve the effects of simple HLA's (add / remove a variable ) + and furthermore can have following effects on the variables: + Possibly add variable ( $+ ) + Possibly remove variable ( $- ) + Possibly add or remove a variable ( $$ ) + + Overrides HLA.convert function + """ lib = {'~': 'Not', '$+': 'PosYes', '$-': 'PosNot', @@ -1617,53 +1630,100 @@ def convert(self, clauses): def angelic_action(self): """ - example: + Converts a high level action (HLA) with angelic semantics into all of its corresponding high level actions (HLA). + An HLA with angelic semantics can achieve the effects of simple HLA's (add / remove a variable) + and furthermore can have following effects for each variable: + + Possibly add variable ( $+: 'PosYes' ) --> corresponds to two HLAs: + HLA_1: add variable + HLA_2: leave variable unchanged + + Possibly remove variable ( $-: 'PosNot' ) --> corresponds to two HLAs: + HLA_1: remove variable + HLA_2: leave variable unchanged + + Possibly add / remove a variable ( $$: 'PosYesNot' ) --> corresponds to three HLAs: + HLA_1: add variable + HLA_2: remove variable + HLA_3: leave variable unchanged + + + example: the angelic action with effects possibly add A and possibly add or remove B corresponds to the following 6 effects of HLAs: + + + '$+A & $$B': HLA_1: 'A & B' (add A and add B) + HLA_2: 'A & ~B' (add A and remove B) + HLA_3: 'A' (add A) + HLA_4: 'B' (add B) + HLA_5: '~B' (remove B) + HLA_6: ' ' (no effect) + """ - #print(self.effect) effects=[[]] for clause in self.effect: - if clause.op[:9] == 'PosYesNot': - effects = effects*3 - n=3 - w=9 - elif clause.op[:6] == 'PosYes': - effects =effects* 2 - n=2 - w=6 - elif clause.op[:6] == 'PosNot': - effects = effects* 2 - n=2 - w=3 - else: - n=1 - w=0 + (n,w) = Angelic_HLA.compute_parameters(clause, effects) + effects = effects*n # create n copies of effects it=range(1) if len(effects)!=0: + # split effects into n sublists (seperate n copies created in compute_parameters) it = range(len(effects)//n) for i in it: if effects[i]: if clause.args: - effects[i] = expr(str(effects[i]) + '&' + str(Expr(clause.op[w:],clause.args[0]))) + effects[i] = expr(str(effects[i]) + '&' + str(Expr(clause.op[w:],clause.args[0]))) # make changes in the ith part of effects if n==3: effects[i+len(effects)//3]= expr(str(effects[i+len(effects)//3]) + '&' + str(Expr(clause.op[6:],clause.args[0]))) else: - effects[i] = expr(str(effects[i]) + '&' + str(expr(clause.op[w:]))) - if n==3: effects[i+len(effects)//3] = expr(str(effects[i+len(effects)//3]) + '&' + str(expr(clause.op[6:]))) + effects[i] = expr(str(effects[i]) + '&' + str(expr(clause.op[w:]))) # make changes in the ith part of effects + if n==3: + effects[i+len(effects)//3] = expr(str(effects[i+len(effects)//3]) + '&' + str(expr(clause.op[6:]))) else: if clause.args: - effects[i] = Expr(clause.op[w:], clause.args[0]) - if n==3: effects[i+len(effects)//3] = Expr(clause.op[6:], clause.args[0]) + effects[i] = Expr(clause.op[w:], clause.args[0]) # make changes in the ith part of effects + if n==3: + effects[i+len(effects)//3] = Expr(clause.op[6:], clause.args[0]) else: - effects[i] = expr(clause.op[w:]) - if n==3: effects[i+len(effects)//3] = expr(clause.op[6:]) + effects[i] = expr(clause.op[w:]) # make changes in the ith part of effects + if n==3: + effects[i+len(effects)//3] = expr(clause.op[6:]) #print('effects', effects) - + return [ HLA(Expr(self.name, self.args), self.precond, effects[i] ) for i in range(len(effects)) ] + def compute_parameters(clause, effects): + """ + computes n,w + + n = number of HLA effects that the anelic HLA corresponds to + w = length of representation of angelic HLA effect + + n = 1, if effect is add + n = 1, if effect is remove + n = 2, if effect is possibly add + n = 2, if effect is possibly remove + n = 3, if effect is possibly add or remove + + """ + if clause.op[:9] == 'PosYesNot': + # possibly add/remove variable: three possible effects for the variable + n=3 + w=9 + elif clause.op[:6] == 'PosYes': # possibly add variable: two possible effects for the variable + n=2 + w=6 + elif clause.op[:6] == 'PosNot': # possibly remove variable: two possible effects for the variable + n=2 + w=3 # We want to keep 'Not' from 'PosNot' when adding action + else: # variable or ~variable + n=1 + w=0 + return (n,w) + + class Angelic_Node(Node): """ Extends the class Node. From 4b8fde04e72e08101362302606a3a5f1f8dde15c Mon Sep 17 00:00:00 2001 From: Marianna Date: Sun, 22 Jul 2018 01:09:31 +0300 Subject: [PATCH 7/7] Changes in planning_angelic.ipynb notebook --- planning.py | 4 +- planning_angelic_search.ipynb | 110 ++++++++++++++-------------------- 2 files changed, 47 insertions(+), 67 deletions(-) diff --git a/planning.py b/planning.py index 4dc743437..2913c2c2e 100644 --- a/planning.py +++ b/planning.py @@ -1731,8 +1731,8 @@ class Angelic_Node(Node): self.action_pes: contains the pessimistic description of an angelic HLA """ - def __init__(self, state, parent=None, action_opt=None, action_pes=None, path_cost=0): - super().__init__(state, parent, action_opt, path_cost) + def __init__(self, state, parent=None, action_opt=None, action_pes=None, path_cost=0): + super().__init__(state, parent, action_opt , path_cost) self.action_pes = action_pes diff --git a/planning_angelic_search.ipynb b/planning_angelic_search.ipynb index 315809e9d..20400cd49 100644 --- a/planning_angelic_search.ipynb +++ b/planning_angelic_search.ipynb @@ -17,7 +17,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 66, "metadata": {}, "outputs": [], "source": [ @@ -40,8 +40,8 @@ " - If the optimistic reachable set intersects the goal, but the pessimistic doesn't we do some further refinements, in order to see if there is a sequence of actions that achieves the goal. \n", " \n", "### Search in space of refinements\n", - "- We create a search tree, that has root the action and children it's refinements\n", - "- We extend frontier by adding each refinement, so that we keep looping till we find all primitive actions\n", + "- Create a search tree, that has root the action and children it's refinements\n", + "- Extend frontier by adding each refinement, so that we keep looping till we find all primitive actions\n", "- If we achieve that we return the path of the solution (search tree), else there is no solution and we return None.\n", "\n", " \n" @@ -76,16 +76,16 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 67, "metadata": {}, "outputs": [], "source": [ "library = {\n", " 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'],\n", " 'steps': [['Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], [], [], []],\n", - " 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']],\n", - " 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~At(SFOLongTermParking)'], ['~At(Home)']]\n", - " }" + " 'precond': [['At(Home) & Have(Car)'], ['At(Home)'], ['At(Home) & Have(Car)'], ['At(SFOLongTermParking)'], ['At(Home)']],\n", + " 'effect': [['At(SFO) & ~At(Home)'], ['At(SFO) & ~At(Home) & ~Have(Cash)'], ['At(SFOLongTermParking) & ~At(Home)'], ['At(SFO) & ~At(LongTermParking)'], ['At(SFO) & ~At(Home) & ~Have(Cash)']] }\n", + "\n" ] }, { @@ -98,15 +98,14 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 68, "metadata": {}, "outputs": [], "source": [ - "\n", "go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)')\n", - "taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home) & Have(Cash)', effect='At(SFO) & ~At(Home)')\n", - "drive_SFOLongTermParking = HLA('Drive(Home,SFOLongTermParking)', precond='At(Home) & Have(Car)', effect='At(SFOLongTermParking) & ~At(Home)')\n", - "shuttle_SFO = HLA('Shuttle(SFOLongTermParking,SFO)', precond = 'At(SFOLongTermParking)', effect = 'At(SFO) & ~At(SFOLongTermParking)')" + "taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home) & ~Have(Cash)')\n", + "drive_SFOLongTermParking = HLA('Drive(Home, SFOLongTermParking)', 'At(Home) & Have(Car)','At(SFOLongTermParking) & ~At(Home)' )\n", + "shuttle_SFO = HLA('Shuttle(SFOLongTermParking, SFO)', 'At(SFOLongTermParking)', 'At(SFO) & ~At(LongTermParking)')" ] }, { @@ -119,7 +118,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 69, "metadata": {}, "outputs": [], "source": [ @@ -131,18 +130,22 @@ "metadata": {}, "source": [ "An agent gives us some approximate information about the plan we will follow:
\n", - "(initialPlan is a list with two nested lists, containing the optimistic and pessimistic descriptions respectively, of the sequence of angelic HLA's)\n", + "(initialPlan is an Angelic Node, where: \n", + "- state is the initial state of the problem, \n", + "- parent is None \n", + "- action: is a list of actions (Angelic HLA's) with the optimistic estimators of effects and \n", + "- action_pes: is a list of actions (Angelic HLA's) with the pessimistic approximations of the effects\n", "##### InitialPlan" ] }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 70, "metadata": {}, "outputs": [], "source": [ "angelic_opt_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & $-At(Home)' ) \n", - "angelic_pes_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & ~At(Home)' ) \n", + "angelic_pes_description = Angelic_HLA('Go(Home, SFO)', precond = 'At(Home)', effect ='$+At(SFO) & ~At(Home)' )\n", "\n", "initialPlan = [Angelic_Node(prob.init, None, [angelic_opt_description], [angelic_pes_description])] \n" ] @@ -151,13 +154,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We want to find the optimistic and pessimistic reachable set of initialPlan_1 when applied to the problem:\n", + "We want to find the optimistic and pessimistic reachable set of initialPlan when applied to the problem:\n", "##### Optimistic/Pessimistic reachable set" ] }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 71, "metadata": {}, "outputs": [ { @@ -186,25 +189,25 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 72, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "['Drive', 'Shuttle']\n", - "[{'precond': [At(Home), Have(Car)], 'name': 'Drive', 'completed': False, 'args': (Home, SFOLongTermParking), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}, {'precond': [At(Home), Have(Car)], 'name': 'Shuttle', 'completed': False, 'args': (SFOLongTermParking, SFO), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}] \n", + "[HLA(Drive(Home, SFOLongTermParking)), HLA(Shuttle(SFOLongTermParking, SFO))]\n", + "[{'consumes': {}, 'effect': [At(SFOLongTermParking), NotAt(Home)], 'uses': {}, 'completed': False, 'precond': [At(Home), Have(Car)], 'args': (Home, SFOLongTermParking), 'name': 'Drive', 'duration': 0}, {'consumes': {}, 'effect': [At(SFO), NotAt(LongTermParking)], 'uses': {}, 'completed': False, 'precond': [At(SFOLongTermParking)], 'args': (SFOLongTermParking, SFO), 'name': 'Shuttle', 'duration': 0}] \n", "\n", - "['Taxi']\n", - "[{'precond': [At(Home)], 'name': 'Taxi', 'completed': False, 'args': (Home, SFO), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}] \n", + "[HLA(Taxi(Home, SFO))]\n", + "[{'consumes': {}, 'effect': [At(SFO), NotAt(Home), NotHave(Cash)], 'uses': {}, 'completed': False, 'precond': [At(Home)], 'args': (Home, SFO), 'name': 'Taxi', 'duration': 0}] \n", "\n" ] } ], "source": [ "for sequence in Problem.refinements(go_SFO, prob, library):\n", - " print([x.name for x in sequence])\n", + " print (sequence)\n", " print([x.__dict__ for x in sequence ], '\\n')" ] }, @@ -218,88 +221,65 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 73, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[('Drive', (Home, SFOLongTermParking)), ('Shuttle', (SFOLongTermParking, SFO))] \n", + "[HLA(Drive(Home, SFOLongTermParking)), HLA(Shuttle(SFOLongTermParking, SFO))] \n", "\n", - "[{'precond': [At(Home), Have(Car)], 'name': 'Drive', 'completed': False, 'args': (Home, SFOLongTermParking), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}, {'precond': [At(Home), Have(Car)], 'name': 'Shuttle', 'completed': False, 'args': (SFOLongTermParking, SFO), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}]\n" + "[{'consumes': {}, 'effect': [At(SFOLongTermParking), NotAt(Home)], 'uses': {}, 'completed': False, 'precond': [At(Home), Have(Car)], 'args': (Home, SFOLongTermParking), 'name': 'Drive', 'duration': 0}, {'consumes': {}, 'effect': [At(SFO), NotAt(LongTermParking)], 'uses': {}, 'completed': False, 'precond': [At(SFOLongTermParking)], 'args': (SFOLongTermParking, SFO), 'name': 'Shuttle', 'duration': 0}]\n" ] } ], "source": [ "plan= Problem.angelic_search(prob, library, initialPlan)\n", - "print([(x.name, x.args) for x in plan], '\\n')\n", - "print([x.__dict__ for x in plan])" + "print (plan, '\\n')\n", + "print ([x.__dict__ for x in plan])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Example 2\n", - "(using decompose)" + "## Example 2" ] }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 74, "metadata": {}, "outputs": [], "source": [ - "library = {\n", - " 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Drive(Home, SFOLongTermParking)', 'Get(Ticket)' , 'Shuttle(SFOLongTermParking, SFO)', 'Taxi(Home, SFO)'],\n", - " 'steps': [['Drive(Home, SFOLongTermParking)', 'Shuttle(SFOLongTermParking, SFO)'], ['Taxi(Home, SFO)'], ['Get(Ticket)'],[], [], []],\n", - " 'precond': [['At(Home)', 'Have(Car)'], ['At(Home)'], ['At(Home)', 'Have(Car)'],['At(SFOLongTermPark)',' Have(Cash)'], ['At(SFOLongTermParking) & Have(Ticket)'], ['At(Home)']],\n", - " 'effect': [['At(SFO)'], ['At(SFO)'], ['At(SFOLongTermParking)'], ['Have(Ticket)'] ,['At(SFO)'], ['At(SFO)'], ['~At(Home)'], ['~At(Home)'], ['~At(Home)'], ['~Have(Cash)'] ,['~At(SFOLongTermParking)'], ['~At(Home)','~Have(Cash)']]\n", + "library_2 = {\n", + " 'HLA': ['Go(Home,SFO)', 'Go(Home,SFO)', 'Bus(Home, MetroStop)', 'Metro(MetroStop, SFO)' , 'Metro(MetroStop, SFO)', 'Metro1(MetroStop, SFO)', 'Metro2(MetroStop, SFO)' ,'Taxi(Home, SFO)'],\n", + " 'steps': [['Bus(Home, MetroStop)', 'Metro(MetroStop, SFO)'], ['Taxi(Home, SFO)'], [], ['Metro1(MetroStop, SFO)'], ['Metro2(MetroStop, SFO)'],[],[],[]],\n", + " 'precond': [['At(Home)'], ['At(Home)'], ['At(Home)'], ['At(MetroStop)'], ['At(MetroStop)'],['At(MetroStop)'], ['At(MetroStop)'] ,['At(Home) & Have(Cash)']],\n", + " 'effect': [['At(SFO) & ~At(Home)'], ['At(SFO) & ~At(Home) & ~Have(Cash)'], ['At(MetroStop) & ~At(Home)'], ['At(SFO) & ~At(MetroStop)'], ['At(SFO) & ~At(MetroStop)'], ['At(SFO) & ~At(MetroStop)'] , ['At(SFO) & ~At(MetroStop)'] ,['At(SFO) & ~At(Home) & ~Have(Cash)']] \n", " }" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "possible actions" - ] - }, - { - "cell_type": "code", - "execution_count": 95, - "metadata": {}, - "outputs": [], - "source": [ - "go_SFO = HLA('Go(Home,SFO)', precond='At(Home)', effect='At(SFO) & ~At(Home)')\n", - "taxi_SFO = HLA('Taxi(Home,SFO)', precond='At(Home) & Have(Cash)', effect='At(SFO) & ~At(Home)')\n", - "drive_SFOLongTermParking = HLA('Drive(Home,SFOLongTermParking)', precond='At(Home) & Have(Car)', effect='At(SFOLongTermParking) & ~At(Home)')\n", - "get_ticket = HLA('Get(Ticket)', precond = 'At(SFOLongTermPark) & Have(Cash)', effect = 'Have(Ticket) & ~Have(Cash)')\n", - "shuttle_SFO = HLA('Shuttle(SFOLongTermParking,SFO)', precond = 'At(SFOLongTermParking)', effect = 'At(SFO) & ~At(SFOLongTermParking)')" - ] - }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 75, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[('Shuttle', (SFOLongTermParking, SFO)), ('Get', (Ticket,))] \n", + "[HLA(Bus(Home, MetroStop)), HLA(Metro1(MetroStop, SFO))] \n", "\n", - "[{'precond': [At(Home), Have(Car)], 'name': 'Shuttle', 'completed': False, 'args': (SFOLongTermParking, SFO), 'duration': 0, 'uses': {}, 'effect': [At(SFO)], 'consumes': {}}, {'precond': [At(Home), Have(Car)], 'name': 'Get', 'completed': False, 'args': (Ticket,), 'duration': 0, 'uses': {}, 'effect': [At(SFOLongTermParking)], 'consumes': {}}]\n" + "[{'consumes': {}, 'effect': [At(MetroStop), NotAt(Home)], 'uses': {}, 'completed': False, 'precond': [At(Home)], 'args': (Home, MetroStop), 'name': 'Bus', 'duration': 0}, {'consumes': {}, 'effect': [At(SFO), NotAt(MetroStop)], 'uses': {}, 'completed': False, 'precond': [At(MetroStop)], 'args': (MetroStop, SFO), 'name': 'Metro1', 'duration': 0}]\n" ] } ], "source": [ - "prob = Problem('At(Home) & Have(Cash) & Have(Car)', 'At(SFO)', [go_SFO, taxi_SFO, drive_SFOLongTermParking,get_ticket,shuttle_SFO])\n", - "initialPlan = [Angelic_Node(prob.init, None, [angelic_opt_description], [angelic_pes_description])]\n", - "plan = Problem.angelic_search(prob, library, initialPlan)\n", - "print([(x.name, x.args) for x in plan], '\\n')\n", - "print([x.__dict__ for x in plan])" + "plan_2 = Problem.angelic_search(prob, library_2, initialPlan)\n", + "print(plan_2, '\\n')\n", + "print([x.__dict__ for x in plan_2])" ] } ],