def __init__(self, mdpsim_path='mdpsim-1.23/mdpsim', mgpt_path='mini-gpt/planner', planner: Planner = Planner.LRTDP, heuristic: Heuristic = Heuristic.FF, port=2323, max_time=10, **kwargs): """ Create a new PDDL planner object :param mgpt_path: the path to the mGPT executable :param planner: the type of planner to use. Default is LRTDP :param heuristic: the heuristic to use. Default is FF :param port: the port to run mdpsim on. It can be anything that is free :param max_time: the maximum time in seconds the planner is allowed. Default is 10 :param kwargs: allows user to specify additional mGPT settings """ if not exists(mgpt_path): raise ValueError("Could not find executable file at {}".format(mgpt_path)) if not exists(mdpsim_path): raise ValueError("Could not find executable file at {}".format(mdpsim_path)) # for item in kwargs: # if item != 'wsl' and item not in 'acdeimnprswz': # raise ValueError("Invalid argument {} for mGPT".format(item)) self._mdpsim_port = port self._use_wsl = kwargs.get('wsl', False) # use the windows subsystem for linux? self._mdpsim_path = mdpsim_path self._planner_path = mgpt_path self._planner = planner self._heuristic = heuristic self._max_time = max_time
def _create_temp_file(self, domain: Any, problem: Any, verbose=False) -> Tuple[str, str]: name = next(tempfile._get_candidate_names()) show("Generating temp PDDL file {}".format(name), verbose) if isinstance(domain, str): # it's a path to a file! if not exists(domain): raise ValueError( "Could not find PDDL file at {}".format(domain)) if not exists(problem): raise ValueError( "Could not find PDDL file at {}".format(problem)) with open(name, 'w') as temp_file, open(domain, 'r') as domain_file, open( problem, 'r') as problem_file: temp_file.write('{}\n\n{}'.format(domain_file.read(), problem_file.read())) problem_name = self._extract_problem_name(problem) return name, problem_name else: # it's the objects! with open(name, 'w') as temp_file: temp_file.write('{}\n\n{}'.format(domain, problem)) return name, problem.name
def find_plan(self, domain: Any, problem: Any, verbose=False) -> Tuple[bool, Any]: """ Given a path to the PDDL domain and problem file, determine if a plan can be found. We do this by spinning up mdpsim, then running mGPT, then shutting it all down! :param domain: the domain file :param problem: the problem file :param verbose: the verbosity level :return: the first boolean represents whether the files were valid PDDL, the second represents whether a plan could be found and a list of output from the planner """ # first, create a new file that has both the domain and problem in it. temp_name, problem_name = self._create_temp_file(domain, problem, verbose=verbose) command = ('wsl' if self._use_wsl else 'bash') p = None p2 = None try: show("Starting mdpsim...", verbose) # now run mdpsim with the temp file as input p = Popen( [command, self._mdpsim_path, '--port', '{}'.format(self._mdpsim_port), '--log-dir=/dev/null', '--warnings=1', temp_name ], stdout=PIPE, stderr=PIPE, universal_newlines=True ) # give it a second necessary? sleep(1) if p.poll(): # it finished! something bad must have happened std_out, std_err = p.communicate() if p.returncode != 0: error = self._extract_error(std_err, domain, problem) show("mdpsim failed to start with error: {}".format(error), verbose) return False, error show("mdpsim started!", verbose) show("Starting mGPT...", verbose) # it's running well! now start planner p2 = Popen( [command, self._planner_path, '-v', '100', '-p', self._planner.value, '-h', self._heuristic.value, 'localhost:{}'.format(self._mdpsim_port), temp_name, problem_name ], stdout=PIPE, stderr=PIPE, universal_newlines=True ) show("mGPT started! Waiting for output...", verbose) try: std_out, std_err = p2.communicate(timeout=self._max_time) output = PlanOutput(std_out) return True, output except subprocess.TimeoutExpired: return False, 'Timeout!' finally: os.remove(temp_name) if exists('last_id'): os.remove('last_id') # created by the planner and mdpsim if p: p.terminate() if p2: p2.terminate()