示例#1
0
def domainToOperatorGraphs(domain):
	opGraphs = set()
	dopGraphs = set()
	for action in domain.actions:
		op = Operator(name=action.name, num_args=len(action.parameters))
		op_graph = Action(name=action.name, root_element=op)
		evalActionParams(action.parameters, op_graph)

		if action.precond is not None:
			getFormulaGraph(action.precond.formula, op_graph, parent=op, relationship='precond-of',
							elements=op_graph.elements, edges=op_graph.edges)
		if action.effect is not None:
			getFormulaGraph(action.effect.formula, op_graph, parent=op, relationship='effect-of',
							elements=op_graph.elements,
							edges=op_graph.edges)

		if action.decomp is not None:
			# henceforth, action.decomp is tuple (sub-params, decomp)
			decomp_graph = PlanElementGraph(name=action.name, type_graph='decomp')
			getDecompGraph(action.decomp.formula, decomp_graph, action.parameters + action.decomp.sub_params)
			op_graph.subplan = decomp_graph

			# This searches for params that are listed as params and sub-params, may not be needed
			# opelms = list(op_graph.elements)
			# dpelms = list(decomp_graph.elements)
			# for step_elm in opelms:
			# 	for d_elm in dpelms:
			# 		if not isinstance(d_elm, Argument):
			# 			continue
			# 		if d_elm.arg_name == step_elm.arg_name:
			# 			op_graph.assign(step_elm, d_elm)
			dopGraphs.add(op_graph)
		else:
			opGraphs.add(op_graph)
	return opGraphs, dopGraphs
示例#2
0
def Groundify(Planets, GL, has_links):

	for Planet in Planets:
		for step in Planet.Steps:
			Step = Action.subgraph(Planet, step)
			Planet.UnifyActions(Step, GL[step.stepnumber])

	if not has_links:
		#we're done
		return Planets

	Discovered_Planets = []
	for Plan in Planets:
		Libs = [LinkLib(i,link,GL) for i, link in enumerate(Plan.CausalLinkGraph.edges)]

		#LW = [plan1 [link1.condition, link2.condition,..., link-n.condition],
			#  plan2 [link1.condition, link2.condition, ..., link-m.condition],
		    #  plan-k [l1,...,lz]]
		LW = productByPosition(Libs)

		for lw in LW:
			NP = Plan.deepcopy()
			for _link in lw:
				pre_token = GL.getConsistentPrecondition(Action.subgraph(NP, _link.sink), _link.label)
				pre_link = NP.RemoveSubgraph(pre_token)
				pre_link.sink = _link.label

			Discovered_Planets.append(NP)

	return Discovered_Planets
示例#3
0
def Groundify(Planets, GL, has_links):

	for Planet in Planets:
		for step in Planet.Steps:
			Step = Action.subgraph(Planet, step)
			Planet.UnifyActions(Step, GL[step.stepnumber])

	if not has_links:
		#we're done
		return Planets

	Discovered_Planets = []
	for Plan in Planets:
		Libs = [LinkLib(i,link,GL) for i, link in enumerate(Plan.CausalLinkGraph.edges)]

		#LW = [plan1 [link1.condition, link2.condition,..., link-n.condition],
			#  plan2 [link1.condition, link2.condition, ..., link-m.condition],
		    #  plan-k [l1,...,lz]]
		LW = productByPosition(Libs)

		for lw in LW:
			NP = Plan.deepcopy()
			for _link in lw:
				pre_token = GL.getConsistentPrecondition(Action.subgraph(NP, _link.sink), _link.label)
				if _link.label == pre_token:
					continue
				pre_link = NP.RemoveSubgraph(pre_token)
				pre_link.sink = _link.label
				NP.edges.add(pre_link)

			Discovered_Planets.append(NP)

	return Discovered_Planets
