From ba8d6a352eb635f8561c276cd9a91e4ffddc2f0d Mon Sep 17 00:00:00 2001 From: Kaivalya Rawal Date: Sun, 16 Apr 2017 16:56:50 +0530 Subject: [PATCH 1/4] define HLA, Problem and implement 11.1 --- planning.py | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/planning.py b/planning.py index 30b8a79f6..e69c9280e 100644 --- a/planning.py +++ b/planning.py @@ -574,3 +574,227 @@ def goal_test(kb): go = Action(expr("Go(actor, to)"), [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 + constraints. + """ + unique_group = 1 + + def __init__(self, action, precond=[None, None], effect=[None, None], duration=0, + consume={}, use={}): + """ + As opposed to actions, to define HLA, we have added constraints. + duration holds the amount of time required to execute the task + consumes holds a dictionary representing the resources the task consumes + uses holds a dictionary representing the resources the task uses + """ + super().__init__(action, precond, effect) + self.duration = duration + self.consumes = consume + self.uses = use + self.completed = False + # self.priority = -1 # must be assigned in relation to other HLAs + # self.job_group = -1 # must be assigned in relation to other HLAs + + def do_action(self, job_order, available_resources, kb, args): + """ + An HLA based version of act - along with knowledge base updation, it handles + resource checks, and ensures the actions are executed in the correct order. + """ + # print(self.name) + if not self.has_usable_resource(available_resources): + raise Exception('Not enough usable resources to execute {}'.format(self.name)) + if not self.has_consumable_resource(available_resources): + raise Exception('Not enough consumable resources to execute {}'.format(self.name)) + 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 + for resource in self.consumes: # remove consumed resources + available_resources[resource] -= self.consumes[resource] + self.completed = True # set the task status to complete + + def has_consumable_resource(self, available_resources): + """ + Ensure there are enough consumable resources for this action to execute. + """ + for resource in self.consumes: + if available_resources.get(resource) is None: + return False + if available_resources[resource] < self.consumes[resource]: + return False + return True + + def has_usable_resource(self, available_resources): + """ + Ensure there are enough usable resources for this action to execute. + """ + for resource in self.uses: + if available_resources.get(resource) is None: + return False + if available_resources[resource] < self.uses[resource]: + return False + return True + + def inorder(self, job_order): + """ + Ensure that all the jobs that had to be executed before the current one have been + successfully executed. + """ + for jobs in job_order: + if self in jobs: + for job in jobs: + if job is self: + return True + if not job.completed: + return False + return True + + def refine(self, precond, library): # TODO + raise NotImplementedError + + +def refinements(hla, outcome, hierarchy): + return hla.refine(outcome, hierarchy) + +def result(problem, action): + return problem.act(action) + +class Problem(PDDL): + """ + Define real-world problems by aggregating resources as numerical quantities instead of + named entities. + + 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={}): + super().__init__(initial_state, actions, goal_test) + self.jobs = jobs + self.resources = resources + + def act(self, action): + """ + Performs the HLA given as argument. + + Note that this is different from the superclass action - where the parameter was an + Expression. For real world problems, an Expr object isn't enough to capture all the + detail required for executing the action - resources, preconditions, etc need to be + checked for too. + """ + args = action.args + 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) + # print(self.resources) + + def subseq(hla): + return (None,None) + +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 + >>> + """ + 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}) + + 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) From e17fd43875d2505403b88e6f4bdbec5e735063ec Mon Sep 17 00:00:00 2001 From: Kaivalya Rawal Date: Sun, 16 Apr 2017 16:57:15 +0530 Subject: [PATCH 2/4] add demonstration of job_shop_problem --- tests/test_planning.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_planning.py b/tests/test_planning.py index e13bcfd92..2388de336 100644 --- a/tests/test_planning.py +++ b/tests/test_planning.py @@ -81,3 +81,20 @@ def test_graph_call(): graph() assert levels_size == len(graph.levels) - 1 + + +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]] + + for action in solution: + p.act(action) + + assert p.goal_test() From 9f9936f77d14e13264a11466024626fa437b6df3 Mon Sep 17 00:00:00 2001 From: Kaivalya Rawal Date: Mon, 17 Apr 2017 02:36:25 +0530 Subject: [PATCH 3/4] implementing 11.5 --- planning.py | 105 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 11 deletions(-) diff --git a/planning.py b/planning.py index e69c9280e..e665cc06f 100644 --- a/planning.py +++ b/planning.py @@ -2,6 +2,7 @@ """ import itertools +from search import Node from utils import Expr, expr, first from logic import FolKB @@ -653,15 +654,56 @@ def inorder(self, job_order): return False return True - def refine(self, precond, library): # TODO - raise NotImplementedError - - -def refinements(hla, outcome, hierarchy): - return hla.refine(outcome, hierarchy) - -def result(problem, action): - return problem.act(action) + def refine(self, 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)"] + ] + } + """ + e = Expr(self.name, self.args) + indices = [i for i,x in enumerate(library["HLA"]) if expr(x) == e] + for i in indices: + action = HLA(expr(library["steps"][i]), [s["precond_pos"][i],s["precond_neg"][i]], + [s["effect_pos"][i],s["effect_neg"][i]]) + if action.check_precond(state.kb, action.args): + yield action class Problem(PDDL): """ @@ -692,8 +734,49 @@ def act(self, action): list_action.do_action(self.jobs, self.resources, self.kb, args) # print(self.resources) - def subseq(hla): - return (None,None) + def hierarchical_search(problem, hierarchy): + act = Node(problem.initial_state) + frontier = FIFOQueue() + frontier.append(act) + while(True): + if not frontier: #(len(frontier)==0): + return None + plan = frontier.pop() + hla = plan.state #first_or_null(plan) + prefix = plan.parent.state #prefix, suffix = subseq(plan.state, hla) + outcome = result(problem, prefix) + if hla is None: + if outcome.goal_test(): + return plan.path() + else: + for sequence in refinements(hla, outcome, hierarchy): + frontier.append(Node(plan.state, plan.parent, sequence)) + + def refinements(hla, outcome, hierarchy): + return hla.refine(outcome, hierarchy) + + def result(problem, action): + if action is not None: + problem.act(action) + return problem + else: + return problem + + def first_or_null(plan): + l = [x for x in plan.state if x is not None] + if len(l) > 0: + return l[0] + else: + return None + + def subseq(plan, hla): + index = plan.index(hla) + result = (plan[index-1], plan[index+1]) + if index == 0: + result = (None, result[1]) + if index == len(plan)-1: + result = (result[0], None) + return result def job_shop_problem(): """ From 1d3b0f690612625bd0bfad0d73c2b59543ebe7da Mon Sep 17 00:00:00 2001 From: Kaivalya Rawal Date: Mon, 17 Apr 2017 04:39:22 +0530 Subject: [PATCH 4/4] adding test for refinement --- planning.py | 117 +++++++++++++++++++++-------------------- tests/test_planning.py | 31 +++++++++++ 2 files changed, 91 insertions(+), 57 deletions(-) diff --git a/planning.py b/planning.py index e665cc06f..edfb39f19 100644 --- a/planning.py +++ b/planning.py @@ -3,7 +3,7 @@ import itertools from search import Node -from utils import Expr, expr, first +from utils import Expr, expr, first, FIFOQueue from logic import FolKB @@ -653,8 +653,38 @@ def inorder(self, job_order): if not job.completed: return False return True + + +class Problem(PDDL): + """ + Define real-world problems by aggregating resources as numerical quantities instead of + named entities. + + 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={}): + super().__init__(initial_state, actions, goal_test) + self.jobs = jobs + self.resources = resources + + def act(self, action): + """ + Performs the HLA given as argument. + + Note that this is different from the superclass action - where the parameter was an + Expression. For real world problems, an Expr object isn't enough to capture all the + detail required for executing the action - resources, preconditions, etc need to be + checked for too. + """ + args = action.args + 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) + # print(self.resources) - def refine(self, state, library): # TODO - refinements may be (multiple) HLA themselves ... + 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: @@ -697,86 +727,58 @@ def refine(self, state, library): # TODO - refinements may be (multiple) HLA the ] } """ - e = Expr(self.name, self.args) - indices = [i for i,x in enumerate(library["HLA"]) if expr(x) == e] + 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: - action = HLA(expr(library["steps"][i]), [s["precond_pos"][i],s["precond_neg"][i]], - [s["effect_pos"][i],s["effect_neg"][i]]) + 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): yield action - -class Problem(PDDL): - """ - Define real-world problems by aggregating resources as numerical quantities instead of - named entities. - - 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={}): - super().__init__(initial_state, actions, goal_test) - self.jobs = jobs - self.resources = resources - - def act(self, action): + + def hierarchical_search(problem, hierarchy): """ - Performs the HLA given as argument. - - Note that this is different from the superclass action - where the parameter was an - Expression. For real world problems, an Expr object isn't enough to capture all the - detail required for executing the action - resources, preconditions, etc need to be - checked for too. + [Figure 11.5] 'Hierarchical Search, a Breadth First Search implementation of Hierarchical + Forward Planning Search' + + The problem is a real-world prodlem defined by the problem class, and the hierarchy is + a dictionary of HLA - refinements (see refinements generator for details) """ - args = action.args - 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) - # print(self.resources) - - def hierarchical_search(problem, hierarchy): - act = Node(problem.initial_state) + act = Node(problem.actions[0]) frontier = FIFOQueue() frontier.append(act) while(True): if not frontier: #(len(frontier)==0): return None plan = frontier.pop() + print(plan.state.name) hla = plan.state #first_or_null(plan) - prefix = plan.parent.state #prefix, suffix = subseq(plan.state, hla) - outcome = result(problem, prefix) + prefix = None + if plan.parent: + prefix = plan.parent.state.action #prefix, suffix = subseq(plan.state, hla) + outcome = Problem.result(problem, prefix) if hla is None: if outcome.goal_test(): return plan.path() else: - for sequence in refinements(hla, outcome, hierarchy): + print("else") + for sequence in Problem.refinements(hla, outcome, hierarchy): + print("...") frontier.append(Node(plan.state, plan.parent, sequence)) - def refinements(hla, outcome, hierarchy): - return hla.refine(outcome, hierarchy) - def result(problem, action): + """The outcome of applying an action to the current problem""" if action is not None: problem.act(action) return problem else: return problem - - def first_or_null(plan): - l = [x for x in plan.state if x is not None] - if len(l) > 0: - return l[0] - else: - return None - def subseq(plan, hla): - index = plan.index(hla) - result = (plan[index-1], plan[index+1]) - if index == 0: - result = (None, result[1]) - if index == len(plan)-1: - result = (result[0], None) - return result def job_shop_problem(): """ @@ -881,3 +883,4 @@ def goal_test(kb): return Problem(init, [add_engine1, add_engine2, add_wheels1, add_wheels2, inspect1, inspect2], goal_test, [job_group1, job_group2], resources) + diff --git a/tests/test_planning.py b/tests/test_planning.py index 2388de336..0e57ffca6 100644 --- a/tests/test_planning.py +++ b/tests/test_planning.py @@ -98,3 +98,34 @@ def test_job_shop_problem(): p.act(action) assert p.goal_test() + +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"))) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy