Пример #1
0
    def __init__(self,
                 ID=None,
                 type_graph=None,
                 name=None,
                 Elements=None,
                 plan_elm=None,
                 Edges=None,
                 Restrictions=None):

        if ID is None:
            ID = uuid4()
        if type_graph is None:
            type_graph = 'PlanElementGraph'
        if Elements is None:
            Elements = set()
        if Edges is None:
            Edges = set()
        if Restrictions is None:
            Restrictions = set()

        self.OrderingGraph = OrderingGraph()
        self.CausalLinkGraph = CausalLinkGraph()

        self.flaws = FlawLib()
        self.solved = False
        self.initial_dummy_step = None
        self.final_dummy_step = None

        if plan_elm is None:
            plan_elm = Element(ID=ID, typ=type_graph, name=name)

        super(PlanElementGraph, self).__init__(ID, type_graph, name, Elements,
                                               plan_elm, Edges, Restrictions)
Пример #2
0
	def __init__(self, dummy_init_constructor, dummy_goal_constructor):
		self.ID = uuid4()
		self.OrderingGraph = OrderingGraph()
		self.CausalLinkGraph = CausalLinkGraph()
		# self.HierarchyGraph = HierarchyGraph()
		self.flaws = FlawLib()
		self.solved = False
		self.dummy = dummyTuple(dummy_init_constructor.instantiate(), dummy_goal_constructor.instantiate())

		self.init = self.dummy.init.preconds
		self.goal = self.dummy.final.preconds
		self.steps = [self.dummy.init, self.dummy.final]

		# check if any existing steps are choices (instances of cndts of open conditions)
		self.dummy.final.update_choices(self)

		self.cndt_map = None
		self.threat_map = None
		# self.gstep_lib = ground_step_list

		# self.h_step_dict = dict()

		self.heuristic = float('inf')
		self.name = ''
		self.cost = 0
		self.depth = 0
Пример #3
0
	def __init__(self, operator, args, preconditions, effects, stepnum, height):

		# READ-ONLY ATTRIBUTES #
		# schema refers to the name of the operator
		self.schema = operator
		# Args are Argument or Actor "Element" types
		self.Args = args
		# ID used as "instance ID"
		self.ID = uuid4()
		# preconds is a list of GCond
		self.preconds = preconditions
		self.effects = effects
		# stepnum is the ground step constructor type
		self.stepnum = stepnum
		self.stepnumber = stepnum
		# height is 0 when primitive
		self.height = height

		if height > 0:
			self.sub_steps = []
			self.sub_orderings = OrderingGraph()
			self.sub_links = CausalLinkGraph()
			self.dummy = dummyTuple(None, None)

		# depth starts at 0 and takes on value during planning
		self.depth = 0

		self.cndts = None
		self.cndt_map = None
		self.threat_map = None
		self.threats = None
		self.cntg_mental = None

		self.instantiable = True

		# INSTANCE ATTRIBUTES #
		# risks are number of threat instances
		self.risks = list()
		self.choices = list()
		# choices are instances of cndt antecedents
		self.choice_map = dict()
		# self.num_choices = 0
		# open preconditions which need causal link
		self.open_preconds = list(self.preconds)
Пример #4
0
	def swap_substeps(self, gsteps, GL, decomp_step):
		# base case - sub-steps are all height = 0
		primitive_substeps = [arg for arg in decomp_step.ground_subplan.elements
		                      if type(arg) == Operator and arg.height == 0]
		composite_substeps = [arg for arg in decomp_step.ground_subplan.elements
		                      if type(arg) == Operator and arg.height > 0]

		if len(composite_substeps) == 0:
			prim_dict = {step: gsteps[step.stepnumber].instantiate() for step in primitive_substeps}
			self.create_composite_gstep(gsteps, decomp_step, prim_dict)
			return prim_dict
		else:
			# links and orderings in intermediate stage
			# change_dict = {step.root: gsteps[step.stepnumber].instantiate() for step in decomp_step.ground_subplan.Root_Graphs}

			change_dict = {}
			# order steps by height, lowest to highest.
			step_list = [step for step in decomp_step.ground_subplan.Step_Graphs]
			step_list.sort(key=lambda x: x.height)
			do_not_add_as_substep = []
			for step in step_list:

				Args = [decompile(arg, decomp_step.ground_subplan) for arg in step.Args]
				preconds = [GLiteral(p.name, [decompile(arg, p) for arg in p.Args],
				                     p.truth, p.replaced_ID, (p.name, p.truth) not in GL.non_static_preds)
				            for p in step.Preconditions]
				effects = [GLiteral(e.name, [decompile(arg, e) for arg in e.Args],
				                    e.truth, e.replaced_ID, (e.name, e.truth) not in GL.non_static_preds)
				           for e in step.Effects]
				schema = str(step)
				step_copy = GStep(schema, Args, preconds, effects, step.stepnumber, step.height)
				step_copy.ID = step.root.ID
				st_t = gsteps[step.stepnumber].instantiate()
				step_copy.swap_setup(st_t.cndts, st_t.cndt_map, st_t.threats, st_t.threat_map, st_t.cntg_mental)

				# give no children
				if step.height > 0:
					init_step = st_t.dummy[0]
					init_step.schema = "begin:" + str(step)
					final_step = st_t.dummy[1]
					final_step.schema = "finish:" + str(step)
					step_copy.dummy = dummyTuple(init_step, final_step)

					# step_copy.sub_steps = []
					children = decomp_step.ground_subplan.DecompGraph.getNeighbors(step.root)
					step_copy.sub_steps = [change_dict[child] for child in children if child.typ != 'step-s']
					do_not_add_as_substep.extend(step_copy.sub_steps)

					step_copy.sub_orderings = OrderingGraph()
					step_copy.sub_links = CausalLinkGraph()

				change_dict[step.root] = step_copy
				# self.sub_steps.append(step)
			self.create_composite_gstep(gsteps, decomp_step, change_dict, do_not_add_as_substep)
			return change_dict
Пример #5
0
    def Actions_2_Plan(cls, Actions, h):
        # Used by Plannify

        if not checkHeight(Actions, h):
            return None

        elements = set().union(*[A.elements for A in Actions])
        edges = set().union(*[A.edges for A in Actions])
        Plan = cls(name='Action_2_Plan', Elements=elements, Edges=edges)
        for edge in Plan.edges:
            if edge.label == 'effect-of':
                elm = Plan.getElementById(edge.sink.ID)
                elm.replaced_ID = edge.sink.replaced_ID

        Plan.OrderingGraph = OrderingGraph()
        Plan.CausalLinkGraph = CausalLinkGraph()
        # Plan.Steps = [A.root for A in Actions]
        return Plan
