[docs]classMaxEpisodesTerminationCondition(TerminationCondition):"""Checks whether a maximum number of episodes has been exceeded. This termination condition will only trigger on phase level. It uses the ``episodes`` key in the phase configuration to check whether a maximum number of episodes has been reached. Examples -------- Consider the following experiment phase definition:: schedule: Training: phase_config: mode: train worker: 2 episodes: 100 simulation: conditions: - name: palaestrai.experiment:MaxEpisodesTerminationCondition params: {} name: palaestrai.simulation:TakingTurns run_config: condition: name: palaestrai.experiment:MaxEpisodesTerminationCondition params: {} Then, the phase would end when both workers (``worker: 2``) have reached 100 episodes (``episodes: 100``). """defphase_flow_control(self,run_governor:RunGovernor,message:SimulationControllerTerminationRequest,)->Tuple[SimulationFlowControl,Any]:ifnotisinstance(message,SimulationControllerTerminationRequest):returnSimulationFlowControl.CONTINUE,Noneifrun_governor.experiment_runisNone:LOG.warning("MaxEpisodesTerminationCondition cannot control flow: ""Run governor has no experiment run object!")returnSimulationFlowControl.CONTINUE,Nonetry:max_episodes=run_governor.experiment_run.get_episodes(run_governor.current_phase)worker=run_governor.experiment_run.get_worker(run_governor.current_phase)evaluate_every=run_governor.experiment_run.get_evaluate_every(run_governor.current_phase)assertmax_episodesisnotNoneassertworkerisnotNonesum_max_episodes=max_episodes*workerevaluations=Noneifevaluate_everyisnotNone:evaluations=(sum_max_episodes//evaluate_every)*workersum_max_episodes+=evaluationsexceptKeyError:# If the current phase does not define a phase limit, we can# continue indefinitely.returnSimulationFlowControl.CONTINUE,None# Not continuing, thus at least the episode is done# (the current_episode_counts will be calculated in the RunGovernor)# so calculate to STOP_PHASE or to only STOP_SIMULATIONnew_episode_counts=copy.deepcopy(run_governor.current_episode_counts)new_episode_counts[message.sender]+=1# If all SCs have reached the max number of episodes, indicate end of# the phase:ifsum(new_episode_counts.values())>=sum_max_episodes:ifnotall(x>=max_episodesforsc_name,xinnew_episode_counts.items()ifnotsc_name.endswith("-EVALUATE")):LOG.error("%s computed STOP_PHASE, ""but not all SimulationControllers are done with their episodes! ""(current_episode_counts: %s, sum_max_episodes: %s, max_episodes: %s, mode: %s)",self,new_episode_counts,sum_max_episodes,max_episodes,message.mode,stack_info=True,)sum_evaluations=sum([xforsc_name,xinnew_episode_counts.items()ifsc_name.endswith("-EVALUATE")])ifevaluationsisnotNone:ifevaluations>sum_evaluations:LOG.error("%s computed STOP_PHASE, but not all evaluations were performed!",self,)elifevaluations<sum_evaluations:LOG.error("%s noticed internal error: Too many evaluations were performed!",self,)returnSimulationFlowControl.STOP_PHASE,None# If only the current one, indicate shutdown of the current simulation# controller:sc_uid=message.senderifsc_uid.endswith("-EVALUATE"):assertrun_governor.max_eval_episodesisnotNoneifrun_governor.max_eval_episodes<=0:LOG.error("Internal error: Max eval episodes should be calculated when ""evaluation workers are present and MaxEpisodesTerminationCondition is applied!")ifnew_episode_counts[sc_uid]<run_governor.max_eval_episodes:returnSimulationFlowControl.RESTART,Noneifnew_episode_counts[sc_uid]>=run_governor.max_eval_episodes:returnSimulationFlowControl.STOP_SIMULATION,Noneifnew_episode_counts[sc_uid]>=max_episodes:returnSimulationFlowControl.STOP_SIMULATION,None# Default casereturnSimulationFlowControl.CONTINUE,None