def determinize(self, name_suffix=0): """Create a deterministic operators with the most likely effects """ op_name = "{}{}".format(self.action.predicate.name, name_suffix) probs, effs = self.effect_probs, self.effects max_idx = np.argmax(probs) max_effects = LiteralConjunction(sorted(effs[max_idx])) preconds = LiteralConjunction( sorted(self.preconditions) + [self.action]) params = sorted( {v for lit in preconds.literals for v in lit.variables}) return Operator(op_name, params, preconds, max_effects)
def create_goal(domain, objects, pile_heights): on = domain.predicates['on'] ontable = domain.predicates['ontable'] remaining_blocks = sorted(objects) goal_lits = [] for pile_height in pile_heights: assert 2 < pile_height block_idxs = np.random.choice(len(remaining_blocks), size=pile_height, replace=False) blocks_in_pile = [] for idx in block_idxs: blocks_in_pile.append(remaining_blocks[idx]) remaining_blocks = [ b for i, b in enumerate(remaining_blocks) if i not in block_idxs ] # left is top for b1, b2 in zip(blocks_in_pile[:-1], blocks_in_pile[1:]): goal_lits.append(on(b1, b2)) goal_lits.append(ontable(blocks_in_pile[-1])) return LiteralConjunction(goal_lits)
def create_goal(domain, objects): place_type = domain.types['place'] presentationdoneat = domain.predicates['presentationdoneat'] workedoutat = domain.predicates['workedoutat'] hikedat = domain.predicates['hikedat'] swamat = domain.predicates['swamat'] goal_lits = [] while len(goal_lits) == 0: for obj in [o for o in objects if o.var_type == place_type]: if obj.startswith("office") and np.random.random() < 0.25: goal_lits.append(presentationdoneat(obj)) elif obj.startswith("gym") and np.random.random() < 0.25: goal_lits.append(workedoutat(obj)) elif obj.startswith("forest") and np.random.random() < 0.25: goal_lits.append(hikedat(obj)) elif obj.startswith("beach") and np.random.random() < 0.25: goal_lits.append(swamat(obj)) max_num_goal_lits = np.random.randint(1, 4) if len(goal_lits) > max_num_goal_lits: np.random.shuffle(goal_lits) goal_lits = goal_lits[:max_num_goal_lits] return LiteralConjunction(goal_lits)
def create_goal(domain, people, hospital_loc, num_selected_people=1): person_at = domain.predicates['person-at'] goal_lits = [] selected_people = np.random.choice(people, size=num_selected_people, replace=False) for person in selected_people: goal_lits.append(person_at(person, hospital_loc)) return LiteralConjunction(goal_lits)
def _create_preconds_pddl_str(self, preconds): all_params = set() precond_strs = [] if isinstance(preconds, Literal): preconds = LiteralConjunction([preconds]) for term in preconds.literals: params = set(map(str, term.variables)) if hasattr(term, 'negated_as_failure') and term.negated_as_failure: # Negative term. The variables to universally # quantify over are those which we have not # encountered yet in this clause. universally_quantified_vars = list(sorted(params - all_params)) precond = "" for var in universally_quantified_vars: precond += "(forall ({}) ".format(var.replace(":", " - ")) precond += "(or " for var in universally_quantified_vars: var_cleaned = "?" + var[:var.find(":")] for param in list(sorted(all_params)): param_cleaned = "?" + param[:param.find(":")] precond += "(not (Different {} {})) ".format( param_cleaned, var_cleaned) precond += "(not {}))".format(term.positive.pddl_str()) for var in universally_quantified_vars: precond += ")" precond_strs.append(precond) else: # Positive term. all_params.update(params) precond_strs.append(term.pddl_str()) return "\n\t\t\t".join(precond_strs)
def parse_goal(board, types, predicates): all_preds = [ predicates["at-goal"]( *[TypedEntity("stone-{}".format(i), types['thing'])]) for i, _ in enumerate(board.boxes) ] return LiteralConjunction(all_preds)
def sample_problem(domain, problem_dir, problem_outfile, num_locs, min_extra_papers=1, max_extra_papers=10): loc_type = domain.types['loc'] paper_type = domain.types['paper'] at = domain.predicates['at'] isHomeBase = domain.predicates['ishomebase'] wantsPaper = domain.predicates['wantspaper'] unpacked = domain.predicates['unpacked'] satisfied = domain.predicates['satisfied'] # Create objects and state state = set() objects = set() home_loc = None target_locs = [] # Add locations for loc_idx in range(num_locs): loc = loc_type(f"loc-{loc_idx}") objects.add(loc) # home if loc_idx == 0: state.add(isHomeBase(loc)) state.add(at(loc)) home_loc = loc # wants paper else: state.add(wantsPaper(loc)) target_locs.append(loc) # Add papers num_papers = num_locs + np.random.randint(min_extra_papers, max_extra_papers + 1) for paper_idx in range(num_papers): paper = paper_type(f"paper-{paper_idx}") objects.add(paper) state.add(unpacked(paper)) # Create goal goal_lits = [satisfied(loc) for loc in target_locs] goal = LiteralConjunction(goal_lits) filepath = os.path.join(PDDLDIR, problem_dir, problem_outfile) PDDLProblemParser.create_pddl_file( filepath, objects=objects, initial_state=state, problem_name="newspaper", domain_name=domain.domain_name, goal=goal, fast_downward_order=True, ) print("Wrote out to {}.".format(filepath))
def create_goal(domain, balls, rooms, num_balls): at = domain.predicates['at'] goal_balls = [balls[i] for i in np.random.choice(len(balls), replace=False, size=num_balls)] goal_lits = [] for ball in goal_balls: room = rooms[np.random.choice(len(rooms))] goal_lits.append(at(ball, room)) return LiteralConjunction(goal_lits)
def _foldt_to_operators(self, dt, action_name, suffix=''): op_counter = 0 operators = set() for (path, leaf) in dt.get_conditional_literals(dt.root): if leaf is None: continue if any(lit.predicate == Effect(self._NoChange) for lit in leaf): continue name = "LearnedOperator{}{}{}".format(action_name, op_counter, suffix) op_counter += 1 # NoChange appears only in effects in the training data, so it # should never be in the preconditions of the learned operators. assert not any(lit.predicate.positive == self._NoChange for lit in path) preconds = LiteralConjunction(path) effects = LiteralConjunction([effect_to_literal(l) for l in leaf]) params = self._get_params_from_preconds(preconds) operator = Operator(name, params, preconds, effects) operators.add(operator) return operators
def _replace_predicate(cls, conds, from_pred, to_pred): if isinstance(conds, list): return [cls._replace_predicate(c, from_pred, to_pred) for c in conds] if isinstance(conds, Literal): if conds.predicate == from_pred: return to_pred(*conds.variables) return conds if isinstance(conds, LiteralConjunction): return LiteralConjunction(cls._replace_predicate(conds.literals, from_pred, to_pred)) if isinstance(conds, LiteralDisjunction): return LiteralDisjunction(cls._replace_predicate(conds.literals, from_pred, to_pred)) if isinstance(conds, ForAll): assert not conds.is_negative, "Negative universal quantification not implemented (use Exists instead)" return ForAll(cls._replace_predicate(conds.body, from_pred, to_pred), conds.variables, is_negative=conds.is_negative) if isinstance(conds, Exists): assert not conds.is_negative, "Negative exisential quantification not implemented (use ForAll instead)" return Exists(conds.variables,cls._replace_predicate(conds.body, from_pred, to_pred), is_negative=conds.is_negative) import ipdb; ipdb.set_trace() raise NotImplementedError()
def create_problem(grid, domain, problem_dir, problem_outfile): # Create location objects loc_type = domain.types['loc'] objects = set() grid_locs = np.empty(grid.shape, dtype=object) for r in range(grid.shape[0]): for c in range(grid.shape[1]): obj = loc_type(f'r{r}_c{c}') objects.add(obj) grid_locs[r, c] = obj initial_state = set() # Add at, isWater, isHill, isGoal at = domain.predicates['at'] isWater = domain.predicates['iswater'] isHill = domain.predicates['ishill'] isGoal = domain.predicates['isgoal'] for r in range(grid.shape[0]): for c in range(grid.shape[1]): obj = grid_locs[r, c] if grid[r, c] == I: initial_state.add(at(obj)) elif grid[r, c] == W: initial_state.add(isWater(obj)) elif grid[r, c] == H: initial_state.add(isHill(obj)) elif grid[r, c] == G: initial_state.add(isGoal(obj)) # Add adjacent adjacent = domain.predicates['adjacent'] def get_neighbors(r, c): for dr, dc in [(-1, 0), (1, 0), (0, -1), (0, 1)]: nr = r + dr nc = c + dc if 0 <= nr < grid.shape[0] and 0 <= nc < grid.shape[1]: yield (nr, nc) for r in range(grid.shape[0]): for c in range(grid.shape[1]): obj = grid_locs[r, c] for (nr, nc) in get_neighbors(r, c): nobj = grid_locs[nr, nc] initial_state.add(adjacent(obj, nobj)) # Add onTrail onTrail = domain.predicates['ontrail'] # Get the path path = [] r, c = np.argwhere(grid == I)[0] while True: path.append((r, c)) if grid[r, c] == G: break for (nr, nc) in get_neighbors(r, c): if (nr, nc) in path: continue if grid[nr, nc] in [P, G, H]: r, c = nr, nc break else: raise Exception("Should not happen") for (r, c), (nr, nc) in zip(path[:-1], path[1:]): obj = grid_locs[r, c] nobj = grid_locs[nr, nc] initial_state.add(onTrail(obj, nobj)) # Goal goal_rcs = np.argwhere(grid == G) assert len(goal_rcs) == 1 goal_r, goal_c = goal_rcs[0] goal_obj = grid_locs[goal_r, goal_c] goal = LiteralConjunction([at(goal_obj)]) filepath = os.path.join(PDDLDIR, problem_dir, problem_outfile) PDDLProblemParser.create_pddl_file( filepath, objects=objects, initial_state=initial_state, problem_name="hiking", domain_name=domain.domain_name, goal=goal, fast_downward_order=True, ) print("Wrote out to {}.".format(filepath))
def _parse_into_literal(self, string, params, is_effect=False): """Parse the given string (representing either preconditions or effects) into a literal. Check against params to make sure typing is correct. """ assert string[0] == "(" assert string[-1] == ")" if string.startswith("(and") and string[4] in (" ", "\n", "("): clauses = self._find_all_balanced_expressions(string[4:-1].strip()) return LiteralConjunction([ self._parse_into_literal(clause, params, is_effect=is_effect) for clause in clauses ]) if string.startswith("(or") and string[3] in (" ", "\n", "("): clauses = self._find_all_balanced_expressions(string[3:-1].strip()) return LiteralDisjunction([ self._parse_into_literal(clause, params, is_effect=is_effect) for clause in clauses ]) if string.startswith("(forall") and string[7] in (" ", "\n", "("): new_binding, clause = self._find_all_balanced_expressions( string[7:-1].strip()) new_name, new_type_name = new_binding.strip()[1:-1].split("-") new_name = new_name.strip() new_type_name = new_type_name.strip() assert new_name not in params, "ForAll variable {} already exists".format( new_name) params[new_name] = self.types[new_type_name] result = ForAll( self._parse_into_literal(clause, params, is_effect=is_effect), TypedEntity(new_name, params[new_name])) del params[new_name] return result if string.startswith("(exists") and string[7] in (" ", "\n", "("): new_binding, clause = self._find_all_balanced_expressions( string[7:-1].strip()) if new_binding[1:-1] == "": # Handle existential goal with no arguments. body = self._parse_into_literal(clause, params, is_effect=is_effect) return body variables = self._parse_objects(new_binding[1:-1]) for v in variables: params[v.name] = v.var_type body = self._parse_into_literal(clause, params, is_effect=is_effect) result = Exists(variables, body) for v in variables: del params[v.name] return result if string.startswith("(probabilistic") and string[14] in (" ", "\n", "("): assert is_effect, "We only support probabilistic effects" lits = [] probs = [] expr = string[14:-1].strip() for match in re.finditer("(\d*\.?\d+)", expr): prob = float(match.group()) subexpr = self._find_balanced_expression( expr[match.end():].strip(), 0) lit = self._parse_into_literal(subexpr, params, is_effect=is_effect) lits.append(lit) probs.append(prob) return ProbabilisticEffect(lits, probs) if string.startswith("(not") and string[4] in (" ", "\n", "("): clause = string[4:-1].strip() if is_effect: return Anti( self._parse_into_literal(clause, params, is_effect=is_effect)) else: return Not( self._parse_into_literal(clause, params, is_effect=is_effect)) string = string[1:-1].split() pred, args = string[0], string[1:] typed_args = [] # Validate types against the given params dict. assert pred in self.predicates, "Predicate {} is not defined".format( pred) assert self.predicates[pred].arity == len(args), pred for i, arg in enumerate(args): if arg not in params: raise Exception("Argument {} not in params {}".format( arg, params)) assert arg in params, "Argument {} is not in the params".format( arg) if isinstance(params, dict): typed_arg = TypedEntity(arg, params[arg]) else: typed_arg = params[params.index(arg)] typed_args.append(typed_arg) return self.predicates[pred](*typed_args)
def _parse_into_literal(self, string, params, is_effect=False): """Parse the given string (representing either preconditions or effects) into a literal. Check against params to make sure typing is correct. """ assert string[0] == "(" assert string[-1] == ")" if string.startswith("(and") and string[4] in (" ", "\n", "("): clauses = self._find_all_balanced_expressions(string[4:-1].strip()) return LiteralConjunction([ self._parse_into_literal(clause, params, is_effect=is_effect) for clause in clauses ]) if string.startswith("(or") and string[3] in (" ", "\n", "("): clauses = self._find_all_balanced_expressions(string[3:-1].strip()) return LiteralDisjunction([ self._parse_into_literal(clause, params, is_effect=is_effect) for clause in clauses ]) if string.startswith("(forall") and string[7] in (" ", "\n", "("): new_binding, clause = self._find_all_balanced_expressions( string[7:-1].strip()) new_name, new_type_name = new_binding.strip()[1:-1].split("-") new_name = new_name.strip() new_type_name = new_type_name.strip() assert new_name not in params, "ForAll variable {} already exists".format( new_name) params[new_name] = self.types[new_type_name] result = ForAll( self._parse_into_literal(clause, params, is_effect=is_effect), TypedEntity(new_name, params[new_name])) del params[new_name] return result if string.startswith("(exists") and string[7] in (" ", "\n", "("): new_binding, clause = self._find_all_balanced_expressions( string[7:-1].strip()) variables = self._parse_objects(new_binding[1:-1]) for v in variables: params[v.name] = v.var_type body = self._parse_into_literal(clause, params, is_effect=is_effect) result = Exists(variables, body) for v in variables: del params[v.name] return result if string.startswith("(not") and string[4] in (" ", "\n", "("): clause = string[4:-1].strip() if is_effect: return Anti( self._parse_into_literal(clause, params, is_effect=is_effect)) else: return Not( self._parse_into_literal(clause, params, is_effect=is_effect)) string = string[1:-1].split() pred, args = string[0], string[1:] # Validate types against the given params dict. assert pred in self.predicates, "Predicate {} is not defined".format( pred) assert self.predicates[pred].arity == len(args), pred for i, arg in enumerate(args): if arg not in params: import ipdb ipdb.set_trace() assert arg in params, "Argument {} is not in the params".format( arg) return self.predicates[pred](*args)
def _state_to_internal(self, state): state = dict(state) new_state_literals = set() directions_to_deltas = { self.direction_type('up') : (-1, 0), self.direction_type('down') : (1, 0), self.direction_type('left') : (0, -1), self.direction_type('right') : (0, 1), } # conn height, width = 6, 6 for r in range(height): for c in range(width): loc = self.location_type(f"f{r}-{c}f") for direction, (dr, dc) in directions_to_deltas.items(): next_r, next_c = r + dr, c + dc if not (0 <= next_r < height and 0 <= next_c < width): continue next_loc = self.location_type(f"f{next_r}-{next_c}f") conn_lit = self.conn(loc, next_loc, direction) new_state_literals.add(conn_lit) # at occupied_locs = set() hospital_loc = None for obj_name, loc_tup in state.items(): if obj_name in ["carrying", "rescue"]: continue r, c = loc_tup loc = self.location_type(f"f{r}-{c}f") if obj_name.startswith("person"): at_pred = self.person_at elif obj_name.startswith("robot"): at_pred = self.robot_at occupied_locs.add((r, c)) elif obj_name.startswith("wall"): at_pred = self.wall_at occupied_locs.add((r, c)) elif obj_name.startswith("hospital"): at_pred = self.hospital_at assert hospital_loc is None hospital_loc = loc else: raise Exception(f"Unrecognized object {obj_name}") new_state_literals.add(at_pred(obj_name, loc)) assert hospital_loc is not None # carrying/handsfree if state["carrying"] is None: new_state_literals.add(self.handsfree("robot0")) else: new_state_literals.add(self.carrying("robot0", state["carrying"])) # clear for r in range(height): for c in range(width): if (r, c) not in occupied_locs: loc = self.location_type(f"f{r}-{c}f") clear_lit = self.clear(loc) new_state_literals.add(clear_lit) # objects new_objects = frozenset({o for lit in new_state_literals for o in lit.variables }) # goal new_goal = LiteralConjunction([self.person_at(person, hospital_loc) \ for person in sorted(state["rescue"])]) new_state = State(frozenset(new_state_literals), new_objects, new_goal) return new_state
def find_ff_replan_policy(ndr_operators, action_space, observation_space): # First pull out the most likely effect per NDR to form # deterministic operators deterministic_operators = [] for ndr_list in ndr_operators.values(): for i, ndr in enumerate(ndr_list): op_name = "{}{}".format(ndr.action.predicate.name, i) probs, effs = ndr.effect_probs, ndr.effects max_idx = np.argmax(probs) max_effects = LiteralConjunction(sorted(effs[max_idx])) if len(max_effects.literals ) == 0 or NOISE_OUTCOME in max_effects.literals: continue preconds = LiteralConjunction( sorted(ndr.preconditions) + [ndr.action]) params = sorted( {v for lit in preconds.literals for v in lit.variables}) operator = Operator(op_name, params, preconds, max_effects) deterministic_operators.append(operator) domain_name = "mydomain" planner = FastForwardPlanner(deterministic_operators, domain_name, action_space, observation_space) # Only replan if outcome is not expected expected_next_state = None plan = [] def get_next_expected_state(state, action): return ndr_operators[action.predicate].predict_max(state, action) # Given a state, replan and execute first section in plan def policy(obs): nonlocal expected_next_state nonlocal plan state = obs.literals goal = obs.goal objects = obs.objects if False: #len(plan) > 0: expected_next_state = get_next_expected_state(state, plan[0]) return plan.pop(0) # Add possible actions to state full_state = set(state) full_state.update(action_space.all_ground_literals(obs)) # Create problem file fname = '/tmp/problem.pddl' PDDLProblemParser.create_pddl_file(fname, objects, full_state, "myproblem", domain_name, goal) # Get plan print("goal:", goal) try: plan = planner.get_plan(fname, use_cache=False) print("plan:", plan) except NoPlanFoundException: # Default to random print("no plan found") return action_space.sample(obs) # Updated expected next state expected_next_state = get_next_expected_state(state, plan[0]) return plan.pop(0) return policy