Compare commits

..

5 Commits

  1. 47
      css/src/style.scss
  2. 77
      css/style.css
  3. 2
      css/style.min.css
  4. BIN
      img/robot.png
  5. BIN
      img/station.png
  6. 83
      index.html
  7. 2
      js/controls.js
  8. 37
      js/rl.js
  9. 915
      js/view.js

@ -1,8 +1,11 @@
// compileCompressed
*{ *{
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
body{ body{
margin: 0;
padding: 0;
// background-color: ; // background-color: ;
font-family: sans-serif; font-family: sans-serif;
} }
@ -13,17 +16,30 @@ body{
#canvas{ #canvas{
height: 100%; height: 100%;
} }
nav{ nav{
position: absolute; position: absolute;
top: 10px; top: 10px;
left: 10px; left: 10px;
} }
button{
margin: 0.3em;
}
.absolute{ .absolute{
position: absolute; position: absolute;
top:0; top:0;
left:0; left:0;
} }
.stage{
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.plot{ .plot{
position: absolute; position: absolute;
top: 2vh; top: 2vh;
@ -33,9 +49,38 @@ nav{
} }
.sliders{ .sliders{
position: absolute;
top: 20vh;
left: 2vw;
width: 20vw;
}
#formula{
position: absolute;
top: 71.5vh;
width: 90vw;
}
.score{
position: absolute; position: absolute;
top: 7vh; top: 7vh;
left: 2vw; left: 2vw;
width: 20vw; width: 20vw;
height: 10vw; }
.lightbox{
padding: 2em;
position: absolute;
top:0;
left: 50%;
transform: translateX(-50%) translateY(-100%);
z-index: 10;
max-width: 50%;
background-color: #BBB;
transition: all 1s;
&.active{
top:20%;
transform: translateX(-50%) translateY(-50%);
}
} }

@ -0,0 +1,77 @@
* {
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
#container {
height: 100vh;
position: relative;
}
#canvas {
height: 100%;
}
nav {
position: absolute;
top: 10px;
left: 10px;
}
.absolute {
position: absolute;
top: 0;
left: 0;
}
.plot {
position: absolute;
top: 2vh;
right: 2vw;
width: 20vw;
height: 10vw;
}
.sliders {
position: absolute;
top: 20vh;
left: 2vw;
width: 20vw;
}
#formula {
position: absolute;
top: 71.5vh;
width: 90vw;
}
.score {
position: absolute;
top: 7vh;
left: 2vw;
width: 20vw;
}
.lightbox {
padding: 2em;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%) translateY(-100%);
z-index: 10;
width: 50%;
height: 40%;
background-color: #BBB;
transition: all 1s;
}
.lightbox.active {
top: 50%;
transform: translateX(-50%) translateY(-50%);
}

2
css/style.min.css vendored