示例#4
0
def problemToGraphs(problem):
	"""
		Returns a dictionary:
		Keys: 'arg', 'init', 'goal'
		Values: arg dictionary, (elements, edges), (elements, edges)
	"""

	Args = {object.name: Argument(name=object.name, typ=object.typeName) for object in problem.objects if
			not object.typeName.lower() in {'character', 'actor', 'person', 'agent'}}
	Args.update({object.name: Actor(typ=object.typeName.lower(), name=object.name) for object in problem.objects if
				 object.typeName.lower() in {'character', 'actor', 'person', 'agent'}})
	goal_elements, goal_edges = getGoalSet(problem.goal.formula, Args)
	goal_op = Operator(name='dummy_goal', stepnumber=1, num_args=0)
	goal_graph = Action(name='dummy_goal', root_element=goal_op)
	goal_graph.elements.update(goal_elements)
	goal_graph.edges.update(goal_edges)
	goal_graph.edges.update({Edge(goal_op, goal_lit, 'precond-of')
							 for goal_lit in goal_elements if type(goal_lit) is Literal})

	init_op = Operator(name='dummy_init', stepnumber=0, num_args=0)
	init_graph = Action(name='dummy_init', root_element=init_op)
	for condition in problem.init.predicates:
		lit = Literal(name=condition.name, num_args=len(condition.parameters), truth=True)
		init_graph.elements.add(lit)
		init_graph.edges.add(Edge(init_op, lit, 'effect-of'))
		for i, p in enumerate(condition.parameters):
			init_graph.edges.add(Edge(lit, Args[p], i))

	return Args, init_graph, goal_graph
示例#5
0
def problemToGraphs(problem):
    """
		Returns a dictionary:
		Keys: 'arg', 'init', 'goal'
		Values: arg dictionary, (elements, edges), (elements, edges)
	"""

    if problem.goalAction is not None:
        action = problem.goalAction
        gop = Operator(name=action.name, num_args=len(action.parameters))
        GoalAction = Action(name=action.name, root_element=gop)
        evalActionParams(action.parameters, GoalAction)
        getFormulaGraph(action.precond.formula,
                        GoalAction,
                        parent=gop,
                        relationship='precond-of',
                        elements=GoalAction.elements,
                        edges=GoalAction.edges)
        decomp_graph = PlanElementGraph(name=action.name, type_graph='decomp')
        getDecompGraph(action.decomp.formula, decomp_graph, action.parameters)
        GoalAction.subgraphs.add(decomp_graph)
        goal_graph = GoalAction
        init_op = Operator(name='dummy_init', stepnumber=0, num_args=0)
        init_graph = Action(name='dummy_init', root_element=init_op)
        Args = dict()

    else:
        Args = {
            object.name: Argument(name=object.name, typ=object.typeName)
            for object in problem.objects
            if not object.typeName.lower() in {'character', 'actor'}
        }
        Args.update({
            object.name: Actor(name=object.name)
            for object in problem.objects
            if object.typeName.lower() in {'character', 'actor'}
        })
        goal_elements, goal_edges = getGoalSet(problem.goal.formula, Args)
        goal_op = Operator(name='dummy_goal', stepnumber=1, num_args=0)
        goal_graph = Action(name='dummy_goal', root_element=goal_op)
        goal_graph.elements.update(goal_elements)
        goal_graph.edges.update(goal_edges)
        goal_graph.edges.update({
            Edge(goal_op, goal_lit, 'precond-of')
            for goal_lit in goal_elements if type(goal_lit) is Literal
        })

        init_op = Operator(name='dummy_init', stepnumber=0, num_args=0)
        init_graph = Action(name='dummy_init', root_element=init_op)
        for condition in problem.init.predicates:
            lit = Literal(name=condition.name,
                          num_args=len(condition.parameters),
                          truth=True)
            init_graph.elements.add(lit)
            init_graph.edges.add(Edge(init_op, lit, 'effect-of'))
            for i, p in enumerate(condition.parameters):
                init_graph.edges.add(Edge(lit, Args[p], ARGLABELS[i]))

    return (Args, init_graph, goal_graph)
