import { DQAgent } from "./algorithms/deepq/dqagent" ; import { Teacher , TeacherTrackingInformation , TeachingConfig } from "./teacher" ; import { v4 } from 'uuid' ; import { Model } from "./model" ; import { LearningDataLogger } from "./misc/learning_data_logger" ; import { DQAgentConfig } from "./algorithms/agent_config" ; const DEFAULT_ACADEMY_CONFIG = { parentLogsElement : null , agentsLogs : false , memoryLogs : false } ; /**
 * Academy configuration, used for logs. You need to say if you want to log agents and memory, and
 * give the parent <div> element
 */ export interface AcademyConfig { /** Parent <div> element, default to `null` */ parentLogsElement : HTMLElement ; /** If agents logs should be displayed, default to `false` */ agentsLogs : boolean ; /** If memory logs should be displayed, default to `false` */ memoryLogs : boolean ; } /**
 * Input to give at each step of the Academy, where you specify the target teacher and its inputs.
 */ export interface AcademyStepInput { teacherName : string ; agentsInput : number [ ] ; } /** Configuration to build an agent */ export interface BuildAgentConfig { /** The agent cannot have no model. But multiple agents can share the same one */ model : Model ; /** The agent configuration, defaulted if not present */ agentConfig ? : DQAgentConfig ; } /**
 * Class to interact with when creating the environment and updating it.
 */ export class Academy { private agents : Map < string , DQAgent > ; private teachers : Map < string , Teacher > ; private assigments : Map < string , string > ; private logger : LearningDataLogger ; private config : AcademyConfig ; constructor ( config ? ) { this . config = { ... DEFAULT_ACADEMY_CONFIG , ... config } ; this . agents = new Map < string , DQAgent > ( ) ; this . teachers = new Map < string , Teacher > ( ) ; this . assigments = new Map < string , string > ( ) ; if ( this . config . parentLogsElement ) { this . createLogger ( this . config . parentLogsElement ) ; } } addAgent ( config , name ? ) { let agent = new DQAgent ( config . model , config . agentConfig , name ) ; if ( ! agent . Name ) agent . Name = v4 ( ) ; this . agents . set ( agent . Name , agent ) ; return agent . Name ; } addTeacher ( config ? , name ? ) { let teacher = new Teacher ( config , name ) ; if ( ! teacher . Name ) teacher . Name = v4 ( ) ; this . teachers . set ( teacher . Name , teacher ) ; return teacher . Name ; } assignTeacherToAgent ( agentName , teacherName ) { if ( ! this . agents . has ( agentName ) ) throw new Error ( "No such agent has been registered" ) ; if ( ! this . teachers . has ( teacherName ) ) throw new Error ( "No such teacher has been registered" ) ; this . assigments . set ( agentName , teacherName ) ; this . teachers . get ( teacherName ) . affectStudent ( this . agents . get ( agentName ) ) ; } param { AcademyStepInput [ ] | AcademyStepInput } inputs returns { Promise < Map < string , number > > } async step ( inputs ) { let actions = new Map < string , number > ( ) ; let finalInput = inputs instanceof Array ? inputs : [ inputs ] ; for ( let input of finalInput ) { if ( ! this . teachers . has ( input . teacherName ) ) { throw new Error ( "No teacher has name " + input . teacherName ) ; } const agentsActions = await this . teachers . get ( input . teacherName ) . teach ( input . agentsInput ) ; agentsActions . forEach ( ( value , key ) => { if ( actions . has ( key ) ) throw new Error ( "Dqagent " + key + " has already registered an action." ) ; actions . set ( key , value ) ; } ) ; } if ( this . logger ) this . logger . updateTables ( true ) ; return actions ; } param { string } name param { number } reward addRewardToAgent ( name , reward ) { if ( this . agents . has ( name ) ) this . agents . get ( name ) . addReward ( reward ) ; } param { string } name param { number } reward setRewardOfAgent ( name , reward ) { if ( this . agents . has ( name ) ) this . agents . get ( name ) . setReward ( reward ) ; } param { string } teacherName param { ( teacher : string ) => void } callback constructor OnLearningLessonEnded ( teacherName , callback ) { if ( this . teachers . has ( teacherName ) ) this . teachers . get ( teacherName ) . onLearningLessonEnded = callback ; } param { string } teacherName param { ( teacher : string , lessonNumber : number ) => void } callback constructor OnLessonEnded ( teacherName , callback ) { if ( this . teachers . has ( teacherName ) ) this . teachers . get ( teacherName ) . onLessonEnded = callback ; } param { string } teacherName param { ( teacher : string , lessonNumber : number ) => void } callback constructor OnTeachingEnded ( teacherName , callback ) { if ( this . teachers . has ( teacherName ) ) this . teachers . get ( teacherName ) . onTeachingEnded = callback ; } /**
     * Function to reset everything from teachers and agents (resetting parameters of teachers, and resetting memory and parameters of agents).
     */ resetTeachersAndAgents ( ) { this . teachers . forEach ( t => t . reset ( ) ) ; this . agents . forEach ( a => a . reset ( ) ) ; } /**
     * Function resetting everything in the academy, calling first [[resetTeachersAndAgents]], then cleaning everything concerning teachers and agents.
     */ reset ( ) { this . resetTeachersAndAgents ( ) ; this . teachers . clear ( ) ; this . agents . clear ( ) ; } param { string } teacherName resetTeacherLesson ( teacherName ) { this . teachers . get ( teacherName ) . resetLesson ( ) ; } returns { string [ ] } constructor get Teachers ( ) { return Array . from ( this . teachers . keys ( ) ) ; } param { string } name returns { TeacherTrackingInformation } getTeacherData ( name ) { return this . teachers . get ( name ) . getData ( ) ; } param { HTMLElement } parent createLogger ( parent ) { if ( this . logger ) this . logger . dispose ( ) ; this . config . parentLogsElement = parent ; this . logger = new LearningDataLogger ( parent , this ) ; } param { boolean } memory toggleLogs ( memory = false ) { const status = this . config . agentsLogs ; this . config . agentsLogs = ! status ; if ( status ) this . config . memoryLogs = memory ; } toggleTeaching ( teacher , toggle ) { if ( toggle === true ) this . teachers . get ( teacher ) . startTeaching ( ) ; else this . teachers . get ( teacher ) . stopTeaching ( ) ; } }