@ -1 +1 @@
*{margin:0;padding:0}body{font-family:sans-serif}#container{height:100vh;position:relative}#canvas{height:100%}nav{position:absolute;top:10px;left:10px}.absolute{position:absolute;top:0;left:0}.plot{position:absolute;top:2vh;right:2vw;width:20vw;height:10vw}.sliders{position:absolute;top:7vh;left:2vw;width:20vw;height:10vw} *{margin:0;padding:0}body{margin:0;padding:0;font-family:sans-serif}#container{height:100vh;position:relative}#canvas{height:100%}nav{position:absolute;top:10px;left:10px}button{margin:0.3em}.absolute{position:absolute;top:0;left:0}.stage{display:flex;justify-content:center;align-items:center;height:100vh}.plot{position:absolute;top:2vh;right:2vw;width:20vw;height:10vw}.sliders{position:absolute;top:20vh;left:2vw;width:20vw}#formula{position:absolute;top:71.5vh;width:90vw}.score{position:absolute;top:7vh;left:2vw;width:20vw}.lightbox{padding:2em;position:absolute;top:0;left:50%;transform:translateX(-50%) translateY(-100%);z-index:10;max-width:50%;background-color:#BBB;transition:all 1s}.lightbox.active{top:20%;transform:translateX(-50%) translateY(-50%)}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script> <script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script>
<script src='https://unpkg.com/vue/dist/vue.js'></script> <script src='https://unpkg.com/vue/dist/vue.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/vue-konva@2.0.11/umd/vue-konva.min.js'></script> <script src='https://cdn.jsdelivr.net/npm/vue-konva@2.0.11/umd/vue-konva.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
@ -15,61 +15,50 @@
<!-- The loading of KaTeX is deferred to speed up page rendering --> <!-- The loading of KaTeX is deferred to speed up page rendering -->
<script src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" integrity="sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" integrity="sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz" crossorigin="anonymous"></script>
<title>RL exhibit - prototype</title> <title>RL exhibit - prototype</title>
<link rel="stylesheet" href="https://gitcdn.xyz/cdn/jzilg/embellish.css/fff9961c5fec2d1c8ff53c87b12e18d5c8db7761/embellish.min.css">
<link rel="stylesheet" href="css/style.min.css"> <link rel="stylesheet" href="css/style.min.css">
</head> </head>
<body> <body>
<div id="app"> <div id="app">
<v-stage ref="stage" :config="stage_config"> <rl-local class="stage" :machine="machine" :maze="maze" :config="stage_config" v-show="isActive('local')"></rl-local>
<!-- <v-layer ref="local_layer" :config="local_layer">
<v-group ref="map_group" :config="map_config"> <rl-map class="stage" :machine="machine" :maze="maze" :config="stage_config" v-show="isActive('global')"></rl-map>
<v-rect v-for="(t_type, idx) in maze.map.flat()" :config="get_tile_config(idx, t_type, true)" :key="idx"></v-rect>
<v-regular-polygon :config="agent_config"></v-regular-polygon> <line-chart css-classes="plot" :chart-data="datacollection" :options="plot_options" v-show="isActive('plot')"></line-chart>
</v-group>
</v-layer> --> <div class="sliders" v-show="isActive('sliders')">
<v-layer ref="map_layer"> <h1>Learning Rate {{machine.learning_rate}}</h1>
<v-group ref="mini_map_group" :config="mini_map_config"> <vue-slider v-model="machine.learning_rate" :drag-on-click="true" v-bind="slider_config"></vue-slider>
<!-- <v-group ref="grid_group"> <h1>Discount Factor {{machine.discount_factor}}</h1>
<v-line v-for="y in maze.height+1" :config="get_grid_line_config(y-1, true)"></v-line> <vue-slider v-model="machine.discount_factor" :drag-on-click="true" v-bind="slider_config"></vue-slider>
<v-line v-for="x in maze.width+1" :config="get_grid_line_config(x-1)"></v-line> <h1>Epsilon {{machine.epsilon}}</h1>
</v-group> --> <vue-slider v-model="machine.epsilon" :drag-on-click="true" v-bind="slider_config"></vue-slider>
<v-rect v-for="(t_type, idx) in maze.map.flat()" :config="get_tile_config(idx, t_type)" :key="idx" ></v-rect> <div id="formula"></div>
<v-group v-for="(action,idx) in q_table" :config="get_field_config(idx)">
<v-shape v-for="(value, key) in action" :config="get_triangle_config(value, key)"></v-shape>
<v-text v-for="i in 4" :config="get_q_text_config(action,i)"></v-text>
</v-group>
<v-regular-polygon :config="agent_config"></v-regular-polygon>
</v-group>
</v-layer>
</v-stage>
<line-chart css-classes="plot" :chart-data="datacollection" :options="plot_options"></line-chart>
<div class="sliders">
<h1>Learning Rate {{learning_rate}}</h1>
<vue-slider v-model="learning_rate" :drag-on-click="true" v-bind="slider_config"></vue-slider>
<h1>Discount Factor {{discount_factor}}</h1>
<vue-slider v-model="discount_factor" :drag-on-click="true" v-bind="slider_config"></vue-slider>
<h1>Epsilon {{epsilon}}</h1>
<vue-slider v-model="epsilon" :drag-on-click="true" v-bind="slider_config"></vue-slider>
<h1>Current Score</h1>
<h2>{{score}}</h2>
<div id="test" style="position: absolute;bottom: 10vh;width:90vw"></div>
</div> </div>
<div class="score" v-show="isActive('score')">
<h1>Current Energy</h1>
<h2>{{machine.score}}</h2>
</div>
<navi-gation :options="navigation" v-show="isActive('navi')"></navi-gation>
</div> </div>
<nav>
<button class="button" onclick="machine.run(1)">run 1 episode!</button>
<button class="button" onclick="machine.run(100)">run 100 episodes!</button>
<button class="button" onclick="machine.auto_step();">auto step!</button>
<button class="button" onclick="machine.greedy_step();">greedy step!</button>
<button class="button" onclick="machine.reset_machine()">reset machine</button>
</nav>
<script> <script>
var map = [ var map = [
[0, 0, 1, 8, 0, 0, 0, 0], [0, 0, 1, 8, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
[1, 0, 0, 0, 0, 1, 0, 1], [1, 0, 0, 0, 0, 1, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[2, 0, 1, 0, 1, 0, 0, 1] [0, 1, 1, 1, 1, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[1, 0, 1, 0, 0, 0, 0, 1, 1, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[2, 0, 0, 0, 1, 0, 1, 0, 0, 1]
]; ];
</script> </script>
<script src="js/rl.js"></script> <script src="js/rl.js"></script>

2
js/controls.js vendored

@ -27,7 +27,7 @@ function key_callback(e) {
break; break;
} }
var ret = 1; var ret = 1;
if (tmp != undefined){ if (tmp != undefined && document.querySelector(".lightbox.active") == null){
ret = machine.step(tmp); ret = machine.step(tmp);
} }
// show_q_table(); // show_q_table();

@ -4,6 +4,7 @@ class RL_machine {
rewards, rewards,
start_state, start_state,
end_states, end_states,
start_score,
end_score, end_score,
learning_rate, learning_rate,
discount_factor, discount_factor,
@ -14,11 +15,16 @@ class RL_machine {
this.lr = learning_rate; this.lr = learning_rate;
this.df = discount_factor; this.df = discount_factor;
this.start_state = start_state; this.start_state = start_state;
this.start_score = start_score;
this.end_score = end_score; this.end_score = end_score;
this.end_states = end_states; this.end_states = end_states;
this.epsilon = epsilon; this.epsilon = epsilon;
this.q_table = this.actions_per_state.map((c) => c.reduce((o,n) => {o[n]=0; return o},{})); this.q_table = this.actions_per_state.map((c) => c.reduce((o,n) => {o[n]=0; return o},{}));
this.reset_machine(); this.reset_machine();
this.callback = null;
}
setCallback(cb){
this.callback = cb;
} }
reset_machine(){ reset_machine(){
for (var q in this.q_table){ for (var q in this.q_table){
@ -27,17 +33,24 @@ class RL_machine {
} }
} }
this.episode = 0; this.episode = 0;
this.state = this.start_state;
this.score = 0;
this.running = false; this.running = false;
this.score_history = []; this.score_history = [];
this.state = this.start_state;
this.score = this.start_score;
} }
new_episode(){ new_episode(reason = "failed"){
const reset = () => {
this.episode++;
this.score_history.push(this.score);
this.state = this.start_state;
this.score = this.start_score;
}
// add_new_episode_callback // add_new_episode_callback
this.episode++; if (!this.running && this.callback) {
this.state = this.start_state; this.callback(reason).then((p) => reset());
this.score_history.push(this.score); } else {
this.score = 0; reset();
}
} }
auto_step(){ auto_step(){
if (Math.random() < this.epsilon){ if (Math.random() < this.epsilon){
@ -52,8 +65,12 @@ class RL_machine {
step(action){ step(action){
this.state = this.update_q_table(this.state, action); this.state = this.update_q_table(this.state, action);
// add_new_step_callback // add_new_step_callback
if (this.end_states.indexOf(this.state) >= 0 || this.score < this.end_score){ if (this.end_states.indexOf(this.state) >= 0) {
this.new_episode(); this.new_episode("success");
return 2
}
if (this.score <= this.end_score){
this.new_episode("failed");
return 2 return 2
} }
return 1 return 1
@ -191,4 +208,4 @@ var maze = new Maze(map, reward);
var learning_rate = 0.75; var learning_rate = 0.75;
var discount_factor = 0.8; var discount_factor = 0.8;
var machine = new RL_machine(maze.actions, maze.transactions, maze.rewards, maze.start_state, maze.end_states, -999, learning_rate, discount_factor, 0.2); var machine = new RL_machine(maze.actions, maze.transactions, maze.rewards, maze.start_state, maze.end_states, 50, 0, learning_rate, discount_factor, 0.2);

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save