示例#6
0
    def testDecomp(self):
        from GlobalContainer import GC

        story_domain = 'domains/ark-domain.pddl'
        story_problem = 'domains/ark-problem.pddl'

        print('Reading {} and {}'.format(story_domain, story_problem))
        story = parseDomAndProb(story_domain, story_problem)
        # (op_graphs, objects, GC.object_types, init, goal)

        try:
            SGL = reload('SGL')
            GC.SGL = SGL
        except:
            SGL = GLib(*story)
            GC.SGL = SGL

        disc_domain = 'domains/ark-discourse-tests.pddl'
        disc_problem = 'domains/ark-discourse-tests-problem.pddl'

        print('Reading {} and {}'.format(disc_domain, disc_problem))
        disc = parseDomAndProb(disc_domain, disc_problem)
        # (op_graphs, objects, GC.object_types, init, goal)

        try:
            DGL = reload('DGL')
            GC.DGL = DGL
        except:
            DGL = GLib(*disc, storyGL=SGL)
            GC.DGL = DGL

        bi = PlanSpacePlanner(story[1], SGL, disc[1], DGL)
        results = bi.POCL(5)
        for R in results:
            S = R.S
            print(type(S))
            print('\n')
            print('Story')

            for step in topoSort(S):
                print(Action.subgraph(S, step))

            for elm in S.elements:
                print(elm)
            for edge in S.edges:
                print(edge)

            D = R.D
            print('\nDiscourse')
            for step in topoSort(D):
                print(Action.subgraph(D, step))

            for elm in D.elements:
                print(elm)
            for edge in D.edges:
                print(edge)

        print('\n\n')
示例#7
0
def AddLink(link, new_plan, UW, remove_flaw=True):

	Source = Action.subgraph(new_plan, UW[link.source.position])
	new_d = Source.getElmByRID(link.label.replaced_ID)
	if new_d is None:
		Sink = Action.subgraph(new_plan, UW[link.sink.position])
		new_d = Sink.getElmByRID(link.label.replaced_ID)
	D = Condition.subgraph(new_plan, new_d)
	new_plan.CausalLinkGraph.addEdge(UW[link.source.position], UW[link.sink.position],D)

	if remove_flaw:
		flaws = new_plan.flaws.flaws
		f = Flaw((UW[link.sink.position], D), 'opf')
		if f in flaws:
			new_plan.flaws.remove(f)
示例#8
0
def Plannify(RQ, GL):
    #An ActionLib for steps in RQ - ActionLib is a container w/ all of its possible instances as ground steps
    print('... Processing {}'.format(RQ.name))
    print('...ActionLibs')
    Libs = [
        ActionLib(i, RS, GL) for i, RS in enumerate(
            [Action.subgraph(RQ, step) for step in RQ.Steps])
    ]

    #A World is a combination of one ground-instance from each step
    Worlds = productByPosition(Libs)

    print('...Planets')
    #A Planet is a plan s.t. all steps are "arg_name consistent", but a step may not be equiv to some ground step
    Planets = [
        PlanElementGraph.Actions_2_Plan(W) for W in Worlds
        if isArgNameConsistent(W)
    ]

    print('...Linkify')
    #Linkify installs orderings and causal links from RQ/decomp to Planets, rmvs Planets which cannot support links
    has_links = Linkify(Planets, RQ, GL)

    print('...Groundify')
    #Groundify is the process of replacing partial steps with its ground step, and removing inconsistent planets
    Plans = Groundify(Planets, GL, has_links)

    print('...returning consistent plans')
    return [Plan for Plan in Plans if Plan.isInternallyConsistent()]
示例#9
0
	def testPlanner(self):
		from GlobalContainer import GC

	#	domain = 'domains/ark-domain.pddl'
	#	problem = 'domains/ark-problem.pddl'
		#domain = 'domains/ark-domain-decomp.pddl'
		#problem = 'domains/ark-problem-decomp.pddl'
	#	domain = 'domains/ark-domain-decomp-two.pddl'
		#problem = 'domains/ark-problem-decomp-two.pddl'
		#domain = 'domains/ark-domain-decomp-three.pddl'
	#	problem = 'domains/ark-problem-outcomes.pddl'
	#	domain = 'domains/ark-domain-outcomes.pddl'
		domain = 'domains/h1.pddl'
		problem = 'domains/h1p1.pddl'

		print('Reading {} and {}'.format(domain, problem))

		try:
			SGL = reload(domain + problem)
			GC.SGL = SGL
		except:
			SGL = GLib(domain, problem)
			GC.SGL = SGL

		pypocl = PlanSpacePlanner(SGL)
		results = pypocl.POCL(1)
		for R in results:
			print(R)
			for step in topoSort(R):
				print(Action.subgraph(R, step))

		print('\n\n')
示例#10
0
def AddNewSteps(UW, other, SSteps, new_plan):
	for step in UW:
		if step not in SSteps:
			S_new = Action.subgraph(other, step).deepcopy()
			S_new.root.arg_name = step.stepnumber
			# move pieces
			new_plan.elements.update(S_new.elements)
			new_plan.edges.update(S_new.edges)
			# place in order
			new_plan.OrderingGraph.addEdge(new_plan.initial_dummy_step, S_new.root)
			new_plan.OrderingGraph.addEdge(S_new.root, new_plan.final_dummy_step)
示例#11
0
def AddNewFlaws(GL, step, new_plan):
	Step = Action.subgraph(new_plan, step)
	# Step = Action.subgraph(new_plan, new_plan.getElmByRID(step.replaced_ID))

	for pre in Step.preconditions:
		#this is a hack, if the precondition has two operator parents, then its in a causal link
		cndts = {edge for edge in new_plan.edges if isinstance(edge.source, Operator) and edge.sink == pre}
		if len(cndts) == 0:
			raise ValueError('wait, no edge for this preconditon? impossible!')
		if len(cndts) < 2:
			new_plan.flaws.insert(GL, new_plan, Flaw((step, pre), 'opf'))

	new_plan.flaws.addCndtsAndRisks(GL, step)
示例#12
0
    def POCL(self, num_plans=5):
        Completed = []
        visited = 0

        while len(self.Open) > 0:

            #Select child
            plan = self.Open.pop()

            visited += 1

            if not plan.isInternallyConsistent():
                continue

            if plan.num_flaws() == 0:
                print(
                    'bipartite solution found at {} nodes expanded and {} nodes visited'
                    .format(visited,
                            len(self.Open) + visited))
                Completed.append(plan)
                if len(Completed) == num_plans:
                    return Completed
                continue
            elif len(plan.S.flaws) == 0 and not plan.S.solved:
                plan.S.solved = True
                print(
                    'story solution found at {} nodes expanded and {} nodes visited'
                    .format(visited,
                            len(self.Open) + visited))
            elif len(plan.D.flaws) == 0 and not plan.D.solved:
                plan.D.solved = True
                print(
                    'disc solution found at {} nodes expanded and {} nodes visited'
                    .format(visited,
                            len(self.Open) + visited))
                for step in topoSort(plan.D):
                    print(Action.subgraph(plan.D, step))
                print('\n')

            #Select Flaw
            k, flaw = plan.next_flaw()
            #k = 0:story, 1:disc
            #if k == 1:
            print('{} selected : {}\n'.format(flaw.name, flaw))

            #Add children to Open List
            children = self.generateChildren(plan, k, flaw)

            #print('generated children: {}'.format(len(children)))
            for child in children:
                self.Open.insert(child)
示例#13
0
def domainToOperatorGraphs(domain):
    opGraphs = set()
    for action in domain.actions:
        op = Operator(name=action.name, num_args=len(action.parameters))
        op_graph = Action(name=action.name, root_element=op)
        evalActionParams(action.parameters, op_graph)

        if action.precond is not None:
            getFormulaGraph(action.precond.formula,
                            op_graph,
                            parent=op,
                            relationship='precond-of',
                            elements=op_graph.elements,
                            edges=op_graph.edges)
        if action.effect is not None:
            getFormulaGraph(action.effect.formula,
                            op_graph,
                            parent=op,
                            relationship='effect-of',
                            elements=op_graph.elements,
                            edges=op_graph.edges)
        if hasattr(action, 'decomp') and action.decomp is not None:
            decomp_graph = PlanElementGraph(name=action.name,
                                            type_graph='decomp')
            getDecompGraph(action.decomp.formula, decomp_graph,
                           action.parameters)
            op_graph.subgraphs.add(decomp_graph)
            for step_elm in op_graph.elements:
                for d_elm in decomp_graph.elements:
                    if not isinstance(d_elm, Argument):
                        continue
                    if d_elm.arg_name == step_elm.arg_name:
                        op_graph.assign(step_elm, d_elm)

        opGraphs.add(op_graph)
    return opGraphs