Пример #6
0
class PlanElementGraph(ElementGraph):
    def __init__(self,
                 ID=None,
                 type_graph=None,
                 name=None,
                 Elements=None,
                 plan_elm=None,
                 Edges=None,
                 Restrictions=None):

        if ID is None:
            ID = uuid4()
        if type_graph is None:
            type_graph = 'PlanElementGraph'
        if Elements is None:
            Elements = set()
        if Edges is None:
            Edges = set()
        if Restrictions is None:
            Restrictions = set()

        self.OrderingGraph = OrderingGraph()
        self.CausalLinkGraph = CausalLinkGraph()

        self.flaws = FlawLib()
        self.solved = False
        self.initial_dummy_step = None
        self.final_dummy_step = None

        if plan_elm is None:
            plan_elm = Element(ID=ID, typ=type_graph, name=name)

        super(PlanElementGraph, self).__init__(ID, type_graph, name, Elements,
                                               plan_elm, Edges, Restrictions)

    def __hash__(self):
        return hash(self.name) ^ hash(self.typ) ^ hash(self.ID)

    @classmethod
    def Actions_2_Plan(cls, Actions, h):
        # Used by Plannify

        if not checkHeight(Actions, h):
            return None

        elements = set().union(*[A.elements for A in Actions])
        edges = set().union(*[A.edges for A in Actions])
        Plan = cls(name='Action_2_Plan', Elements=elements, Edges=edges)
        for edge in Plan.edges:
            if edge.label == 'effect-of':
                elm = Plan.getElementById(edge.sink.ID)
                elm.replaced_ID = edge.sink.replaced_ID

        Plan.OrderingGraph = OrderingGraph()
        Plan.CausalLinkGraph = CausalLinkGraph()
        # Plan.Steps = [A.root for A in Actions]
        return Plan

    def UnifyActions(self, P, G):
        # Used by Plannify

        NG = G.deepcopy(replace_internals=True)
        for edge in list(NG.edges):

            if edge.sink.replaced_ID == -1:
                sink = copy.deepcopy(edge.sink)
                sink.replaced_ID = edge.sink.ID
                self.elements.add(sink)
            else:
                sink = P.getElmByRID(edge.sink.replaced_ID)
                if sink is None:
                    sink = copy.deepcopy(edge.sink)
                    self.elements.add(sink)

            source = P.getElmByRID(edge.source.replaced_ID)
            if source is None:
                source = copy.deepcopy(edge.source)
                self.elements.add(source)

            self.edges.add(Edge(source, sink, edge.label))

    def deepcopy(self):
        new_self = copy.deepcopy(self)
        new_self.ID = uuid4()
        return new_self

    def RemoveSubgraph(self, literal):
        edges = list(self.edges)
        elm = self.getElementById(literal.ID)
        link = None
        self.elements.remove(elm)

        for edge in list(self.edges):
            if edge.source == elm:
                edges.remove(edge)
            if link is None:
                if edge.sink == elm:
                    link = edge
        edges.remove(link)
        self.edges = set(edges)
        return link

    def ReplaceSubgraphs(self, literal_old, literal_new):
        edges = list(self.edges)
        elm = self.getElementById(literal_old.ID)
        link = None
        self.elements.remove(elm)

        for edge in list(self.edges):
            if edge.source == elm:
                edges.remove(edge)
            if link is None:
                if edge.sink == elm:
                    link = edge
        edges.remove(link)
        link.sink = literal_new
        self.elements.add(literal_new)
        self.edges = set(edges)
        self.edges.add(link)
        return link

    def AddSubgraph(self, subgraph):
        self.elements.update(subgraph.elements)
        self.edges.update(subgraph.edges)

    def isInternallyConsistent(self):
        return self.OrderingGraph.isInternallyConsistent() and self.CausalLinkGraph.isInternallyConsistent() and \
            super(PlanElementGraph, self).isInternallyConsistent()

    @property
    def Steps(self):
        return [
            element for element in self.elements if type(element) is Operator
        ]

    @property
    def Step_Graphs(self):
        return [Action.subgraph(self, step) for step in self.Steps]

    @property
    def Steps_Sorted(self):
        pass

    def detectTCLFperCL(self, GL, causal_link):
        detectedThreatenedCausalLinks = set()
        for step in self.Steps:
            self.testThreat(GL, self.CausalLinkGraph.nonThreats, causal_link,
                            step, detectedThreatenedCausalLinks)
        return detectedThreatenedCausalLinks

    def detectTCLFperStep(self, GL, step):
        detectedThreatenedCausalLinks = set()
        for causal_link in self.CausalLinkGraph.edges:
            self.testThreat(GL, self.CausalLinkGraph.nonThreats, causal_link,
                            step, detectedThreatenedCausalLinks)
        return detectedThreatenedCausalLinks

    def testThreat(self, GL, nonThreats, causal_link, step, dTCLFs):
        if step in nonThreats[causal_link]:
            return
        if step == causal_link.source or step == causal_link.sink:
            nonThreats[causal_link].add(step)
            return
        if self.OrderingGraph.isPath(causal_link.sink, step):
            nonThreats[causal_link].add(step)
            return
        if self.OrderingGraph.isPath(step, causal_link.source):
            nonThreats[causal_link].add(step)
            return
        if step.stepnumber not in GL.threat_dict[causal_link.sink.stepnumber]:
            nonThreats[causal_link].add(step)
            return
        if test(Action.subgraph(self, step), causal_link):
            dTCLFs.add(TCLF((step, causal_link), 'tclf'))
        nonThreats[causal_link].add(step)

    #@clock
    def detectThreatenedCausalLinks(self, GL):
        detectedThreatenedCausalLinks = set()
        for causal_link in self.CausalLinkGraph.edges:
            for step in self.Steps:
                self.testThreat(GL, self.CausalLinkGraph.nonThreats,
                                causal_link, step,
                                detectedThreatenedCausalLinks)
        return detectedThreatenedCausalLinks

    def __repr__(self):
        c = '\ncost {} + heuristic {}'.format(self.cost, self.heuristic)
        steps = [''.join('\t' + str(step) + '\n' for step in self.Step_Graphs)]
        order = [
            ''.join('\t' + str(ordering.source) + ' < ' + str(ordering.sink) +
                    '\n' for ordering in self.OrderingGraph.edges)
        ]
        links = [
            ''.join('\t' + str(cl) + '\n' for cl in self.CausalLinkGraph.edges)
        ]
        return 'PLAN: ' + str(self.ID) + c + '\n*Steps: \n' + ''.join(['{}'.format(step) for step in steps]) + \
            '*Orderings:\n' + \
            ''.join(['{}'.format(o) for o in order]) + '*CausalLinks:\n' + ''.join(['{}'.format(link) for link in links]) + '}'
