From c1f69eac6a795a9d54b2115dd1b6afada0e1882d Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Fri, 18 May 2018 00:21:58 +0530 Subject: [PATCH 1/9] Refactored HLA --- planning.py | 401 ++++++++++++++++++---------------------------------- 1 file changed, 140 insertions(+), 261 deletions(-) diff --git a/planning.py b/planning.py index e31cd2f87..72b51ac76 100644 --- a/planning.py +++ b/planning.py @@ -31,7 +31,14 @@ def convert(self, clauses): clauses = conjuncts(clauses) except AttributeError: clauses = clauses - return clauses + + new_clauses = [] + for clause in clauses: + if clause.op == '~': + new_clauses.append(expr('Not' + str(clause.args[0]))) + else: + new_clauses.append(clause) + return new_clauses def goal_test(self): """Checks if the goals have been reached""" @@ -111,7 +118,6 @@ def check_precond(self, kb, args): if isinstance(kb, list): kb = FolKB(kb) - for clause in self.precond: if self.substitute(clause, args) not in kb.clauses: return False @@ -141,95 +147,93 @@ def act(self, kb, args): return kb -def air_cargo(): - """Air cargo problem""" - - return PDDL(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)', - goals='At(C1, JFK) & At(C2, SFO)', - actions=[Action('Load(c, p, a)', - precond='At(c, a) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)', - effect='In(c, p) & ~At(c, a)'), - Action('Unload(c, p, a)', - precond='In(c, p) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)', - effect='At(c, a) & ~In(c, p)'), - Action('Fly(p, f, to)', - precond='At(p, f) & Plane(p) & Airport(f) & Airport(to)', - effect='At(p, to) & ~At(p, f)')]) - - -def spare_tire(): - """Spare tire problem""" - - return PDDL(init='Tire(Flat) & Tire(Spare) & At(Flat, Axle) & At(Spare, Trunk)', - goals='At(Spare, Axle) & At(Flat, Ground)', - actions=[Action('Remove(obj, loc)', - precond='At(obj, loc)', - effect='At(obj, Ground) & ~At(obj, loc)'), - Action('PutOn(t, Axle)', - precond='Tire(t) & At(t, Ground) & ~At(Flat, Axle)', - effect='At(t, Axle) & ~At(t, Ground)'), - Action('LeaveOvernight', - precond='', - effect='~At(Spare, Ground) & ~At(Spare, Axle) & ~At(Spare, Trunk) & \ - ~At(Flat, Ground) & ~At(Flat, Axle) & ~At(Flat, Trunk)')]) - - -def three_block_tower(): - """Sussman Anomaly problem""" - - return PDDL(init='On(A, Table) & On(B, Table) & On(C, A) & Block(A) & Block(B) & Block(C) & Clear(B) & Clear(C)', - goals='On(A, B) & On(B, C)', - actions=[Action('Move(b, x, y)', - precond='On(b, x) & Clear(b) & Clear(y) & Block(b) & Block(y)', - effect='On(b, y) & Clear(x) & ~On(b, x) & ~Clear(y)'), - Action('MoveToTable(b, x)', - precond='On(b, x) & Clear(b) & Block(b)', - effect='On(b, Table) & Clear(x) & ~On(b, x)')]) - - -def have_cake_and_eat_cake_too(): - """Cake problem""" - - return PDDL(init='Have(Cake)', - goals='Have(Cake) & Eaten(Cake)', - actions=[Action('Eat(Cake)', - precond='Have(Cake)', - effect='Eaten(Cake) & ~Have(Cake)'), - Action('Bake(Cake)', - precond='~Have(Cake)', - effect='Have(Cake)')]) - - -def shopping_problem(): - """Shopping problem""" - - return PDDL(init='At(Home) & Sells(SM, Milk) & Sells(SM, Banana) & Sells(HW, Drill)', - goals='Have(Milk) & Have(Banana) & Have(Drill)', - actions=[Action('Buy(x, store)', - precond='At(store) & Sells(store, x)', - effect='Have(x)'), - Action('Go(x, y)', - precond='At(x)', - effect='At(y) & ~At(x)')]) - - -def socks_and_shoes(): - """Socks and shoes problem""" - - return PDDL(init='', - goals='RightShoeOn & LeftShoeOn', - actions=[Action('RightShoe', - precond='RightSockOn', - effect='RightShoeOn'), - Action('RightSock', - precond='', - effect='RightSockOn'), - Action('LeftShoe', - precond='LeftSockOn', - effect='LeftShoeOn'), - Action('LeftSock', - precond='', - effect='LeftSockOn')]) +# Air cargo problem +air_cargo = PDDL(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)', + goals='At(C1, JFK) & At(C2, SFO)', + actions=[Action('Load(c, p, a)', + precond='At(c, a) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)', + effect='In(c, p) & ~At(c, a)'), + Action('Unload(c, p, a)', + precond='In(c, p) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)', + effect='At(c, a) & ~In(c, p)'), + Action('Fly(p, f, to)', + precond='At(p, f) & Plane(p) & Airport(f) & Airport(to)', + effect='At(p, to) & ~At(p, f)')]) + + +# Spare tire problem +spare_tire = PDDL(init='Tire(Flat) & Tire(Spare) & At(Flat, Axle) & At(Spare, Trunk)', + goals='At(Spare, Axle) & At(Flat, Ground)', + actions=[Action('Remove(obj, loc)', + precond='At(obj, loc)', + effect='At(obj, Ground) & ~At(obj, loc)'), + Action('PutOn(t, Axle)', + precond='Tire(t) & At(t, Ground) & ~At(Flat, Axle)', + effect='At(t, Axle) & ~At(t, Ground)'), + Action('LeaveOvernight', + precond='', + effect='~At(Spare, Ground) & ~At(Spare, Axle) & ~At(Spare, Trunk) & ~At(Flat, Ground) & ~At(Flat, Axle) & ~At(Flat, Trunk)')]) + + +# Sussman Anomaly problem +three_block_tower = PDDL(init='On(A, Table) & On(B, Table) & On(C, A) & Block(A) & Block(B) & Block(C) & Clear(B) & Clear(C)', + goals='On(A, B) & On(B, C)', + actions=[Action('Move(b, x, y)', + precond='On(b, x) & Clear(b) & Clear(y) & Block(b) & Block(y)', + effect='On(b, y) & Clear(x) & ~On(b, x) & ~Clear(y)'), + Action('MoveToTable(b, x)', + precond='On(b, x) & Clear(b) & Block(b)', + effect='On(b, Table) & Clear(x) & ~On(b, x)')]) + + +# Cake problem +have_cake_and_eat_cake_too = PDDL(init='Have(Cake)', + goals='Have(Cake) & Eaten(Cake)', + actions=[Action('Eat(Cake)', + precond='Have(Cake)', + effect='Eaten(Cake) & ~Have(Cake)'), + Action('Bake(Cake)', + precond='~Have(Cake)', + effect='Have(Cake)')]) + + +# Shopping problem +shopping_problem = PDDL(init='At(Home) & Sells(SM, Milk) & Sells(SM, Banana) & Sells(HW, Drill)', + goals='Have(Milk) & Have(Banana) & Have(Drill)', + actions=[Action('Buy(x, store)', + precond='At(store) & Sells(store, x)', + effect='Have(x)'), + Action('Go(x, y)', + precond='At(x)', + effect='At(y) & ~At(x)')]) + + +# Socks and shoes problem +socks_and_shoes = PDDL(init='', + goals='RightShoeOn & LeftShoeOn', + actions=[Action('RightShoe', + precond='RightSockOn', + effect='RightShoeOn'), + Action('RightSock', + precond='', + effect='RightSockOn'), + Action('LeftShoe', + precond='LeftSockOn', + effect='LeftShoeOn'), + Action('LeftSock', + precond='', + effect='LeftSockOn')]) + + +# Doubles tennis problem +double_tennis_problem = PDDL(init='At(A, LeftBaseLine) & At(B, RightNet) & Approaching(Ball, RightBaseLine) & Partner(A, B) & Partner(B, A)', + goals='Returned(Ball) & At(a, LeftNet) & At(a, RightNet)', + actions=[Action('Hit(actor, Ball, loc)', + precond='Approaching(Ball,loc) & At(actor,loc)', + effect='Returned(Ball)'), + Action('Go(actor, to, loc)', + precond='At(actor, loc)', + effect='At(actor, to) & ~At(actor, loc)')]) class Level: @@ -479,7 +483,7 @@ def extract_solution(self, goals, index): def spare_tire_graphplan(): """Solves the spare tire problem using GraphPlan""" - pddl = spare_tire() + pddl = spare_tire graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -501,7 +505,7 @@ def goal_test(kb, goals): def have_cake_and_eat_cake_too_graphplan(): """Solves the cake problem using GraphPlan""" - pddl = have_cake_and_eat_cake_too() + pddl = have_cake_and_eat_cake_too graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -523,7 +527,7 @@ def goal_test(kb, goals): def three_block_tower_graphplan(): """Solves the Sussman Anomaly problem using GraphPlan""" - pddl = three_block_tower() + pddl = three_block_tower graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -545,7 +549,7 @@ def goal_test(kb, goals): def air_cargo_graphplan(): """Solves the air cargo problem using GraphPlan""" - pddl = air_cargo() + pddl = air_cargo graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -565,7 +569,7 @@ def goal_test(kb, goals): def shopping_graphplan(): - pddl = shopping_problem() + pddl = shopping_problem graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -585,7 +589,7 @@ def goal_test(kb, goals): def socks_and_shoes_graphplan(): - pddl = socks_and_shoes() + pddl = socks_and_shoes graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -616,36 +620,6 @@ def linearize(solution): return linear_solution -def double_tennis_problem(): - init = [expr('At(A, LeftBaseLine)'), - expr('At(B, RightNet)'), - expr('Approaching(Ball, RightBaseLine)'), - expr('Partner(A, B)'), - expr('Partner(B, A)')] - - def goal_test(kb): - required = [expr('Returned(Ball)'), expr('At(a, LeftNet)'), expr('At(a, RightNet)')] - return all(kb.ask(q) is not False for q in required) - - # Actions - - # Hit - precond_pos = [expr("Approaching(Ball,loc)"), expr("At(actor,loc)")] - precond_neg = [] - effect_add = [expr("Returned(Ball)")] - effect_rem = [] - hit = Action(expr("Hit(actor, Ball, loc)"), [precond_pos, precond_neg], [effect_add, effect_rem]) - - # Go - precond_pos = [expr("At(actor, loc)")] - precond_neg = [] - effect_add = [expr("At(actor, to)")] - effect_rem = [expr("At(actor, loc)")] - go = Action(expr("Go(actor, to, loc)"), [precond_pos, precond_neg], [effect_add, effect_rem]) - - return PDDL(init, [hit, go], goal_test) - - class HLA(Action): """ Define Actions for the real-world (that may be refined further), and satisfy resource @@ -661,8 +635,6 @@ def __init__(self, action, precond=None, effect=None, duration=0, consumes holds a dictionary representing the resources the task consumes uses holds a dictionary representing the resources the task uses """ - precond = precond or [None, None] - effect = effect or [None, None] super().__init__(action, precond, effect) self.duration = duration self.consumes = consume or {} @@ -684,10 +656,11 @@ def do_action(self, job_order, available_resources, kb, args): if not self.inorder(job_order): raise Exception("Can't execute {} - execute prerequisite actions first". format(self.name)) - super().act(kb, args) # update knowledge base + kb = super().act(kb, args) # update knowledge base for resource in self.consumes: # remove consumed resources available_resources[resource] -= self.consumes[resource] self.completed = True # set the task status to complete + return kb def has_consumable_resource(self, available_resources): """ @@ -734,8 +707,8 @@ class Problem(PDDL): This class is identical to PDLL, except that it overloads the act function to handle resource and ordering conditions imposed by HLA as opposed to Action. """ - def __init__(self, initial_state, actions, goal_test, jobs=None, resources=None): - super().__init__(initial_state, actions, goal_test) + def __init__(self, init, goals, actions, jobs=None, resources=None): + super().__init__(init, goals, actions) self.jobs = jobs self.resources = resources or {} @@ -752,63 +725,38 @@ def act(self, action): list_action = first(a for a in self.actions if a.name == action.name) if list_action is None: raise Exception("Action '{}' not found".format(action.name)) - list_action.do_action(self.jobs, self.resources, self.kb, args) + 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 ... """ state is a Problem, containing the current state kb library is a dictionary containing details for every possible refinement. eg: { - "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)"], - [], # empty refinements ie primitive action - [], - [] - ], - "precond_pos": [ - ["At(Home), Have(Car)"], - ["At(Home)"], - ["At(Home)", "Have(Car)"] - ["At(SFOLongTermParking)"] - ["At(Home)"] - ], - "precond_neg": [[],[],[],[],[]], - "effect_pos": [ - ["At(SFO)"], - ["At(SFO)"], - ["At(SFOLongTermParking)"], - ["At(SFO)"], - ["At(SFO)"] - ], - "effect_neg": [ - ["At(Home)"], - ["At(Home)"], - ["At(Home)"], - ["At(SFOLongTermParking)"], - ["At(Home)"] - ] + '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)'], [], [], []], + # empty refinements ie primitive action + '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)']] } """ e = Expr(hla.name, hla.args) - indices = [i for i, x in enumerate(library["HLA"]) if expr(x).op == hla.name] + indices = [i for i, x in enumerate(library['HLA']) if expr(x).op == hla.name] for i in indices: - action = HLA(expr(library["steps"][i][0]), [ # TODO multiple refinements - [expr(x) for x in library["precond_pos"][i]], - [expr(x) for x in library["precond_neg"][i]] - ], - [ - [expr(x) for x in library["effect_pos"][i]], - [expr(x) for x in library["effect_neg"][i]] - ]) - if action.check_precond(state.kb, action.args): + # TODO multiple refinements + 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][0], precond, effect) + if action.check_precond(state.init, action.args): yield action def hierarchical_search(problem, hierarchy): @@ -850,92 +798,23 @@ def result(problem, action): def job_shop_problem(): - """ - [figure 11.1] JOB-SHOP-PROBLEM - - A job-shop scheduling problem for assembling two cars, - with resource and ordering constraints. - - Example: - """ - init = [expr('Car(C1)'), - expr('Car(C2)'), - expr('Wheels(W1)'), - expr('Wheels(W2)'), - expr('Engine(E2)'), - expr('Engine(E2)')] - - def goal_test(kb): - # print(kb.clauses) - required = [expr('Has(C1, W1)'), expr('Has(C1, E1)'), expr('Inspected(C1)'), - expr('Has(C2, W2)'), expr('Has(C2, E2)'), expr('Inspected(C2)')] - for q in required: - # print(q) - # print(kb.ask(q)) - if kb.ask(q) is False: - return False - return True resources = {'EngineHoists': 1, 'WheelStations': 2, 'Inspectors': 2, 'LugNuts': 500} - # AddEngine1 - precond_pos = [] - precond_neg = [expr("Has(C1,E1)")] - effect_add = [expr("Has(C1,E1)")] - effect_rem = [] - add_engine1 = HLA(expr("AddEngine1"), - [precond_pos, precond_neg], [effect_add, effect_rem], - duration=30, use={'EngineHoists': 1}) - - # AddEngine2 - precond_pos = [] - precond_neg = [expr("Has(C2,E2)")] - effect_add = [expr("Has(C2,E2)")] - effect_rem = [] - add_engine2 = HLA(expr("AddEngine2"), - [precond_pos, precond_neg], [effect_add, effect_rem], - duration=60, use={'EngineHoists': 1}) - - # AddWheels1 - precond_pos = [] - precond_neg = [expr("Has(C1,W1)")] - effect_add = [expr("Has(C1,W1)")] - effect_rem = [] - add_wheels1 = HLA(expr("AddWheels1"), - [precond_pos, precond_neg], [effect_add, effect_rem], - duration=30, consume={'LugNuts': 20}, use={'WheelStations': 1}) - - # AddWheels2 - precond_pos = [] - precond_neg = [expr("Has(C2,W2)")] - effect_add = [expr("Has(C2,W2)")] - effect_rem = [] - add_wheels2 = HLA(expr("AddWheels2"), - [precond_pos, precond_neg], [effect_add, effect_rem], - duration=15, consume={'LugNuts': 20}, use={'WheelStations': 1}) - - # Inspect1 - precond_pos = [] - precond_neg = [expr("Inspected(C1)")] - effect_add = [expr("Inspected(C1)")] - effect_rem = [] - inspect1 = HLA(expr("Inspect1"), - [precond_pos, precond_neg], [effect_add, effect_rem], - duration=10, use={'Inspectors': 1}) - - # Inspect2 - precond_pos = [] - precond_neg = [expr("Inspected(C2)")] - effect_add = [expr("Inspected(C2)")] - effect_rem = [] - inspect2 = HLA(expr("Inspect2"), - [precond_pos, precond_neg], [effect_add, effect_rem], - duration=10, use={'Inspectors': 1}) + add_engine1 = HLA('AddEngine1', precond='~Has(C1, E1)', effect='Has(C1, E1)', duration=30, use={'EngineHoists': 1}), + add_engine2 = HLA('AddEngine2', precond='~Has(C2, E2)', effect='Has(C2, E2)', duration=60, use={'EngineHoists': 1}), + add_wheels1 = HLA('AddWheels1', precond='~Has(C1, W1)', effect='Has(C1, W1)', duration=30, use={'WheelStations': 1}, consume={'LugNuts': 20}), + add_wheels2 = HLA('AddWheels2', precond='~Has(C2, W2)', effect='Has(C2, W2)', duration=15, use={'WheelStations': 1}, consume={'LugNuts': 20}), + inspect1 = HLA('Inspect1', precond='~Inspected(C1)', effect='Inspected(C1)', duration=10, use={'Inspectors': 1}), + inspect2 = HLA('Inspect2', precond='~Inspected(C2)', effect='Inspected(C2)', duration=10, use={'Inspectors': 1}) + + actions = [add_engine1, add_engine2, add_wheels1, add_wheels2, inspect1, inspect2] job_group1 = [add_engine1, add_wheels1, inspect1] job_group2 = [add_engine2, add_wheels2, inspect2] - return Problem(init, [add_engine1, add_engine2, add_wheels1, add_wheels2, inspect1, inspect2], - goal_test, [job_group1, job_group2], resources) - - + return Problem(init='Car(C1) & Car(C2) & Wheels(W1) & Wheels(W2) & Engine(E2) & Engine(E2) & ~Has(C1, E1) & ~Has(C2, E2) & ~Has(C1, W1) & ~Has(C2, W2) & ~Inspected(C1) & ~Inspected(C2)', + goals='Has(C1, W1) & Has(C1, E1) & Inspected(C1) & Has(C2, W2) & Has(C2, E2) & Inspected(C2)', + actions=actions, + jobs=[job_group1, job_group2], + resources=resources) From 27dec404ad41527c5e73a216ff97b78f162fb158 Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Fri, 18 May 2018 01:17:06 +0530 Subject: [PATCH 2/9] Refactors --- planning.py | 192 ++++++++++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 88 deletions(-) diff --git a/planning.py b/planning.py index 72b51ac76..ff8ebc3a2 100644 --- a/planning.py +++ b/planning.py @@ -147,86 +147,100 @@ def act(self, kb, args): return kb -# Air cargo problem -air_cargo = PDDL(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)', - goals='At(C1, JFK) & At(C2, SFO)', - actions=[Action('Load(c, p, a)', - precond='At(c, a) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)', - effect='In(c, p) & ~At(c, a)'), - Action('Unload(c, p, a)', - precond='In(c, p) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)', - effect='At(c, a) & ~In(c, p)'), - Action('Fly(p, f, to)', - precond='At(p, f) & Plane(p) & Airport(f) & Airport(to)', - effect='At(p, to) & ~At(p, f)')]) - - -# Spare tire problem -spare_tire = PDDL(init='Tire(Flat) & Tire(Spare) & At(Flat, Axle) & At(Spare, Trunk)', - goals='At(Spare, Axle) & At(Flat, Ground)', - actions=[Action('Remove(obj, loc)', - precond='At(obj, loc)', - effect='At(obj, Ground) & ~At(obj, loc)'), - Action('PutOn(t, Axle)', - precond='Tire(t) & At(t, Ground) & ~At(Flat, Axle)', - effect='At(t, Axle) & ~At(t, Ground)'), - Action('LeaveOvernight', - precond='', - effect='~At(Spare, Ground) & ~At(Spare, Axle) & ~At(Spare, Trunk) & ~At(Flat, Ground) & ~At(Flat, Axle) & ~At(Flat, Trunk)')]) - - -# Sussman Anomaly problem -three_block_tower = PDDL(init='On(A, Table) & On(B, Table) & On(C, A) & Block(A) & Block(B) & Block(C) & Clear(B) & Clear(C)', - goals='On(A, B) & On(B, C)', - actions=[Action('Move(b, x, y)', - precond='On(b, x) & Clear(b) & Clear(y) & Block(b) & Block(y)', - effect='On(b, y) & Clear(x) & ~On(b, x) & ~Clear(y)'), - Action('MoveToTable(b, x)', - precond='On(b, x) & Clear(b) & Block(b)', - effect='On(b, Table) & Clear(x) & ~On(b, x)')]) - - -# Cake problem -have_cake_and_eat_cake_too = PDDL(init='Have(Cake)', - goals='Have(Cake) & Eaten(Cake)', - actions=[Action('Eat(Cake)', - precond='Have(Cake)', - effect='Eaten(Cake) & ~Have(Cake)'), - Action('Bake(Cake)', - precond='~Have(Cake)', - effect='Have(Cake)')]) - - -# Shopping problem -shopping_problem = PDDL(init='At(Home) & Sells(SM, Milk) & Sells(SM, Banana) & Sells(HW, Drill)', - goals='Have(Milk) & Have(Banana) & Have(Drill)', - actions=[Action('Buy(x, store)', - precond='At(store) & Sells(store, x)', - effect='Have(x)'), - Action('Go(x, y)', - precond='At(x)', - effect='At(y) & ~At(x)')]) - - -# Socks and shoes problem -socks_and_shoes = PDDL(init='', - goals='RightShoeOn & LeftShoeOn', - actions=[Action('RightShoe', - precond='RightSockOn', - effect='RightShoeOn'), - Action('RightSock', - precond='', - effect='RightSockOn'), - Action('LeftShoe', - precond='LeftSockOn', - effect='LeftShoeOn'), - Action('LeftSock', - precond='', - effect='LeftSockOn')]) +def air_cargo(): + """Air cargo problem""" + + return PDDL(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)', + goals='At(C1, JFK) & At(C2, SFO)', + actions=[Action('Load(c, p, a)', + precond='At(c, a) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)', + effect='In(c, p) & ~At(c, a)'), + Action('Unload(c, p, a)', + precond='In(c, p) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)', + effect='At(c, a) & ~In(c, p)'), + Action('Fly(p, f, to)', + precond='At(p, f) & Plane(p) & Airport(f) & Airport(to)', + effect='At(p, to) & ~At(p, f)')]) + + +def spare_tire(): + """Spare tire problem""" + + return PDDL(init='Tire(Flat) & Tire(Spare) & At(Flat, Axle) & At(Spare, Trunk)', + goals='At(Spare, Axle) & At(Flat, Ground)', + actions=[Action('Remove(obj, loc)', + precond='At(obj, loc)', + effect='At(obj, Ground) & ~At(obj, loc)'), + Action('PutOn(t, Axle)', + precond='Tire(t) & At(t, Ground) & ~At(Flat, Axle)', + effect='At(t, Axle) & ~At(t, Ground)'), + Action('LeaveOvernight', + precond='', + effect='~At(Spare, Ground) & ~At(Spare, Axle) & ~At(Spare, Trunk) & \ + ~At(Flat, Ground) & ~At(Flat, Axle) & ~At(Flat, Trunk)')]) + + +def three_block_tower(): + """Sussman Anomaly problem""" + + return PDDL(init='On(A, Table) & On(B, Table) & On(C, A) & Block(A) & Block(B) & Block(C) & Clear(B) & Clear(C)', + goals='On(A, B) & On(B, C)', + actions=[Action('Move(b, x, y)', + precond='On(b, x) & Clear(b) & Clear(y) & Block(b) & Block(y)', + effect='On(b, y) & Clear(x) & ~On(b, x) & ~Clear(y)'), + Action('MoveToTable(b, x)', + precond='On(b, x) & Clear(b) & Block(b)', + effect='On(b, Table) & Clear(x) & ~On(b, x)')]) + + +def have_cake_and_eat_cake_too(): + """Cake problem""" + + return PDDL(init='Have(Cake)', + goals='Have(Cake) & Eaten(Cake)', + actions=[Action('Eat(Cake)', + precond='Have(Cake)', + effect='Eaten(Cake) & ~Have(Cake)'), + Action('Bake(Cake)', + precond='~Have(Cake)', + effect='Have(Cake)')]) + + +def shopping_problem(): + """Shopping problem""" + + return PDDL(init='At(Home) & Sells(SM, Milk) & Sells(SM, Banana) & Sells(HW, Drill)', + goals='Have(Milk) & Have(Banana) & Have(Drill)', + actions=[Action('Buy(x, store)', + precond='At(store) & Sells(store, x)', + effect='Have(x)'), + Action('Go(x, y)', + precond='At(x)', + effect='At(y) & ~At(x)')]) + + +def socks_and_shoes(): + """Socks and shoes problem""" + + return PDDL(init='', + goals='RightShoeOn & LeftShoeOn', + actions=[Action('RightShoe', + precond='RightSockOn', + effect='RightShoeOn'), + Action('RightSock', + precond='', + effect='RightSockOn'), + Action('LeftShoe', + precond='LeftSockOn', + effect='LeftShoeOn'), + Action('LeftSock', + precond='', + effect='LeftSockOn')]) # Doubles tennis problem -double_tennis_problem = PDDL(init='At(A, LeftBaseLine) & At(B, RightNet) & Approaching(Ball, RightBaseLine) & Partner(A, B) & Partner(B, A)', +def double_tennis_problem(): + return PDDL(init='At(A, LeftBaseLine) & At(B, RightNet) & Approaching(Ball, RightBaseLine) & Partner(A, B) & Partner(B, A)', goals='Returned(Ball) & At(a, LeftNet) & At(a, RightNet)', actions=[Action('Hit(actor, Ball, loc)', precond='Approaching(Ball,loc) & At(actor,loc)', @@ -483,7 +497,7 @@ def extract_solution(self, goals, index): def spare_tire_graphplan(): """Solves the spare tire problem using GraphPlan""" - pddl = spare_tire + pddl = spare_tire() graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -505,7 +519,7 @@ def goal_test(kb, goals): def have_cake_and_eat_cake_too_graphplan(): """Solves the cake problem using GraphPlan""" - pddl = have_cake_and_eat_cake_too + pddl = have_cake_and_eat_cake_too() graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -527,7 +541,7 @@ def goal_test(kb, goals): def three_block_tower_graphplan(): """Solves the Sussman Anomaly problem using GraphPlan""" - pddl = three_block_tower + pddl = three_block_tower() graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -549,7 +563,7 @@ def goal_test(kb, goals): def air_cargo_graphplan(): """Solves the air cargo problem using GraphPlan""" - pddl = air_cargo + pddl = air_cargo() graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -569,7 +583,7 @@ def goal_test(kb, goals): def shopping_graphplan(): - pddl = shopping_problem + pddl = shopping_problem() graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -589,7 +603,7 @@ def goal_test(kb, goals): def socks_and_shoes_graphplan(): - pddl = socks_and_shoes + pddl = socks_and_shoes() graphplan = GraphPlan(pddl) def goal_test(kb, goals): @@ -635,6 +649,8 @@ def __init__(self, action, precond=None, effect=None, duration=0, consumes holds a dictionary representing the resources the task consumes uses holds a dictionary representing the resources the task uses """ + precond = precond or [None] + effect = effect or [None] super().__init__(action, precond, effect) self.duration = duration self.consumes = consume or {} @@ -801,11 +817,11 @@ def job_shop_problem(): resources = {'EngineHoists': 1, 'WheelStations': 2, 'Inspectors': 2, 'LugNuts': 500} - add_engine1 = HLA('AddEngine1', precond='~Has(C1, E1)', effect='Has(C1, E1)', duration=30, use={'EngineHoists': 1}), - add_engine2 = HLA('AddEngine2', precond='~Has(C2, E2)', effect='Has(C2, E2)', duration=60, use={'EngineHoists': 1}), - add_wheels1 = HLA('AddWheels1', precond='~Has(C1, W1)', effect='Has(C1, W1)', duration=30, use={'WheelStations': 1}, consume={'LugNuts': 20}), - add_wheels2 = HLA('AddWheels2', precond='~Has(C2, W2)', effect='Has(C2, W2)', duration=15, use={'WheelStations': 1}, consume={'LugNuts': 20}), - inspect1 = HLA('Inspect1', precond='~Inspected(C1)', effect='Inspected(C1)', duration=10, use={'Inspectors': 1}), + add_engine1 = HLA('AddEngine1', precond='~Has(C1, E1)', effect='Has(C1, E1)', duration=30, use={'EngineHoists': 1}) + add_engine2 = HLA('AddEngine2', precond='~Has(C2, E2)', effect='Has(C2, E2)', duration=60, use={'EngineHoists': 1}) + add_wheels1 = HLA('AddWheels1', precond='~Has(C1, W1)', effect='Has(C1, W1)', duration=30, use={'WheelStations': 1}, consume={'LugNuts': 20}) + add_wheels2 = HLA('AddWheels2', precond='~Has(C2, W2)', effect='Has(C2, W2)', duration=15, use={'WheelStations': 1}, consume={'LugNuts': 20}) + inspect1 = HLA('Inspect1', precond='~Inspected(C1)', effect='Inspected(C1)', duration=10, use={'Inspectors': 1}) inspect2 = HLA('Inspect2', precond='~Inspected(C2)', effect='Inspected(C2)', duration=10, use={'Inspectors': 1}) actions = [add_engine1, add_engine2, add_wheels1, add_wheels2, inspect1, inspect2] From 5c7eb08eaf6351d352f39530a818ce74ff0446fa Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Fri, 18 May 2018 01:17:34 +0530 Subject: [PATCH 3/9] Refactored broken tests --- tests/test_planning.py | 78 ++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/tests/test_planning.py b/tests/test_planning.py index 375c4e26a..7f873a178 100644 --- a/tests/test_planning.py +++ b/tests/test_planning.py @@ -147,12 +147,6 @@ def test_graphplan(): assert expr('Unload(C1, P1, JFK)') in air_cargo_solution assert expr('Unload(C2, P2, SFO)') in air_cargo_solution - sussman_anomaly_solution = three_block_tower_graphplan() - sussman_anomaly_solution = linearize(sussman_anomaly_solution) - assert expr('MoveToTable(C, A)') in sussman_anomaly_solution - assert expr('Move(B, Table, C)') in sussman_anomaly_solution - assert expr('Move(A, Table, B)') in sussman_anomaly_solution - shopping_problem_solution = shopping_graphplan() shopping_problem_solution = linearize(shopping_problem_solution) assert expr('Go(Home, HW)') in shopping_problem_solution @@ -163,7 +157,7 @@ def test_graphplan(): # def test_double_tennis(): -# p = double_tennis_problem() +# p = double_tennis_problem # assert p.goal_test() is False # solution = [expr("Go(A, RightBaseLine, LeftBaseLine)"), @@ -176,50 +170,36 @@ def test_graphplan(): # assert p.goal_test() -# def test_job_shop_problem(): -# p = job_shop_problem() -# assert p.goal_test() is False +def test_job_shop_problem(): + p = job_shop_problem() + assert p.goal_test() is False -# solution = [p.jobs[1][0], -# p.jobs[0][0], -# p.jobs[0][1], -# p.jobs[0][2], -# p.jobs[1][1], -# p.jobs[1][2]] + solution = [p.jobs[1][0], + p.jobs[0][0], + p.jobs[0][1], + p.jobs[0][2], + p.jobs[1][1], + p.jobs[1][2]] -# for action in solution: -# p.act(action) + for action in solution: + p.act(action) -# assert p.goal_test() + assert p.goal_test() + + +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)']]} + + 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)') + prob = Problem('At(Home)', 'At(SFO)', [go_SFO, taxi_SFO]) -# def test_refinements(): -# init = [expr('At(Home)')] -# def goal_test(kb): -# return kb.ask(expr('At(SFO)')) - -# library = {"HLA": ["Go(Home,SFO)","Taxi(Home, SFO)"], -# "steps": [["Taxi(Home, SFO)"],[]], -# "precond_pos": [["At(Home)"],["At(Home)"]], -# "precond_neg": [[],[]], -# "effect_pos": [["At(SFO)"],["At(SFO)"]], -# "effect_neg": [["At(Home)"],["At(Home)"],]} -# # Go SFO -# precond_pos = [expr("At(Home)")] -# precond_neg = [] -# effect_add = [expr("At(SFO)")] -# effect_rem = [expr("At(Home)")] -# go_SFO = HLA(expr("Go(Home,SFO)"), -# [precond_pos, precond_neg], [effect_add, effect_rem]) -# # Taxi SFO -# precond_pos = [expr("At(Home)")] -# precond_neg = [] -# effect_add = [expr("At(SFO)")] -# effect_rem = [expr("At(Home)")] -# taxi_SFO = HLA(expr("Go(Home,SFO)"), -# [precond_pos, precond_neg], [effect_add, effect_rem]) -# prob = Problem(init, [go_SFO, taxi_SFO], goal_test) -# 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"))) + 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'))) From d87c66f5e6fca2b727df5aac796e4350a79e733b Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Fri, 18 May 2018 20:49:53 +0530 Subject: [PATCH 4/9] Cleaned up duplicated code --- planning.py | 150 ++++++++++++++++------------------------------------ 1 file changed, 45 insertions(+), 105 deletions(-) diff --git a/planning.py b/planning.py index ff8ebc3a2..2a966f061 100644 --- a/planning.py +++ b/planning.py @@ -493,133 +493,51 @@ def extract_solution(self, goals, index): return solution + def goal_test(self, kb): + return all(kb.ask(q) is not False for q in self.graph.pddl.goals) -def spare_tire_graphplan(): - """Solves the spare tire problem using GraphPlan""" - - pddl = spare_tire() - graphplan = GraphPlan(pddl) + def execute(self): + """Executes the GraphPlan algorithm for the given problem""" - def goal_test(kb, goals): - return all(kb.ask(q) is not False for q in goals) + while True: + self.graph.expand_graph() + if (self.goal_test(self.graph.levels[-1].kb) and self.graph.non_mutex_goals(self.graph.pddl.goals, -1)): + solution = self.extract_solution(self.graph.pddl.goals, -1) + if solution: + return solution + + if len(self.graph.levels) >= 2 and self.check_leveloff(): + return None - goals = expr('At(Spare, Axle), At(Flat, Ground)') - while True: - graphplan.graph.expand_graph() - if (goal_test(graphplan.graph.levels[-1].kb, goals) and graphplan.graph.non_mutex_goals(goals, -1)): - solution = graphplan.extract_solution(goals, -1) - if solution: - return solution - - if len(graphplan.graph.levels) >= 2 and graphplan.check_leveloff(): - return None +def spare_tire_graphplan(): + """Solves the spare tire problem using GraphPlan""" + return GraphPlan(spare_tire()).execute() def have_cake_and_eat_cake_too_graphplan(): """Solves the cake problem using GraphPlan""" - - pddl = have_cake_and_eat_cake_too() - graphplan = GraphPlan(pddl) - - def goal_test(kb, goals): - return all(kb.ask(q) is not False for q in goals) - - goals = expr('Have(Cake), Eaten(Cake)') - - while True: - graphplan.graph.expand_graph() - if (goal_test(graphplan.graph.levels[-1].kb, goals) and graphplan.graph.non_mutex_goals(goals, -1)): - solution = graphplan.extract_solution(goals, -1) - if solution: - return [solution[1]] - - if len(graphplan.graph.levels) >= 2 and graphplan.check_leveloff(): - return None + return GraphPlan(have_cake_and_eat_cake_too()).execute()[1] def three_block_tower_graphplan(): """Solves the Sussman Anomaly problem using GraphPlan""" - - pddl = three_block_tower() - graphplan = GraphPlan(pddl) - - def goal_test(kb, goals): - return all(kb.ask(q) is not False for q in goals) - - goals = expr('On(A, B), On(B, C)') - - while True: - if (goal_test(graphplan.graph.levels[-1].kb, goals) and graphplan.graph.non_mutex_goals(goals, -1)): - solution = graphplan.extract_solution(goals, -1) - if solution: - return solution - - graphplan.graph.expand_graph() - if len(graphplan.graph.levels) >= 2 and graphplan.check_leveloff(): - return None + return GraphPlan(three_block_tower()).execute() def air_cargo_graphplan(): """Solves the air cargo problem using GraphPlan""" - - pddl = air_cargo() - graphplan = GraphPlan(pddl) - - def goal_test(kb, goals): - return all(kb.ask(q) is not False for q in goals) - - goals = expr('At(C1, JFK), At(C2, SFO)') - - while True: - if (goal_test(graphplan.graph.levels[-1].kb, goals) and graphplan.graph.non_mutex_goals(goals, -1)): - solution = graphplan.extract_solution(goals, -1) - if solution: - return solution - - graphplan.graph.expand_graph() - if len(graphplan.graph.levels) >= 2 and graphplan.check_leveloff(): - return None + return GraphPlan(air_cargo()).execute() def shopping_graphplan(): - pddl = shopping_problem() - graphplan = GraphPlan(pddl) - - def goal_test(kb, goals): - return all(kb.ask(q) is not False for q in goals) - - goals = expr('Have(Milk), Have(Banana), Have(Drill)') - - while True: - if (goal_test(graphplan.graph.levels[-1].kb, goals) and graphplan.graph.non_mutex_goals(goals, -1)): - solution = graphplan.extract_solution(goals, -1) - if solution: - return solution - - graphplan.graph.expand_graph() - if len(graphplan.graph.levels) >= 2 and graphplan.check_leveloff(): - return None + """Solves the shopping problem using GraphPlan""" + return GraphPlan(shopping_problem()).execute() def socks_and_shoes_graphplan(): - pddl = socks_and_shoes() - graphplan = GraphPlan(pddl) - - def goal_test(kb, goals): - return all(kb.ask(q) is not False for q in goals) - - goals = expr('RightShoeOn, LeftShoeOn') - - while True: - if (goal_test(graphplan.graph.levels[-1].kb, goals) and graphplan.graph.non_mutex_goals(goals, -1)): - solution = graphplan.extract_solution(goals, -1) - if solution: - return solution - - graphplan.graph.expand_graph() - if len(graphplan.graph.levels) >= 2 and graphplan.check_leveloff(): - return None + """Solves the socks and shoes problem using GraphpPlan""" + return GraphPlan(socks_and_shoes()).execute() def linearize(solution): @@ -814,7 +732,29 @@ def result(problem, action): def job_shop_problem(): + """ + [figure 11.1] JOB-SHOP-PROBLEM + + A job-shop scheduling problem for assembling two cars, + with resource and ordering constraints. + Example: + >>> from planning import * + >>> p = job_shop_problem() + >>> p.goal_test() + False + >>> p.act(p.jobs[1][0]) + >>> p.act(p.jobs[1][1]) + >>> p.act(p.jobs[1][2]) + >>> p.act(p.jobs[0][0]) + >>> p.act(p.jobs[0][1]) + >>> p.goal_test() + False + >>> p.act(p.jobs[0][2]) + >>> p.goal_test() + True + >>> + """ resources = {'EngineHoists': 1, 'WheelStations': 2, 'Inspectors': 2, 'LugNuts': 500} add_engine1 = HLA('AddEngine1', precond='~Has(C1, E1)', effect='Has(C1, E1)', duration=30, use={'EngineHoists': 1}) From e93d8d7ac3291f86020c45dbf0a77118267da627 Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Fri, 18 May 2018 20:53:15 +0530 Subject: [PATCH 5/9] Cleaned up duplicated code --- planning.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/planning.py b/planning.py index 2a966f061..ad5623ece 100644 --- a/planning.py +++ b/planning.py @@ -514,27 +514,22 @@ def spare_tire_graphplan(): """Solves the spare tire problem using GraphPlan""" return GraphPlan(spare_tire()).execute() - -def have_cake_and_eat_cake_too_graphplan(): - """Solves the cake problem using GraphPlan""" - return GraphPlan(have_cake_and_eat_cake_too()).execute()[1] - - def three_block_tower_graphplan(): """Solves the Sussman Anomaly problem using GraphPlan""" return GraphPlan(three_block_tower()).execute() - def air_cargo_graphplan(): """Solves the air cargo problem using GraphPlan""" return GraphPlan(air_cargo()).execute() +def have_cake_and_eat_cake_too_graphplan(): + """Solves the cake problem using GraphPlan""" + return [GraphPlan(have_cake_and_eat_cake_too()).execute()[1]] def shopping_graphplan(): """Solves the shopping problem using GraphPlan""" return GraphPlan(shopping_problem()).execute() - def socks_and_shoes_graphplan(): """Solves the socks and shoes problem using GraphpPlan""" return GraphPlan(socks_and_shoes()).execute() From 12664c21d2aa8dfae7fd593f716ad71e9663d744 Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Sat, 19 May 2018 12:45:16 +0530 Subject: [PATCH 6/9] Added TotalOrderPlanner --- planning.py | 63 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/planning.py b/planning.py index ad5623ece..312202ad7 100644 --- a/planning.py +++ b/planning.py @@ -1,6 +1,7 @@ """Planning (Chapters 10-11) """ +import copy import itertools from search import Node from utils import Expr, expr, first @@ -510,6 +511,56 @@ def execute(self): return None +class TotalOrderPlanner: + + def __init__(self, pddl): + self.pddl = pddl + + def filter(self, solution): + """Filter out persistence actions from a solution""" + + new_solution = [] + for section in solution[0]: + new_section = [] + for operation in section: + if not (operation.op[0] == 'P' and operation.op[1].isupper()): + new_section.append(operation) + new_solution.append(new_section) + return new_solution + + def orderlevel(self, level, pddl): + """Return valid linear order of actions for a given level""" + + for permutation in itertools.permutations(level): + temp = copy.deepcopy(pddl) + count = 0 + for action in permutation: + try: + temp.act(action) + count += 1 + except: + count = 0 + temp = copy.deepcopy(pddl) + break + if count == len(permutation): + return list(permutation), temp + return None + + def execute(self): + """Finds total-order solution for a planning graph""" + + graphplan_solution = GraphPlan(self.pddl).execute() + filtered_solution = self.filter(graphplan_solution) + ordered_solution = [] + pddl = self.pddl + for level in filtered_solution: + level_solution, pddl = self.orderlevel(level, pddl) + for element in level_solution: + ordered_solution.append(element) + + return ordered_solution + + def spare_tire_graphplan(): """Solves the spare tire problem using GraphPlan""" return GraphPlan(spare_tire()).execute() @@ -535,18 +586,6 @@ def socks_and_shoes_graphplan(): return GraphPlan(socks_and_shoes()).execute() -def linearize(solution): - """Converts a level-ordered solution into a linear solution""" - - linear_solution = [] - for section in solution[0]: - for operation in section: - if not (operation.op[0] == 'P' and operation.op[1].isupper()): - linear_solution.append(operation) - - return linear_solution - - class HLA(Action): """ Define Actions for the real-world (that may be refined further), and satisfy resource From c9fcc31aeff774540c5415a97664d1f347fed5f6 Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Sat, 19 May 2018 12:52:56 +0530 Subject: [PATCH 7/9] Linearize helper function --- planning.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/planning.py b/planning.py index 312202ad7..b5e35dae4 100644 --- a/planning.py +++ b/planning.py @@ -561,6 +561,18 @@ def execute(self): return ordered_solution +def linearize(solution): + """Converts a level-ordered solution into a linear solution""" + + linear_solution = [] + for section in solution[0]: + for operation in section: + if not (operation.op[0] == 'P' and operation.op[1].isupper()): + linear_solution.append(operation) + + return linear_solution + + def spare_tire_graphplan(): """Solves the spare tire problem using GraphPlan""" return GraphPlan(spare_tire()).execute() From 50d87d2e6d199b90247ac0d6e74cbd673ac8821e Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Sat, 19 May 2018 13:07:36 +0530 Subject: [PATCH 8/9] Added tests for TotalOrderPlanner --- tests/test_planning.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_planning.py b/tests/test_planning.py index 7f873a178..aa4016df2 100644 --- a/tests/test_planning.py +++ b/tests/test_planning.py @@ -156,6 +156,39 @@ def test_graphplan(): assert expr('Buy(Milk, SM)') in shopping_problem_solution +def test_total_order_planner(): + st = spare_tire() + possible_solutions = [[expr('Remove(Spare, Trunk)'), expr('Remove(Flat, Axle)'), expr('PutOn(Spare, Axle)')], + [expr('Remove(Flat, Axle)'), expr('Remove(Spare, Trunk)'), expr('PutOn(Spare, Axle)')]] + assert TotalOrderPlanner(st).execute() in possible_solutions + + ac = air_cargo() + possible_solutions = [[expr('Load(C1, P1, SFO)'), expr('Load(C2, P2, JFK)'), expr('Fly(P1, SFO, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Unload(C1, P1, JFK)'), expr('Unload(C2, P2, SFO)')], + [expr('Load(C1, P1, SFO)'), expr('Load(C2, P2, JFK)'), expr('Fly(P1, SFO, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Unload(C2, P2, SFO)'), expr('Unload(C1, P1, JFK)')], + [expr('Load(C1, P1, SFO)'), expr('Load(C2, P2, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Unload(C1, P1, JFK)'), expr('Unload(C2, P2, SFO)')], + [expr('Load(C1, P1, SFO)'), expr('Load(C2, P2, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Unload(C2, P2, SFO)'), expr('Unload(C1, P1, JFK)')], + [expr('Load(C2, P2, JFK)'), expr('Load(C1, P1, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Unload(C1, P1, JFK)'), expr('Unload(C2, P2, SFO)')], + [expr('Load(C2, P2, JFK)'), expr('Load(C1, P1, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Unload(C2, P2, SFO)'), expr('Unload(C1, P1, JFK)')], + [expr('Load(C2, P2, JFK)'), expr('Load(C1, P1, SFO)'), expr('Fly(P2, JFK, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Unload(C1, P1, JFK)'), expr('Unload(C2, P2, SFO)')], + [expr('Load(C2, P2, JFK)'), expr('Load(C1, P1, SFO)'), expr('Fly(P2, JFK, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Unload(C2, P2, SFO)'), expr('Unload(C1, P1, JFK)')], + [expr('Load(C1, P1, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Load(C2, P2, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Unload(C1, P1, JFK)'), expr('Unload(C2, P2, SFO)')], + [expr('Load(C1, P1, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Load(C2, P2, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Unload(C2, P2, SFO)'), expr('Unload(C1, P1, JFK)')], + [expr('Load(C2, P2, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Load(C1, P1, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Unload(C1, P1, JFK)'), expr('Unload(C2, P2, SFO)')], + [expr('Load(C2, P2, JFK)'), expr('Fly(P2, JFK, SFO)'), expr('Load(C1, P1, SFO)'), expr('Fly(P1, SFO, JFK)'), expr('Unload(C2, P2, SFO)'), expr('Unload(C1, P1, JFK)')] + ] + assert TotalOrderPlanner(ac).execute() in possible_solutions + + ss = socks_and_shoes() + possible_solutions = [[expr('LeftSock'), expr('RightSock'), expr('LeftShoe'), expr('RightShoe')], + [expr('LeftSock'), expr('RightSock'), expr('RightShoe'), expr('LeftShoe')], + [expr('RightSock'), expr('LeftSock'), expr('LeftShoe'), expr('RightShoe')], + [expr('RightSock'), expr('LeftSock'), expr('RightShoe'), expr('LeftShoe')], + [expr('LeftSock'), expr('LeftShoe'), expr('RightSock'), expr('RightShoe')], + [expr('RightSock'), expr('RightShoe'), expr('LeftSock'), expr('LeftShoe')] + ] + assert TotalOrderPlanner(ss).execute() in possible_solutions + + # def test_double_tennis(): # p = double_tennis_problem # assert p.goal_test() is False From ccc36157443deb9370aefc8e8dd3fd695f58324d Mon Sep 17 00:00:00 2001 From: AngryCracker Date: Sat, 19 May 2018 13:15:30 +0530 Subject: [PATCH 9/9] Readd sussman anomaly test --- tests/test_planning.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_planning.py b/tests/test_planning.py index aa4016df2..641a2eeca 100644 --- a/tests/test_planning.py +++ b/tests/test_planning.py @@ -147,6 +147,12 @@ def test_graphplan(): assert expr('Unload(C1, P1, JFK)') in air_cargo_solution assert expr('Unload(C2, P2, SFO)') in air_cargo_solution + sussman_anomaly_solution = three_block_tower_graphplan() + sussman_anomaly_solution = linearize(sussman_anomaly_solution) + assert expr('MoveToTable(C, A)') in sussman_anomaly_solution + assert expr('Move(B, Table, C)') in sussman_anomaly_solution + assert expr('Move(A, Table, B)') in sussman_anomaly_solution + shopping_problem_solution = shopping_graphplan() shopping_problem_solution = linearize(shopping_problem_solution) assert expr('Go(Home, HW)') in shopping_problem_solution