示例#14
0
	def POCL(self, num_plans=5):
		completed = []
		visited = 0

		while len(self) > 0:

			print(visited, len(self)+visited)
			#Select child
			#print(self._frontier)

			plan = self.pop()
			print(plan.flaws)
			#print('\n selecting plan: {}'.format(plan))
			#print(plan.flaws)

			visited += 1

			if not plan.isInternallyConsistent():
				print('pruned')
				print(plan)
				print(plan.flaws)
				continue

			if len(plan.flaws) == 0:
				print('\nsolution found at {} nodes expanded and {} nodes visited'.format(visited, len(self)+visited))
				completed.append(plan)
				if len(completed) == num_plans:
					print('\n')
					return completed
				for step in topoSort(plan):
					print(Action.subgraph(plan, step))
				continue

			#Select Flaw
			flaw = plan.flaws.next()
			print('{} selected : {}\n'.format(flaw.name, flaw))

		#	if flaw.name == 'tclf':
		#		print('{} selected : {}\n'.format(flaw.name, flaw))
			#	print(plan.flaws)

			#Add children to Open List
			children = self.generateChildren(plan, flaw)

			#print('generated children: {}'.format(len(children)))
			for child in children:
				self.insert(child)
		raise ValueError('Frontier is empty... no plan found')
示例#15
0
    def reuse(self, plan, flaw, GL):
        results = set()
        s_need, precondition = flaw.flaw

        #antecedents - a set of stepnumbers
        antecedents = GL.id_dict[precondition.replaced_ID]
        if len(antecedents) == 0:
            return set()

        for s_old in plan.Steps:
            if s_old.stepnumber not in antecedents:
                continue
            if s_old == s_need:
                continue

            #step 1 - make a copy of the plan, also replaces the plan number
            new_plan = plan.deepcopy()

            #step 2 - Actionize the steps from new_plan
            S_Old = Action.subgraph(new_plan, s_old)
            s_need_new = new_plan.getElementById(s_need.ID)
            #S_Need = Action.subgraph(new_plan, s_need)

            #step 3-4 retarget precondition to be s_old effect
            pre_link_sink = self.RetargetPrecondition(GL, new_plan, S_Old,
                                                      precondition)
            if pre_link_sink is False:
                #Can't reuse in discourse case because story elms in disc args refer to different event instances
                continue

            #step 5 - add orderings, causal links, and create flaws
            self.addStep(new_plan,
                         S_Old.root,
                         s_need_new,
                         pre_link_sink,
                         GL,
                         new=False)

            #step 6 - add new plan to open list
            results.add(new_plan)

        return results
示例#16
0
def Plannify(RQ, GL):
	#An ActionLib for steps in RQ - ActionLib is a container w/ all of its possible instances as ground steps
	print('...ActionLibs')
	Libs = [ActionLib(i, RS, GL) for i, RS in enumerate([Action.subgraph(RQ, step) for step in RQ.Steps])]

	#A World is a combination of one ground-instance from each step
	Worlds = productByPosition(Libs)

	print('...Planets')
	#A Planet is a plan s.t. all steps are "arg_name consistent", but a step may not be equiv to some ground step
	Planets = [PlanElementGraph.Actions_2_Plan(W) for W in Worlds if isArgNameConsistent(W)]

	print('...Linkify')
	#Linkify installs orderings and causal links from RQ/decomp to Planets, rmvs Planets which cannot support links
	has_links = Linkify(Planets, RQ, GL)

	print('...Groundify')
	#Groundify is the process of replacing partial steps with its ground step, and removing inconsistent planets
	Plans = Groundify(Planets, GL, has_links)

	print('...returning consistent plans')
	return [Plan for Plan in Plans if Plan.isInternallyConsistent()]
示例#17
0
def Groundify(Planets, GL, has_links):
	print('...Groundify - Unifying Actions with GL')
	for i, Planet in enumerate(Planets):
		print("... Planet {}".format(i))
		for Step in Planet.Step_Graphs:
			print('... Unifying {} with {}'.format(Step, GL[Step.stepnumber]))
			# Unify Actions (1) swaps step graphs with ground step
			Planet.UnifyActions(Step, GL[Step.stepnumber])

	if not has_links:
		return Planets

	print('...Groundify - Creating Causal Links')
	Discovered_Planets = []
	for Plan in Planets:

		#print(Plan)
		Libs = [LinkLib(i, link, GL) for i, link in enumerate(Plan.CausalLinkGraph.edges)]

		#LW = [plan1 [link1.condition, link2.condition,..., link-n.condition],
			#  plan2 [link1.condition, link2.condition, ..., link-m.condition],
		    #  plan-k [l1,...,lz]]
		LW = productByPosition(Libs)

		for lw in LW:
			# create new Planet ("discovered planet") for each linkworld.
			NP = Plan.deepcopy()
			for _link in list(lw):
				pre_token = GL.getConsistentPrecondition(Action.subgraph(NP, _link.sink), _link.label)
				#label = NP.getElementByID(_link.label.ID)
				if pre_token != _link.label:
					NP.ReplaceSubgraphs(pre_token, _link.label)
				NP.CausalLinkGraph.edges.remove(_link)
				NP.CausalLinkGraph.edges.add(Edge(_link.source, _link.sink, Condition.subgraph(NP, _link.label)))

			Discovered_Planets.append(NP)

	return Discovered_Planets