Пример #7
0
class GPlan:

	def __init__(self, dummy_init_constructor, dummy_goal_constructor):
		self.ID = uuid4()
		self.OrderingGraph = OrderingGraph()
		self.CausalLinkGraph = CausalLinkGraph()
		# self.HierarchyGraph = HierarchyGraph()
		self.flaws = FlawLib()
		self.solved = False
		self.dummy = dummyTuple(dummy_init_constructor.instantiate(), dummy_goal_constructor.instantiate())

		self.init = self.dummy.init.preconds
		self.goal = self.dummy.final.preconds
		self.steps = [self.dummy.init, self.dummy.final]

		# check if any existing steps are choices (instances of cndts of open conditions)
		self.dummy.final.update_choices(self)

		self.cndt_map = None
		self.threat_map = None
		# self.gstep_lib = ground_step_list

		# self.h_step_dict = dict()

		self.heuristic = float('inf')
		self.name = ''
		self.cost = 0
		self.depth = 0

	def __len__(self):
		return len(self.steps)

	def __getitem__(self, pos):
		return self.steps[pos]

	def __setitem__(self, item, pos):
		self.steps[pos] = item

	def index(self, step):
		for i, s in enumerate(self.steps):
			if s.ID == step.ID:
				return i
		print('{} {} {}'.format(self.name, step, step.ID))
		for i, s in enumerate(self.steps):
			print('{} {} {}'.format(i, s, s.ID))
		raise ValueError('{} with ID={} not found in plan {}'.format(step, step.ID, self.name))

	def instantiate(self, add_to_name):
		new_self = copy.deepcopy(self)
		new_self.ID = uuid4()
		new_self.name += add_to_name
		# refresh attributes
		return new_self

	# @property
	# def cost(self):
	# 	return len(self.steps) - 2

	def isInternallyConsistent(self):
		return self.OrderingGraph.isInternallyConsistent() and self.CausalLinkGraph.isInternallyConsistent()

	# Insert Methods #

	def insert(self, step, dni=None):
		# baseline condition:
		self.cost += 1
		# self.cost += (2 * 2 + 1) - (step.height * step.height)
		if step.height > 0:
			return self.insert_decomp(step, dni)
		else:
			return self.insert_primitive(step)


	def insert_primitive(self, new_step):
		self.steps.append(new_step)

		# global orderings
		self.OrderingGraph.addEdge(self.dummy.init, new_step)
		self.OrderingGraph.addEdge(new_step, self.dummy.final)

		# add open conditions for new step
		for pre in new_step.open_preconds:
			self.flaws.insert(self, OPF(new_step, pre))

		# check for causal link threats
		for edge in self.CausalLinkGraph.edges:
			# source, sink, condition = edge
			if edge.source.ID == new_step.ID:
				continue
			if edge.sink.ID == new_step.ID:
				continue
			if self.OrderingGraph.isPath(new_step, edge.source):
				continue
			if self.OrderingGraph.isPath(edge.sink, new_step):
				continue
			if new_step.stepnum in edge.sink.threat_map[edge.label.ID]:
				self.flaws.insert(self, TCLF(new_step, edge))

		return None

	def insert_decomp(self, new_step, dni=None):
		# magic happens here
		swap_dict = dict()

		# sub dummy init
		d_i = new_step.dummy.init.instantiate()
		d_i.depth = new_step.depth
		swap_dict[new_step.dummy.init.ID] = d_i
		self.steps.append(d_i)
		# add flaws for each new_step precondition, but make s_need d_i and update cndt_map/ threat_map
		d_i.swap_setup(new_step.cndts, new_step.cndt_map, new_step.threats, new_step.threat_map, new_step.cntg_mental)
		for pre in new_step.open_preconds:
			self.flaws.insert(self, OPF(d_i, pre, new_step.height))
		preconds = list(new_step.open_preconds)
		d_i.preconds = preconds
		d_i.open_preconds = preconds

		self.OrderingGraph.addEdge(self.dummy.init, d_i)
		self.OrderingGraph.addEdge(d_i, self.dummy.final)


		# sub dummy final
		d_f = new_step.dummy.final.instantiate(default_None_is_to_refresh_open_preconds=False)
		d_f.depth = new_step.depth
		swap_dict[new_step.dummy.final.ID] = d_f
		# d_f will be primitive, to allow any heighted applicable steps
		self.insert(d_f)

		# added this 2017-08-09
		self.OrderingGraph.addEdge(d_i, d_f)
		self.OrderingGraph.addEdge(d_f, self.dummy.final)
		self.OrderingGraph.addEdge(self.dummy.init, d_f)

		# decomposition links
		# self.HierarchyGraph.addOrdering(new_step, d_i)
		# self.HierarchyGraph.addOrdering(new_step, d_f)
		# for sb_step in new_step.sub_steps:
		# 	self.HierarchyGraph.addOrdering(new_step, sb_step)

		# log who your family is
		new_step.dummy = dummyTuple(d_i, d_f)
		d_i.sibling = d_f
		d_f.sibling = d_i

		# sub steps
		for substep in new_step.sub_steps:
			new_substep = substep.instantiate(default_None_is_to_refresh_open_preconds=False)
			swap_dict[substep.ID] = new_substep

			# INCREMENT DEPTH
			new_substep.depth = new_step.depth + 1
			if new_substep.depth > self.depth:
				self.depth = new_substep.depth

			if dni is not None:
				if substep in dni:
					continue

			poss_swaps = self.insert(new_substep)

			if poss_swaps is not None:
				swap_dict.update(poss_swaps)

			# if your substeps have children, make those children fit between your init and
			if new_substep.height > 0:
				self.OrderingGraph.addEdge(new_substep.dummy.final, d_f)
				self.OrderingGraph.addEdge(d_i, new_substep.dummy.init)
			else:
				self.OrderingGraph.addEdge(new_substep, d_f)
				self.OrderingGraph.addEdge(d_i, new_substep)

		# sub orderings
		for edge in new_step.sub_orderings.edges:
			if dni is not None:
				if edge.source in dni:
					continue
				elif edge.sink in dni:
					continue
			# try:
			source, sink = swap_dict[edge.source.ID], swap_dict[edge.sink.ID]
			# except:
			# 	pass
			if source.height > 0:
				source = source.dummy.final
			if sink.height > 0:
				sink = sink.dummy.init
			self.OrderingGraph.addLabeledEdge(source, sink, edge.label)

		# sub links
		for edge in new_step.sub_links.edges:
			# instantiating a GLiteral does not give it new ID (just returns deep copy)
			source, sink, label = swap_dict[edge.source.ID], swap_dict[edge.sink.ID], edge.label.instantiate()
			if source.height > 0:
				source = source.dummy.final
			if sink.height > 0:
				sink = sink.dummy.init

			clink = self.CausalLinkGraph.addEdge(source, sink, label)

			# check if this link is threatened
			for substep in new_step.sub_steps:
				if dni is not None and substep in dni:
					continue

				new_substep = swap_dict[substep.ID]
				if new_substep.ID in {clink.source.ID, clink.sink.ID}:
					continue
				if new_substep.stepnum not in clink.sink.threat_map[clink.label.ID]:
					continue
				if new_substep.height > 0:
					# decomp step compared to its dummy init and dummy final steps
					if self.OrderingGraph.isPath(new_substep.dummy.final, clink.source):
						continue
					if self.OrderingGraph.isPath(clink.sink, new_substep.dummy.init):
						continue
					self.flaws.insert(self, TCLF(new_substep.dummy.final, clink))
				else:
					# primitive step gets the primitive treatment
					if self.OrderingGraph.isPath(new_substep, clink.source):
						continue
					if self.OrderingGraph.isPath(clink.sink, new_substep):
							continue
					self.flaws.insert(self, TCLF(new_substep, clink))

		return swap_dict
		# print('check')

	# Resolve Methods #

	def resolve(self, new_step, s_need, p):
		if new_step.height > 0:
			self.resolve_with_decomp(new_step, s_need, p)
		else:
			self.resolve_with_primitive(new_step, s_need, p)

	def resolve_with_primitive(self, new_step, mutable_s_need, mutable_p):

		# operate on cloned plan
		mutable_s_need.fulfill(mutable_p)

		# add orderings
		self.OrderingGraph.addEdge(new_step, mutable_s_need)
		# add causal link
		c_link = self.CausalLinkGraph.addEdge(new_step, mutable_s_need, mutable_p)
		if mutable_p.ID in mutable_s_need.cntg_mental.keys() and new_step.stepnum in mutable_s_need.cntg_mental[mutable_p.ID]:
			self.OrderingGraph.addCntg(new_step, mutable_s_need)

		mutable_s_need.update_choices(self)

		# check if this link is threatened
		ignore_these = {mutable_s_need.ID, new_step.ID}
		# ignore_these = {mutable_s_need.stepnum, new_step.stepnum}
		for step in self.steps:
			if step.ID in ignore_these:
				continue
			if step.stepnum not in mutable_s_need.threat_map[mutable_p.ID]:
				continue
			if self.OrderingGraph.isPath(mutable_s_need, step):
				continue
			# only for reuse case, otherwise this check is superfluous
			if self.OrderingGraph.isPath(step, new_step):
				continue
			self.flaws.insert(self, TCLF(step, c_link))

		# # check if adding this step threatens other causal links
		# for cl in self.CausalLinkGraph.edges:
		# 	if cl == c_link:
		# 		continue
		# 	if new_step.stepnum not in cl.sink.threat_map[cl.label.ID]:
		# 		continue
		# 	if self.OrderingGraph.isPath(new_step, cl.source):
		# 		continue
		# 	if self.OrderingGraph.isPath(cl.sink, new_step):
		# 		continue
		# 	self.flaws.insert(self, TCLF(new_step, cl))

	def resolve_with_decomp(self, new_step, mutable_s_need, mutable_p):
		d_i, d_f = new_step.dummy

		# operate on cloned plan
		# mutable_s_need = self[s_index]
		# mutable_p = mutable_s_need.preconds[p_index]
		mutable_s_need.fulfill(mutable_p)

		# add ordering
		self.OrderingGraph.addEdge(d_f, mutable_s_need)

		# add causal link
		c_link = self.CausalLinkGraph.addEdge(d_f, mutable_s_need, mutable_p)

		if mutable_p.ID in mutable_s_need.cntg_mental.keys() and d_f.stepnum in mutable_s_need.cntg_mental[mutable_p.ID]:
			self.OrderingGraph.addCntg(new_step, mutable_s_need)

		mutable_s_need.update_choices(self)

		# check if df -> s_need is threatened
		ignore_these = {mutable_s_need.ID, d_f.ID, d_i.ID}
		for step in self.steps:
			# reminder: existing steps are primitive

			if step.ID in ignore_these:
				continue

			### NOT SUFFICIENT: needs to not be a threat to any sub-step added... ###
			if step.stepnum not in mutable_s_need.threat_map[mutable_p.ID]:
				continue
			# check only for d_f, in case this step occurs between d_i and d_f
			if self.OrderingGraph.isPath(step, d_f):
				continue
			if self.OrderingGraph.isPath(mutable_s_need, step):
				continue
			self.flaws.insert(self, TCLF(step, c_link))

		# # check if adding this step threatens other causal links
		# for cl in self.CausalLinkGraph.edges:
		# 	# all causal links are between primitive steps
		# 	if cl == c_link:
		# 		continue
		# 	if new_step.stepnum not in cl.sink.threat_map[cl.label.ID]:
		# 		continue
		# 	if self.OrderingGraph.isPath(d_f, cl.source):
		# 		continue
		# 	if self.OrderingGraph.isPath(cl.sink, d_f):  # LOOK HERE TODO: DECIDE
		# 		continue
		# 	self.flaws.insert(self, TCLF(d_f, cl))

	def __lt__(self, other):
		if self.cost / (1 + math.log2(self.depth+1)) + self.heuristic != other.cost / (1 + math.log2(other.depth+1)) + other.heuristic:
			return self.cost / (1 + math.log2(self.depth+1)) + self.heuristic < other.cost / (1 + math.log2(other.depth+1)) + other.heuristic
		# if self.cost - math.log2(self.depth+1) + self.heuristic != other.cost - math.log2(other.depth+1) + other.heuristic:
		# 	return self.cost - math.log2(self.depth+1) + self.heuristic < other.cost - math.log2(other.depth+1) + other.heuristic
		# if self.cost - self.depth + self.heuristic != other.cost - other.depth + other.heuristic:
		# 	return self.cost - self.depth + self.heuristic < other.cost - other.depth + other.heuristic
		if self.cost + self.heuristic != other.cost + other.heuristic:
			return (self.cost + self.heuristic) < (other.cost + other.heuristic)
		elif self.cost != other.cost:
			return self.cost < other.cost
		elif self.heuristic != other.heuristic:
			return self.heuristic < other.heuristic
		elif len(self.flaws) != len(other.flaws):
			return len(self.flaws) < len(other.flaws)
		elif len(self.CausalLinkGraph.edges) != len(other.CausalLinkGraph.edges):
			return len(self.CausalLinkGraph.edges) > len(other.CausalLinkGraph.edges)
		elif len(self.OrderingGraph.edges) != len(other.OrderingGraph.edges):
			return len(self.OrderingGraph.edges) > len(other.OrderingGraph.edges)
		elif sum([step.stepnum for step in self]) != sum([step.stepnum for step in other]):
			return sum([step.stepnum for step in self]) < sum([step.stepnum for step in other])
		else:
			return self.OrderingGraph < other.OrderingGraph

	def __str__(self):
		return self.name
		# return 'GPlan{} c={} h={}\t'.format(self.ID[-4:], self.cost, self.heuristic) + \
		# 		str(self.steps) + '\n' + str(self.OrderingGraph) + '\n' + str(self.CausalLinkGraph)

	def __repr__(self):
		return self.__str__()
Пример #8
0
class GPlan:
    def __init__(self, dummy_init_constructor, dummy_goal_constructor):
        self.ID = uuid4()
        self.OrderingGraph = OrderingGraph()
        self.CausalLinkGraph = CausalLinkGraph()
        self.flaws = FlawLib()
        self.solved = False
        self.dummy = dummyTuple(dummy_init_constructor.instantiate(),
                                dummy_goal_constructor.instantiate())

        self.init = self.dummy.init.preconds
        self.goal = self.dummy.final.preconds
        self.steps = [self.dummy.init, self.dummy.final]

        # check if any existing steps are choices (instances of cndts of open conditions)
        self.dummy.final.update_choices(self)

        self.cndt_map = None
        self.threat_map = None
        # self.gstep_lib = ground_step_list

        # self.h_step_dict = dict()

        self.heuristic = float('inf')

    def __len__(self):
        return len(self.steps)

    def __getitem__(self, pos):
        return self.steps[pos]

    def __setitem__(self, item, pos):
        self.steps[pos] = item

    def index(self, step):
        return self.steps.index(step)

    def instantiate(self):
        new_self = copy.deepcopy(self)
        new_self.ID = uuid4()
        # refresh attributes
        return new_self

    @property
    def cost(self):
        return len(self.steps) - 2

    def isInternallyConsistent(self):
        return self.OrderingGraph.isInternallyConsistent(
        ) and self.CausalLinkGraph.isInternallyConsistent()

    # Insert Methods #

    def insert(self, step, dummy_dict=None):
        if step.height > 0:
            dummy_dict, sub_steps = self.insert_decomp(step, dummy_dict)
            return dummy_dict, sub_steps
        else:
            self.insert_primitive(step)
        return None, None
        # self.steps.append(step)

    # def insert_decomp(self, new_step, dummy_dict=None):
    # 	# magic happens here
    # 	swap_dict = dict()
    #
    # 	# sub dummy init
    # 	d_i = new_step.sub_dummy.sub_init.instantiate()
    # 	swap_dict[new_step.sub_dummy.sub_init.ID] = d_i
    # 	self.steps.append(d_i)
    #
    # 	# sub dummy final
    # 	d_f = new_step.sub_dummy.sub_final.instantiate(default_None_is_to_refresh_open_preconds=False)
    # 	swap_dict[new_step.sub_dummy.sub_final.ID] = d_f
    # 	self.steps.append(d_f)
    #
    # 	if dummy_dict is None:
    # 		dummy_dict = dict()
    #
    # 	# sub steps (recursively insert... then reuse later for existing links
    # 	for substep in new_step.sub_steps:
    # 		new_substep = substep.instantiate(default_None_is_to_refresh_open_preconds=False)
    # 		swap_dict[substep.ID] = new_substep
    #
    # 		# substep points to dummies of same subplan
    # 		dummy_dict[new_substep] = dummyTuple(d_i, d_f)
    # 		sub_dummy_dict = self.insert(new_substep)
    # 		if sub_dummy_dict is not None:
    # 			dummy_dict.update(sub_dummy_dict)
    #
    # 	# sub orderings
    # 	for edge in new_step.sub_orderings.edges:
    # 		self.OrderingGraph.addEdge(swap_dict[edge.source.ID], swap_dict[edge.sink.ID])
    #
    # 	# sub links
    # 	for edge in new_step.sub_links.edges:
    # 		clink = self.CausalLinkGraph.addEdge(swap_dict[edge.source.ID], swap_dict[edge.sink.ID],
    # 		                                     edge.label.instantiate())
    # 		# check if this link is threatened
    # 		for substep in new_step.sub_steps:
    # 			new_substep = swap_dict[substep.ID]
    # 			if new_substep.ID in {clink.source.ID, clink.sink.ID}:
    # 				continue
    # 			if new_substep.stepnum not in clink.sink.threat_map[clink.label.ID]:
    # 				continue
    # 			if self.OrderingGraph.isPath(new_substep, clink.source):
    # 				continue
    # 			if self.OrderingGraph.isPath(clink.sink, new_substep):
    # 				continue
    # 			self.flaws.insert(self, TCLF(new_substep, clink))
    #
    # 	# global orderings
    # 	self.OrderingGraph.addEdge(self.dummy.init, d_i)
    # 	self.OrderingGraph.addEdge(self.dummy.init, d_f)
    # 	self.OrderingGraph.addEdge(d_i, self.dummy.final)
    # 	self.OrderingGraph.addEdge(d_f, self.dummy.final)
    #
    # 	return dummy_dict

    def insert_primitive(self, new_step):
        self.steps.append(new_step)
        self.OrderingGraph.addEdge(self.dummy.init, new_step)
        self.OrderingGraph.addEdge(new_step, self.dummy.final)
        return None, None, None, new_step

    def resolve(self, new_step, s_index, p_index):
        if new_step.height > 0:
            self.resolve_with_decomp(new_step, s_index, p_index)
        else:
            self.resolve_with_primitive(new_step, s_index, p_index)

    def resolve_with_primitive(self, new_step, s_index, p_index):

        # operate on cloned plan
        mutable_s_need = self[s_index]
        mutable_p = mutable_s_need.preconds[p_index]
        mutable_s_need.fulfill(mutable_p)
        mutable_s_need.update_choices(self)
        # add orderings
        self.OrderingGraph.addEdge(new_step, mutable_s_need)
        # add causal link
        c_link = self.CausalLinkGraph.addEdge(new_step, mutable_s_need,
                                              mutable_p)

        # add open conditions for new step
        for pre in new_step.open_preconds:
            self.flaws.insert(self, OPF(new_step, pre))

        # check if this link is threatened
        ignore_these = {mutable_s_need.ID, new_step.ID}
        for step in self.steps:
            if step.ID in ignore_these:
                continue
            if self.OrderingGraph.isPath(mutable_s_need, step):
                continue
            if step.stepnum in mutable_s_need.threats:
                self.flaws.insert(self, TCLF(step, c_link))

        # check if adding this step threatens other causal links
        for cl in self.CausalLinkGraph.edges:
            if cl == c_link:
                continue
            if new_step.stepnum not in cl.sink.threat_map[cl.label]:
                continue
            if self.OrderingGraph.isPath(new_step, cl.source):
                continue
            if self.OrderingGraph.isPath(cl.sink, new_step):
                continue
            self.flaws.insert(self, TCLF(new_step, cl))

    def resolve_with_decomp(self, new_step, s_index, p_index):
        d_i, d_f = new_step.dummy

        # operate on cloned plan
        mutable_s_need = self[s_index]
        mutable_p = mutable_s_need.preconds[p_index]
        mutable_s_need.fulfill(mutable_p)
        mutable_s_need.update_choices(self)

        # add orderings to rest of plan
        self.OrderingGraph.addEdge(d_f, mutable_s_need)

        # add causal link
        c_link = self.CausalLinkGraph.addEdge(d_f, mutable_s_need, mutable_p)

        # check if df -> s_need is threatened
        ignore_these = {mutable_s_need.ID, d_f.ID, d_i.ID}
        for step in self.steps:
            # existing steps must be primitive
            if step.ID in ignore_these:
                continue
            if self.OrderingGraph.isPath(step, d_f):
                continue
            if self.OrderingGraph.isPath(mutable_s_need, step):
                continue
            if step.stepnum in mutable_s_need.threats:
                self.flaws.insert(self, TCLF(step, c_link))

        # check if adding this step threatens other causal links
        for cl in self.CausalLinkGraph.edges:
            # all causal links are between primitive steps
            if cl == c_link:
                continue
            if new_step.stepnum not in cl.sink.threat_map[cl.label]:
                continue
            if self.OrderingGraph.isPath(d_f, cl.source):
                continue
            if self.OrderingGraph.isPath(cl.sink, d_i):
                continue
            self.flaws.insert(self, DTCLF(d_i, d_f, cl))

    def insert_primitive_0ld(self, new_step, s_index, p_index):
        # append primitive step
        self.steps.append(new_step)

        # operate on cloned plan
        mutable_s_need = self[s_index]
        mutable_p = mutable_s_need.preconds[p_index]
        mutable_s_need.fulfill(mutable_p)
        mutable_s_need.update_choices(self)
        # add orderings
        self.OrderingGraph.addEdge(new_step, mutable_s_need)
        self.OrderingGraph.addEdge(self.dummy.init, new_step)
        self.OrderingGraph.addEdge(new_step, self.dummy.final)
        # add causal link
        c_link = self.CausalLinkGraph.addEdge(new_step, mutable_s_need,
                                              mutable_p)

        # add open conditions for new step
        for pre in new_step.open_preconds:
            self.flaws.insert(self, OPF(new_step, pre))

        # check if this link is threatened
        ignore_these = {mutable_s_need.ID, new_step.ID}
        for step in self.steps:
            if step.ID in ignore_these:
                continue
            if self.OrderingGraph.isPath(mutable_s_need, step):
                continue
            if step.stepnum in mutable_s_need.threats:
                self.flaws.insert(self, TCLF(step, c_link))

        # check if adding this step threatens other causal links
        for cl in self.CausalLinkGraph.edges:
            if cl == c_link:
                continue
            if new_step.stepnum not in cl.sink.threat_map[cl.label]:
                continue
            if self.OrderingGraph.isPath(new_step, cl.source):
                continue
            if self.OrderingGraph.isPath(cl.sink, new_step):
                continue
            self.flaws.insert(self, TCLF(new_step, cl))

    def insert_decomp(self, new_step):
        # magic happens here
        swap_dict = dict()

        # sub dummy init
        d_i = new_step.sub_dummy.sub_init.instantiate()
        swap_dict[new_step.sub_dummy.sub_init.ID] = d_i
        self.steps.append(d_i)

        # add flaws for each new_step precondition, but make s_need d_i and update cndt_map/ threat_map
        for pre in new_step.open_preconds:
            self.flaws.insert(self, OPF(d_i, pre))
        d_i.swap_setup(new_step.cndts, new_step.cndt_map, new_step.threats,
                       new_step.threat_map)

        # sub dummy final
        d_f = new_step.sub_dummy.sub_final.instantiate(
            default_None_is_to_refresh_open_preconds=False)
        swap_dict[new_step.sub_dummy.sub_final.ID] = d_f
        self.steps.append(d_f)

        # add flaws for each d_f pre
        for pre in d_f.open_preconds:
            self.flaws.insert(self, OPF(d_f, pre))

        self.OrderingGraph.addEdge(self.dummy.init, d_i)
        self.OrderingGraph.addEdge(self.dummy.init, d_f)
        self.OrderingGraph.addEdge(d_i, self.dummy.final)
        self.OrderingGraph.addEdge(d_f, self.dummy.final)

        # sub steps
        for substep in new_step.sub_steps:
            new_substep = substep.instantiate(
                default_None_is_to_refresh_open_preconds=False)
            swap_dict[substep.ID] = new_substep
            if new_substep.height > 0:
                # check what links this new_substep is a source of.

                self.insert(new_substep)
            for open_condition in new_substep.open_preconds:
                self.flaws.insert(self, OPF(new_substep, open_condition))

        # sub orderings
        for edge in new_step.sub_orderings.edges:
            source, sink = swap_dict[edge.source.ID], swap_dict[edge.sink.ID]
            if source.height > 0:
                source = source.dummy.final
            if sink.height > 0:
                sink = sink.dummy.init
            self.OrderingGraph.addEdge(source, sink)

        # sub links
        for edge in new_step.sub_links.edges:
            source, sink, label = swap_dict[edge.source.ID], swap_dict[
                edge.sink.ID], edge.label.instantiate()
            if source.height > 0:
                source = source.dummy.final
            if sink.height > 0:
                sink = sink.dummy.init
            clink = self.CausalLinkGraph.addEdge(source, sink, label)

            # check if this link is threatened
            for substep in new_step.sub_steps:
                new_substep = swap_dict[substep.ID]
                if new_substep.ID in {clink.source.ID, clink.sink.ID}:
                    continue
                if new_substep.stepnum not in clink.sink.threat_map[
                        clink.label.ID]:
                    continue
                if new_substep.height > 0:
                    # decomp step compared to its dummy init and dummy final steps
                    if self.OrderingGraph.isPath(new_substep.dummy.final,
                                                 clink.source):
                        continue
                    if self.OrderingGraph.isPath(clink.sink,
                                                 new_substep.dummy.init):
                        continue
                    self.flaws.insert(
                        self,
                        DTCLF(new_substep.dummy.init, new_substep.dummy.final,
                              clink))
                else:
                    # primitive step gets the primitive treatment
                    if self.OrderingGraph.isPath(new_substep, clink.source):
                        continue
                    if self.OrderingGraph.isPath(clink.sink, new_substep):
                        continue
                    self.flaws.insert(self, TCLF(new_substep, clink))

        # # operate on cloned plan
        # mutable_s_need = self[s_index]
        # mutable_p = mutable_s_need.preconds[p_index]
        # mutable_s_need.fulfill(mutable_p)
        # mutable_s_need.update_choices(self)
        #
        # # add orderings to rest of plan
        # self.OrderingGraph.addEdge(d_f, mutable_s_need)
        #
        # # add causal link
        # c_link = self.CausalLinkGraph.addEdge(d_f, mutable_s_need, mutable_p)
        #
        # # check if df -> s_need is threatened
        # ignore_these = {mutable_s_need.ID, d_f.ID, d_i.ID}
        # for step in self.steps:
        # 	# existing steps must be primitive
        # 	if step.ID in ignore_these:
        # 		continue
        # 	if self.OrderingGraph.isPath(step, d_f):
        # 		continue
        # 	if self.OrderingGraph.isPath(mutable_s_need, step):
        # 		continue
        # 	if step.stepnum in mutable_s_need.threats:
        # 		self.flaws.insert(self, TCLF(step, c_link))
        #
        # # check if adding this step threatens other causal links
        # for cl in self.CausalLinkGraph.edges:
        # 	# all causal links are between primitive steps
        # 	if cl == c_link:
        # 		continue
        # 	if new_step.stepnum not in cl.sink.threat_map[cl.label]:
        # 		continue
        # 	if self.OrderingGraph.isPath(d_f, cl.source):
        # 		continue
        # 	if self.OrderingGraph.isPath(cl.sink, d_i):
        # 		continue
        # 	self.flaws.insert(self, DTCLF(d_i, d_f, cl))

    def __lt__(self, other):
        if self.cost + self.heuristic != other.cost + other.heuristic:
            return (self.cost + self.heuristic) < (other.cost +
                                                   other.heuristic)
        elif self.heuristic != other.heuristic:
            return self.heuristic < other.heuristic
        elif self.cost != other.cost:
            return self.cost < other.cost
        elif len(self.flaws) != len(other.flaws):
            return len(self.flaws) < len(other.flaws)
        elif sum([step.stepnum
                  for step in self]) != sum([step.stepnum for step in other]):
            return sum([step.stepnum for step in self]) < sum(
                [step.stepnum for step in other])
        else:
            return self.OrderingGraph < other.OrderingGraph

    def __str__(self):
        return 'GPlan{} c={} h={}\t'.format(self.ID[-4:], self.cost, self.heuristic) + \
          str(self.steps) + '\n' + str(self.OrderingGraph) + '\n' + str(self.CausalLinkGraph)

    def __repr__(self):
        return self.__str__()
Пример #9
0
class PlanElementGraph(ElementGraph):
    def __init__(self,
                 ID=None,
                 type_graph=None,
                 name=None,
                 Elements=None,
                 plan_elm=None,
                 Edges=None,
                 Restrictions=None):

        if ID is None:
            ID = uuid4()
        if type_graph is None:
            type_graph = 'PlanElementGraph'
        if Elements is None:
            Elements = set()
        if Edges is None:
            Edges = set()
        if Restrictions is None:
            Restrictions = set()

        self.OrderingGraph = OrderingGraph()
        self.CausalLinkGraph = CausalLinkGraph()
        self.DecompGraph = OrderingGraph()

        self.nonequals = set()
        self.flaws = FlawLib()
        self.solved = False
        self.initial_dummy_step = None
        self.final_dummy_step = None

        if plan_elm is None:
            plan_elm = Element(ID=ID, typ=type_graph, name=name)

        super(PlanElementGraph, self).__init__(ID, type_graph, name, Elements,
                                               plan_elm, Edges, Restrictions)

    def __hash__(self):
        return hash(self.name) ^ hash(self.typ) ^ hash(self.ID)

    def __getattr__(self, name):
        if name == 'Args':
            self.updateArgs()
            return self.Args
        else:
            raise AttributeError('no attribute {}'.format(name))

    @classmethod
    def Actions_2_Plan(cls, Actions, h):
        # Used by Plannify

        if not checkHeight(Actions, h):
            return None

        elements = set().union(*[A.elements for A in Actions])
        edges = set().union(*[A.edges for A in Actions])

        new_ords = []
        new_links = []
        new_decomps = []
        for A in Actions:
            if hasattr(A, "ground_subplan"):
                for elm in A.ground_subplan.elements:
                    if elm not in elements and type(elm) == Operator:
                        elm.arg_name = str(uuid4())[19:23] + elm.arg_name
                process_subplan(A.ground_subplan, elements, edges, new_ords,
                                new_links, new_decomps)

        arg_dict = {op: op.arg_name for op in elements if type(op) == Operator}
        inv_map = {v: k for k, v in arg_dict.items()}

        new_edges = []
        for edge in edges:
            must_replace = False
            source = edge.source
            sink = edge.sink
            if type(source) == Operator:
                source = inv_map[source.arg_name]
                must_replace = True
            if type(sink) == Operator:
                sink = inv_map[sink.arg_name]
                must_replace = True
            if must_replace:
                new_edges.append(Edge(source, sink, edge.label))
            else:
                new_edges.append(edge)
        new_elements = []
        for elm in elements:
            if type(elm) == Operator:
                new_elements.append(inv_map[elm.arg_name])
            else:
                new_elements.append(elm)

        update_ords = []
        update_links = []
        update_decomps = []
        for ord in new_ords:
            update_ords.append(
                Edge(inv_map[ord.source.arg_name], inv_map[ord.sink.arg_name],
                     ord.label))
        for link in new_links:
            update_links.append(
                Edge(inv_map[link.source.arg_name],
                     inv_map[link.sink.arg_name], link.label))
        for decomp in new_decomps:
            update_decomps.append(
                Edge(inv_map[decomp.source.arg_name],
                     inv_map[decomp.sink.arg_name], decomp.label))

        Plan = cls(name='Action_2_Plan',
                   Elements=set(new_elements),
                   Edges=set(new_edges))
        Plan.OrderingGraph.edges = set(update_ords)
        Plan.CausalLinkGraph.edges = set(update_links)
        Plan.DecompGraph.edges = set(update_decomps)

        return Plan

    def deepcopy(self):
        new_self = copy.deepcopy(self)
        new_self.ID = uuid4()
        return new_self

    def AddSubgraph(self, subgraph):
        self.elements.update(subgraph.elements)
        self.edges.update(subgraph.edges)

    def isInternallyConsistent(self):
        return self.OrderingGraph.isInternallyConsistent() and self.CausalLinkGraph.isInternallyConsistent() and \
            super(PlanElementGraph, self).isInternallyConsistent()

    @property
    def Steps(self):
        return [
            element for element in self.elements if type(element) is Operator
        ]

    @property
    def Step_Graphs(self):
        return [Action.subgraph(self, step) for step in self.Steps]

    # @property
    # def Root_Graphs(self):
    # 	root_steps = []
    # 	for s in self.Steps:
    # 		nobodys_descendant = True
    # 		for t in self.Steps:
    # 			if s == t:
    # 				continue
    # 			if s in self.rGetDescendants(t):
    # 				nobodys_descendant = False
    # 				break
    # 		if nobodys_descendant:
    # 			root_steps.append(s)
    # 	return [Action.subgraph(self, step) for step in root_steps]

    def __repr__(self):
        c = '\ncost {} + heuristic {}'.format(self.cost, self.heuristic)
        steps = [''.join('\t' + str(step) + '\n' for step in self.Step_Graphs)]
        order = [
            ''.join('\t' + str(ordering.source) + ' < ' + str(ordering.sink) +
                    '\n' for ordering in self.OrderingGraph.edges)
        ]
        links = [
            ''.join('\t' + str(cl) + '\n' for cl in self.CausalLinkGraph.edges)
        ]
        return 'PLAN: ' + str(self.ID) + c + '\n*Steps: \n' + ''.join(['{}'.format(step) for step in steps]) + \
            '*Orderings:\n' + \
            ''.join(['{}'.format(o) for o in order]) + '*CausalLinks:\n' + ''.join(['{}'.format(link) for link in links]) + '}'
Пример #10
0
class GStep:
    """
	Read-Only Ground Step
	"""
    def __init__(self, operator, args, preconditions, stepnum, height):

        # READ-ONLY ATTRIBUTES #
        # schema refers to the name of the operator
        self.schema = operator
        # Args are Argument or Actor "Element" types
        self.Args = args
        # ID used as "instance ID"
        self.ID = uuid4()
        # preconds is a list of GCond
        self.preconds = preconditions
        # stepnum is the ground step constructor type
        self.stepnum = stepnum
        self.stepnumber = stepnum
        # height is 0 when primitive
        self.height = height

        if height > 0:
            self.sub_steps = []
            self.sub_orderings = OrderingGraph()
            self.sub_links = CausalLinkGraph()
            self.dummy = dummyTuple(None, None)

        # depth starts at 0 and takes on value during planning
        self.depth = 0

        self.cndts = None
        self.cndt_map = None
        self.threat_map = None
        self.threats = None

        self.instantiable = True

        # INSTANCE ATTRIBUTES #
        # risks are number of threat instances
        self.risks = list()
        self.choices = list()
        # choices are instances of cndt antecedents
        self.choice_map = dict()
        # self.num_choices = 0
        # open preconditions which need causal link
        self.open_preconds = list(self.preconds)

    # def to_json(self):
    # 	return '{}:{}, {}'
    # return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)

    # public methods #

    # def default(self):
    # 	def default(self, obj):
    # 		if hasattr(obj, 'to_json'):
    # 			return obj.to_json()
    # 		return json.JSONEncoder.default(self, obj)

    def setup(self, step_to_cndt, precond_to_cndt, step_to_threat,
              precond_to_threat):
        """
		:param step_to_cndt: dict of form GStep -> GStep^k such as D[stepnum] -> [cndt antecedent step nums]
		:param precond_to_cndt: dict of form GLiteral -> GStep^k such as D[pre.ID] -> [cndt antecedent step nums]
		:param step_to_threat: dict of form GLiteral -> Gstep^k such as D[stepnum] -> [cndt threat step nums]
		"""
        self.cndts = list(step_to_cndt[self.stepnum])
        self.cndt_map = {
            pre.ID: list(precond_to_cndt[pre.ID])
            for pre in self.preconds
        }
        self.threats = list(step_to_threat[self.stepnum])
        self.threat_map = {
            pre.ID: list(precond_to_threat[pre.ID])
            for pre in self.preconds
        }

    def swap_setup(self, cndts, cndtmap, threats, threatmap):
        self.cndts = cndts
        self.cndt_map = cndtmap
        self.threats = threats
        self.threat_map = threatmap

    def swap_substeps(self, gsteps, decomp_step, num_GL_steps):
        change_dict = {
            step: gsteps[step.stepnumber].instantiate()
            for step in decomp_step.ground_subplan.Steps
        }
        self.sub_steps = list(change_dict.values())
        for edge in decomp_step.ground_subplan.OrderingGraph.edges:
            self.sub_orderings.addEdge(change_dict[edge.source],
                                       change_dict[edge.sink])
        for edge in decomp_step.ground_subplan.CausalLinkGraph.edges:
            new_sink = change_dict[edge.sink]
            # Condition.subgraph(subplan, edge.label)
            g_label = GLiteral(edge.label.name, edge.label.Args,
                               edge.label.truth, -1, None)
            for p in new_sink.preconds:
                if p != g_label:
                    continue
                self.sub_links.addEdge(change_dict[edge.source], new_sink, p)
                self.sub_orderings.addEdge(change_dict[edge.source], new_sink)
                new_sink.fulfill(p)
                break

        # set these babes to not be instantiable "fo' life"
        gsteps[decomp_step.sub_dummy_init.stepnumber].instantiable = False
        gsteps[decomp_step.sub_dummy_goal.stepnumber].instantiable = False
        init_step = gsteps[decomp_step.sub_dummy_init.stepnumber].instantiate()
        final_step = gsteps[
            decomp_step.sub_dummy_goal.stepnumber].instantiate()

        for step in self.sub_steps:
            self.sub_orderings.addEdge(init_step, step)
            self.sub_orderings.addEdge(step, final_step)
        self.sub_orderings.addEdge(init_step, final_step)

        # reconfigure init step to be top cndt for all steps and goal

        for step in self.sub_steps:
            for other_step in self.sub_steps:
                if other_step == step:
                    continue
                prioritize_cndt(other_step, step)
            prioritize_cndt(init_step, step)
            prioritize_cndt(step, final_step)
        prioritize_cndt(init_step, final_step)

        # add init_step as top cndt for all

        self.dummy = dummyTuple(init_step, final_step)

    def instantiate(self,
                    default_refresh=None,
                    default_None_is_to_refresh_open_preconds=None):
        new_self = copy.deepcopy(self)
        new_self.ID = uuid4()
        self.choice_map = dict()

        if default_refresh is None:
            self.risks = list()
            self.choices = list()

        if default_None_is_to_refresh_open_preconds is None:
            self.open_preconds = list(self.preconds)

        return new_self

    def fulfill(self, pre):
        if self.cndt_map is None:
            raise AttributeError('Cndt Map not found; run setup(xyz) first')
        if pre.ID not in self.cndt_map:
            raise ValueError('{} not found in cndt_map, id={}'.format(
                pre, pre.ID))
        if pre not in self.preconds:
            raise ValueError(
                '{} found in cndt_map w/ id={}, but {} not found in preconds'.
                format(pre, pre.ID, pre))
        # remove precondition from open precond
        if pre in self.open_preconds:
            self.open_preconds.remove(pre)
        else:
            print('pre: {} not found in {} to remove, allowed in some cases'.
                  format(pre, self))

    def update_choices(self, plan):
        choices = set()
        for pre in self.open_preconds:
            choice_nums = self.cndt_map[pre.ID]
            for step in plan.steps:
                if self.ID == step.ID:
                    continue
                if plan.OrderingGraph.isPath(self, step):
                    continue
                if step.stepnum in choice_nums:
                    choices.add(step)
        self.choices = list(choices)

    def is_cndt(self, other):
        return other.stepnum in self.cndts

    def is_threat(self, other):
        return other.stepnum in self.threats

    # private hooks #

    def __hash__(self):
        return hash(self.ID)

    def __eq__(self, other):
        return self.ID == other.ID

    def __str__(self):
        args = str([
            arg.name if not isinstance(arg, ElementGraph) else arg
            for arg in self.Args
        ])
        return str(self.schema) + args + '_{}'.format(str(self.ID)[-4:])

    def __repr__(self):
        return self.__str__()
