planning with certainty ( ,cond, clinks[ select causal link rem_clinks clinks[ :remaining causal links if act ! and act ! and self deletes(act,cond)if self possible((act, ),constrs)new_const self add_constraint((act, ),constrsfor in self protect_all_cls(rem_clinks,act,new_const)yield if self possible(( ,act),constrs)new_const self add_constraint(( ,act),constrsfor in self protect_all_cls(rem_clinks,act,new_const)yield elsefor in self protect_all_cls(rem_clinks,act,constrs)yield elseyield constrs the following methods check whether an action (or action instanceachieves or deletes some subgoal stripspop py -(continued def achieves(self,action,subgoal)var,val subgoal return var in self effects(actionand self effects(action)[var=val def deletes(self,action,subgoal)var,val subgoal return var in self effects(actionand self effects(action)[var!val def effects(self,action)"""returns the variable:value dictionary of the effects of action works for both actions and action instances""if isinstance(actionaction_instance)action action action if action ="start"return self planning_problem initial_state elif action ="finish"return {elsereturn action effects the constraints are represented as set of pairs closed under transitivity thus if (aband (bcare the listthen (acmust also be in the list this means that adding new constraint means adding the implied pairsbut querying whether some order is consistent is quick stripspop py -(continued def add_constraint(selfpairconst)if pair in constversion june