示例#18
0
	def reuse(self, plan, flaw):
		results = set()
		s_need, precondition = flaw.flaw

		#antecedents - a set of stepnumbers
		antecedents = self.GL.id_dict[precondition.replaced_ID]
		if len(antecedents) == 0:
			return set()

		for s_old in plan.Steps:
			if s_old.stepnumber not in antecedents:
				continue
			if s_old == s_need:
				continue

			new_plan = plan.deepcopy()
			Old = Action.subgraph(new_plan, s_old)
			effect_token = self.GL.getConsistentEffect(Old, precondition)
			#joint_literal = self.RetargetPrecondition(self.GL, new_plan, Old, precondition)

			if Old.is_decomp or s_need.is_decomp:
				if not isIdenticalElmsInArgs(precondition.Args, Condition.subgraph(Old, effect_token).Args):
					continue
				else:
					print("not identical")

			effect_edge = new_plan.ReplaceSubgraphs(precondition.root, effect_token)

			#add step, orderings, causal links, and create flaws
			self.addStep(new_plan, Old,
						 s_need=new_plan.getElementById(s_need.ID),
						 condition=Condition.subgraph(new_plan, effect_edge.sink),
						 new=False)

			results.add(new_plan)

		return results
示例#19
0
if __name__ == '__main__':
    num_args = len(sys.argv)
    if num_args > 1:
        domain_file = sys.argv[1]
        if num_args > 2:
            problem_file = sys.argv[2]
    else:
        #domain_file = 'domains/mini-indy-domain.pddl'
        #problem_file = 'domains/mini-indy-problem.pddl'
        domain_file = 'domains/ark-domain.pddl'
        problem_file = 'domains/ark-problem.pddl'

    #f = open('workfile', 'w')
    operators, objects, object_types, initAction, goalAction = parseDomAndProb(
        domain_file, problem_file)
    #non_static_preds = preprocessDomain(operators)
    FlawLib.non_static_preds = preprocessDomain(operators)
    obtypes = obTypesDict(object_types)

    Argument.object_types = obtypes
    planner = PlanSpacePlanner(operators, objects, initAction, goalAction)
    #planner.story_GL = GLib(operators, story_objs, obtypes, initAction, goalAction)

    results = planner.POCL(1)

    for result in results:
        totOrdering = topoSort(result)
        print('\n\n\n')
        for step in topoSort(result):
            print(Action.subgraph(result, step))
        #print(result)
示例#20
0
if __name__ ==  '__main__':
	num_args = len(sys.argv)
	if num_args >1:
		domain_file = sys.argv[1]
		if num_args > 2:
			problem_file = sys.argv[2]
	else:
		#domain_file = 'domains/mini-indy-domain.pddl'
		#problem_file = 'domains/mini-indy-problem.pddl'
		domain_file = 'domains/ark-domain.pddl'
		problem_file = 'domains/ark-problem.pddl'

	#f = open('workfile', 'w')
	operators, objects, object_types, initAction, goalAction = parseDomAndProb(domain_file, problem_file)
	#non_static_preds = preprocessDomain(operators)
	FlawLib.non_static_preds = preprocessDomain(operators)
	obtypes = obTypesDict(object_types)

	Argument.object_types = obtypes
	planner = PlanSpacePlanner(operators, objects, initAction, goalAction)
	#planner.story_GL = GLib(operators, story_objs, obtypes, initAction, goalAction)

	results = planner.POCL(1)

	for result in results:
		totOrdering = topoSort(result)
		print('\n\n\n')
		for step in topoSort(result):
			print(Action.subgraph(result, step))
		#print(result)