Пример #11
0
class GStep:
	"""
	Read-Only Ground Step
	"""

	def __init__(self, operator, args, preconditions, effects, stepnum, height):

		# READ-ONLY ATTRIBUTES #
		# schema refers to the name of the operator
		self.schema = operator
		# Args are Argument or Actor "Element" types
		self.Args = args
		# ID used as "instance ID"
		self.ID = uuid4()
		# preconds is a list of GCond
		self.preconds = preconditions
		self.effects = effects
		# stepnum is the ground step constructor type
		self.stepnum = stepnum
		self.stepnumber = stepnum
		# height is 0 when primitive
		self.height = height

		if height > 0:
			self.sub_steps = []
			self.sub_orderings = OrderingGraph()
			self.sub_links = CausalLinkGraph()
			self.dummy = dummyTuple(None, None)

		# depth starts at 0 and takes on value during planning
		self.depth = 0

		self.cndts = None
		self.cndt_map = None
		self.threat_map = None
		self.threats = None
		self.cntg_mental = None

		self.instantiable = True

		# INSTANCE ATTRIBUTES #
		# risks are number of threat instances
		self.risks = list()
		self.choices = list()
		# choices are instances of cndt antecedents
		self.choice_map = dict()
		# self.num_choices = 0
		# open preconditions which need causal link
		self.open_preconds = list(self.preconds)

	# def to_json(self):
	# 	return '{}:{}, {}'
		# return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)

	# public methods #

	# def default(self):
	# 	def default(self, obj):
	# 		if hasattr(obj, 'to_json'):
	# 			return obj.to_json()
	# 		return json.JSONEncoder.default(self, obj)

	def setup(self, step_to_cndt, precond_to_cndt, step_to_threat, precond_to_threat, cntg_mental):
		"""
		:param step_to_cndt: dict of form GStep -> GStep^k such as D[stepnum] -> [cndt antecedent step nums]
		:param precond_to_cndt: dict of form GLiteral -> GStep^k such as D[pre.ID] -> [cndt antecedent step nums]
		:param step_to_threat: dict of form GLiteral -> Gstep^k such as D[stepnum] -> [cndt threat step nums]
		"""
		self.cndts = list(step_to_cndt[self.stepnum])
		self.cndt_map = {pre.ID: list(precond_to_cndt[pre.ID]) for pre in self.preconds}
		self.threats = list(step_to_threat[self.stepnum])
		self.threat_map = {pre.ID: list(precond_to_threat[pre.ID]) for pre in self.preconds}
		self.cntg_mental = {pre.ID: list(cntg_mental[pre.ID]) for pre in self.preconds}

	def swap_setup(self, cndts, cndtmap, threats, threatmap, cntgmap):
		self.cndts = cndts
		self.cndt_map = cndtmap
		self.threats = threats
		self.threat_map = threatmap
		self.cntg_mental = cntgmap

	# for each sub-step in sub-plan, create gstep
	@clock
	def swap_substeps(self, gsteps, GL, decomp_step):
		# base case - sub-steps are all height = 0
		primitive_substeps = [arg for arg in decomp_step.ground_subplan.elements
		                      if type(arg) == Operator and arg.height == 0]
		composite_substeps = [arg for arg in decomp_step.ground_subplan.elements
		                      if type(arg) == Operator and arg.height > 0]

		if len(composite_substeps) == 0:
			prim_dict = {step: gsteps[step.stepnumber].instantiate() for step in primitive_substeps}
			self.create_composite_gstep(gsteps, decomp_step, prim_dict)
			return prim_dict
		else:
			# links and orderings in intermediate stage
			# change_dict = {step.root: gsteps[step.stepnumber].instantiate() for step in decomp_step.ground_subplan.Root_Graphs}

			change_dict = {}
			# order steps by height, lowest to highest.
			step_list = [step for step in decomp_step.ground_subplan.Step_Graphs]
			step_list.sort(key=lambda x: x.height)
			do_not_add_as_substep = []
			for step in step_list:

				Args = [decompile(arg, decomp_step.ground_subplan) for arg in step.Args]
				preconds = [GLiteral(p.name, [decompile(arg, p) for arg in p.Args],
				                     p.truth, p.replaced_ID, (p.name, p.truth) not in GL.non_static_preds)
				            for p in step.Preconditions]
				effects = [GLiteral(e.name, [decompile(arg, e) for arg in e.Args],
				                    e.truth, e.replaced_ID, (e.name, e.truth) not in GL.non_static_preds)
				           for e in step.Effects]
				schema = str(step)
				step_copy = GStep(schema, Args, preconds, effects, step.stepnumber, step.height)
				step_copy.ID = step.root.ID
				st_t = gsteps[step.stepnumber].instantiate()
				step_copy.swap_setup(st_t.cndts, st_t.cndt_map, st_t.threats, st_t.threat_map, st_t.cntg_mental)

				# give no children
				if step.height > 0:
					init_step = st_t.dummy[0]
					init_step.schema = "begin:" + str(step)
					final_step = st_t.dummy[1]
					final_step.schema = "finish:" + str(step)
					step_copy.dummy = dummyTuple(init_step, final_step)

					# step_copy.sub_steps = []
					children = decomp_step.ground_subplan.DecompGraph.getNeighbors(step.root)
					step_copy.sub_steps = [change_dict[child] for child in children if child.typ != 'step-s']
					do_not_add_as_substep.extend(step_copy.sub_steps)

					step_copy.sub_orderings = OrderingGraph()
					step_copy.sub_links = CausalLinkGraph()

				change_dict[step.root] = step_copy
				# self.sub_steps.append(step)
			self.create_composite_gstep(gsteps, decomp_step, change_dict, do_not_add_as_substep)
			return change_dict

	@clock
	def create_composite_gstep(self, gsteps, decomp_step, change_dict, do_not_add_as_substep=None):
		if do_not_add_as_substep is None:
			self.sub_steps = list(change_dict.values())
		else:
			self.sub_steps = [item for item in change_dict.values() if item not in do_not_add_as_substep]

		for edge in decomp_step.ground_subplan.OrderingGraph.edges:
			source = change_dict[edge.source]
			# if source.height > 0:
			# source = change_dict[edge.source].dummy[1]
			sink = change_dict[edge.sink]
			# if sink.height > 0:
			# 	sink = change_dict[edge.sink].dummy[0]
			self.sub_orderings.addLabeledEdge(source, sink, edge.label)

		for edge in decomp_step.ground_subplan.CausalLinkGraph.edges:
			new_sink = change_dict[edge.sink]
			# Condition.subgraph(subplan, edge.label)
			g_label = GLiteral(edge.label.name, [decompile(arg, decomp_step.ground_subplan) for arg in edge.label.Args],
			                   edge.label.truth, -1, None)
			for p in new_sink.preconds:

				if p != g_label:
					continue
				self.sub_links.addEdge(change_dict[edge.source], new_sink, p)
				self.sub_orderings.addEdge(change_dict[edge.source], new_sink)
				new_sink.fulfill(p)
				break

		# set these babes to not be instantiable "fo' life"
		gsteps[decomp_step.sub_dummy_init.stepnumber].instantiable = False
		gsteps[decomp_step.sub_dummy_goal.stepnumber].instantiable = False
		init_step = gsteps[decomp_step.sub_dummy_init.stepnumber].instantiate()
		final_step = gsteps[decomp_step.sub_dummy_goal.stepnumber].instantiate()

		for step in self.sub_steps:
			self.sub_orderings.addEdge(init_step, step)
			self.sub_orderings.addEdge(step, final_step)
		self.sub_orderings.addEdge(init_step, final_step)

		# reconfigure init step to be top cndt for all steps and goal

		for step in self.sub_steps:
			for other_step in self.sub_steps:
				if other_step == step:
					continue
				prioritize_cndt(other_step, step)
			prioritize_cndt(init_step, step)
			prioritize_cndt(step, final_step)
		prioritize_cndt(init_step, final_step)

		# add init_step as top cndt for all

		self.dummy = dummyTuple(init_step, final_step)

	def compile_do_not_insert_list(self, eff_dict, step_swap_map):
		"""
		Compile a mapping from precondition IDs to sub_steps.
		1. precondition matches THIS step as establisher
		2. THIS step has height > 0
		3. THIS step has a mapping from preconditino IDs to its sub_steps
		4. mark these sub_steps as DO NOT INSERT during planning
		"""
		eff_ids = {eff.ID: eff for eff in self.effects}
		relevant_effects = defaultdict(list)
		for k, v in eff_dict.items():
			for v_i in v:
				if v_i not in eff_ids.keys():
					continue
				relevant_effects[eff_ids[v_i]].append(k)

		# relevant_effects = {eff_ids[v_i]: k for k, v in eff_dict.items() for v_i in v if v_i in eff_ids.keys()}

		# relevant_effects = {eff: eff_dict[eff.ID] for eff in self.effects}
		self.do_not_insert_map = {}
		for eff, pre_IDs in relevant_effects.items():
			gstep_list = [step_swap_map[arg.root] for arg in eff.Args if type(arg) == Action]
			for pid in pre_IDs:
				self.do_not_insert_map[pid] = gstep_list

	def instantiate(self, default_refresh=None, default_None_is_to_refresh_open_preconds=None):
		new_self = copy.deepcopy(self)
		new_self.ID = uuid4()
		self.choice_map = dict()

		if default_refresh is None:
			self.risks = list()
			self.choices = list()

		if default_None_is_to_refresh_open_preconds is None:
			self.open_preconds = list(self.preconds)

		return new_self

	def fulfill(self, pre):
		if self.cndt_map is None:
			raise AttributeError('Cndt Map not found; run setup(xyz) first')
		if pre.ID not in self.cndt_map:
			raise ValueError('{} not found in cndt_map, id={}'.format(pre, pre.ID))
		if pre not in self.preconds:
			raise ValueError('{} found in cndt_map w/ id={}, but {} not found in preconds'.format(pre, pre.ID, pre))
		# remove precondition from open precond
		if pre in self.open_preconds:
			self.open_preconds.remove(pre)
		else:
			print('pre: {} not found in {} to remove, allowed in some cases'.format(pre, self))

	def update_choices(self, plan):
		choices = set()
		for pre in self.open_preconds:
			choice_nums = self.cndt_map[pre.ID]
			for step in plan.steps:
				if self.ID == step.ID:
					continue
				if plan.OrderingGraph.isPath(self, step):
					continue
				if step.stepnum in choice_nums:
					choices.add(step)
		self.choices = list(choices)

	def is_cndt(self, other):
		return other.stepnum in self.cndts

	def is_threat(self, other):
		return other.stepnum in self.threats

	# private hooks #

	def __hash__(self):
		return hash(self.ID)

	def __eq__(self, other):
		return self.ID == other.ID

	def __str__(self):
		# if len(self.Args) > 0 and type(self.Args[0]) == str:
		# 	args = ""
		# else:
		# 	args = str([arg.name if not isinstance(arg, ElementGraph) else arg for arg in self.Args])
		# return str(self.schema) + args + '_{}'.format(str(self.ID)[-4:])

		return str(self.schema) + '_{}'.format(str(self.ID)[-4:])

	def __repr__(self):
		return self.__str__()