Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 1 addition & 19 deletions 4-Beyond-Classical-Search/c_hillClimbing.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
var colors = {
hill: 'hsl(217,30%,70%)',
maxima: 'hsl(110,100%,75%)',
unvisitedMaxima: 'hsl(110,100%,50%)',
GMRA: 'hsl(110,25%,60%)'
};

class HillDiagram {
constructor(hill, svg, h, w) {
this.padding = 20;
Expand Down Expand Up @@ -265,7 +258,7 @@ $(document).ready(function() {
svgRects.transition()
.duration(200)
.style('opacity', 1)
.style('class', (d) => {
.attr('class', (d) => {
if (d.maxima) {
return 'hill-maxima';
} else {
Expand All @@ -275,17 +268,6 @@ $(document).ready(function() {
return 'hill';
}
}
})
.style('fill', (d) => {
if (d.maxima) {
return colors.maxima;
} else {
if (d.isGMRA) {
return colors.GMRA;
} else {
return colors.hill;
}
}
});
}

Expand Down
197 changes: 117 additions & 80 deletions 4-Beyond-Classical-Search/c_simulatedAnnealing.js
Original file line number Diff line number Diff line change
@@ -1,82 +1,119 @@
$(document).ready(function(){
$.ajax({
url : "simulatedAnnealing.js",
dataType: "text",
success : function (data) {
$("#simulatedAnnealingCode").html(data);
}
});

var annealingCanvas;
var text,line,background;
var w,h;
var two;
var sa;

var x = 0; // Current Index
var f; // The objective function

var DELAY = 1 * 60;
var POINTS = 30; // Number of points of the objective function
var INITIAL_TEMP = 50;
var K = 1; // Boltzmann constant

function init(){
annealingCanvas = document.getElementById("annealingCanvas");
annealingCanvas.addEventListener("click", handleClick, false);
w = annealingCanvas.offsetWidth;
h = 300;
two = new Two({ width: w, height: h }).appendTo(annealingCanvas);
sa = new SimulatedAnnealing(x,K,INITIAL_TEMP);
text = two.makeText("Temperature: "+INITIAL_TEMP,w/2 ,10,'normal');
line = two.makeLine(x,0,x,h);
line.stroke = 'orangered';
line.linewidth = 5;
setupScene();
}

init();

two.bind('update', function(frameCount){
if(frameCount % DELAY == 0){
x = sa.anneal(f);
// Translate the point according to the new chosen point
line.translation.set(x*w/POINTS,h/2);
y = Math.round(f[x]*100)/100;
text.value = "Temperature: "+sa.T + " ("+x+" , "+y+")";
}
}).play();

function handleClick(){
// When ever the canvas is clicked
// recalculate and redraw the background
// and reinitialize the sa object
setupScene();
x = 0;
sa = new SimulatedAnnealing(x,K,INITIAL_TEMP);
}

function setupScene(){
// If background already exists,
// then clear it
if(background != null)
two.remove(background);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you still using Two.js here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I am not. The deleted part is from the past implementation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, silly me, I misread the diff :)

f = new Array(POINTS);
background = new Array(POINTS-1);
f[0] = 0;
for(var i = 1; i < f.length; i++){
// f[i] ranges between 0 and 3*h/4
f[i] = Math.random() * 3*h/4;
sx = (i-1) * w/POINTS;
sy = h - f[i-1];
fx = i * w/POINTS;
fy = h - f[i];
// Draw lines connecting all f[i]
background[i-1] = two.makeLine(sx,sy,fx,fy);
background[i-1].linewidth = 2;
background[i-1].stroke = '#090A3B';
}
two.update();
}
$(document).ready(function() {

//Wrapper class for the diagram
class SimulatedAnnealingDiagram extends HillWorld {
constructor(selector, h, w, sliderSelector) {
super(selector, h, w);
this.sliderElement = $(sliderSelector);
}

init(delay, k) {
this.delay = delay;
this.initial = this.hillClimber.getCurrentState();
this.simulatedAnnealing = new SimulatedAnnealing(this.hill, this.initial, k);
this.colorScale = d3.scaleLinear().domain([0, 50]).range([70, 30]).clamp(true);
this.showAllStates();
this.bindListeners();
this.paintGlobalMaxima();
this.showTemperature(100);
this.sliderElement.val(100);
this.startAnnealing();
}

showAllStates() {
this.hillDiagram.svgRects.transition()
.duration(200)
.style('opacity', 1);
}

paintGlobalMaxima() {
this.hillDiagram.svgRects.classed('hill-maxima', (d) => d.maxima);
}

teleportRobot(currentState) {
let robotLocation = currentState;
let robotStateValue = this.hill.getStates()[currentState];
this.hillClimberDiagram.robot
.attr('x', this.hillClimberDiagram.xScale(robotLocation) - this.hillClimberDiagram.xOffset)
.attr('y', this.h - this.hillClimberDiagram.yScale(robotStateValue) - this.hillClimberDiagram.yOffset);
}

updateAnnealRegion(currentState) {
this.hillDiagram.svgRects.classed('hill-anneal-current-state', d => d.state == currentState);
}

showTemperature(t) {
this.svgTemp = this.hillDiagram.svg.append('text')
.attr('x', this.w - 180)
.attr('y', this.h - 470)
//Displaying temperature with 2 digit precision
.text(`Temperature : ${Math.round(t*100)/100}`);
}

updateTemperature(t) {
this.svgTemp.text(`Temperature : ${Math.round(t*100)/100}`);
}

nextMove(temp) {
let nextNode = this.simulatedAnnealing.anneal(temp);
if (nextNode.temp <= 0) {
this.updateTemperature(0);
return false;
} else {
let nextState = nextNode.state;
this.hillClimber.changeState(nextState);
this.teleportRobot(nextState);
this.updateAnnealRegion(nextState);
return true;
}
}

startAnnealing() {
//Stop annealing if already running.
this.stopAnnealing();
this.annealIntervalFunction = setInterval(() => {
if (!this.nextMove(this.sliderElement.val())) {
this.stopAnnealing();
}
}, this.delay);
}

stopAnnealing() {
clearInterval(this.annealIntervalFunction, this.delay);
}

destroy() {
this.stopAnnealing();
}

bindListeners() {
this.sliderElement.mouseup(() => {
if (this.sliderElement.val() > 0) {
this.startAnnealing();
}
});
this.sliderElement.mousemove(() => {
this.updateTemperature(this.sliderElement.val())
})
}
}

var simulatedAnnealingDiagram;

function init() {
simulatedAnnealingDiagram = new SimulatedAnnealingDiagram('#annealingCanvas', 500, 1000, '#tempSelector');

let delay = 20;

let k = 0.3;
simulatedAnnealingDiagram.init(delay, k);
};

function restart() {
simulatedAnnealingDiagram.destroy();
init();
}

init();
$('#annealingRestart').click(restart);
});
36 changes: 26 additions & 10 deletions 4-Beyond-Classical-Search/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@

<script src="https://cdnjs.cloudflare.com/ajax/libs/two.js/0.6.0/two.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
<!-- <script type="text/javascript" src="./geneticAlgorithm.js"></script>
<script type="text/javascript" src="./simulatedAnnealing.js"></script> -->
<!-- <script type="text/javascript" src="./geneticAlgorithm.js"></script> -->
<script type="text/javascript" src="./simulatedAnnealing.js"></script>
<script type="text/javascript" src="./hillClimbing.js"></script>
<!-- <script type="text/javascript" src="./andOrGraphSearch.js"></script>
<script type="text/javascript" src="./lrtaAgent.js"></script>
<script type="text/javascript" src="./onlineDfsAgent.js"></script> -->

<!-- <script type="text/javascript" src="./c_geneticAlgorithm.js"></script>
<script type="text/javascript" src="./c_simulatedAnnealing.js"></script> -->
<!-- <script type="text/javascript" src="./c_geneticAlgorithm.js"></script> -->
<script type="text/javascript" src="./c_simulatedAnnealing.js"></script>
<script type="text/javascript" src="./c_hillClimbing.js"></script>
<!-- <script type="text/javascript" src="./c_andOrGraphSearch.js"></script>
<script type="text/javascript" src="./c_lrtaAgent.js"></script>
Expand All @@ -36,7 +36,7 @@ <h2>Optimization Problem</h2>
represented by x-axis and elevation(objective function value) represented by y-axis. The best state is hence the state with the highest objective value</p>
<p>The given diagram is a state-space representation of an objective function. You can click anywhere inside the box to reveal the elevation there. You are allowed <i>25 moves</i> to <b>find the highest peak</b> before the hill is revealed.</p>
<p><span class='inline-legend maxima'></span> represents found global maximas and <span class='inline-legend unvisitedmaxima'></span> represents unfound global maximas</p>
<p>Try to come up with a strategy that can be used for al kinds of hills.</p>
<p>Try to come up with a strategy that can be used for all kinds of hills.</p>
<div class='row'>
<div class="col-md-2">
<div class='btn btn-primary restart-button' id='hillClimbRestart'>Restart</div>
Expand All @@ -51,7 +51,7 @@ <h2 id='hillMoves'></h2>
<h2>Hill Climbing Search</h2>
<p>In hill climbing search, the current node is replaced by the best neighbor. In this case, the objective function is represented by elevation, neighbors of a state are the states to the left and right of it and the best neigbor is the neigbor state
with the highest elevation.</p>
<p>The <span class='inline-legend maxima'></span> represents global maximas and <span class='inline-legend grma'></span> represents the states from where the hill climbing search can reach a global maxima.</p>
<p>The <span class='inline-legend maxima'></span> represents global maximas and <span class='inline-legend gmra'></span> represents the states from where the hill climbing search can reach a global maxima.</p>
<p>Click on different states to start Hill Climbing Search from there and see which direction it prefers and when does it stop.</p>
<p>Use the restart button to try it on different kinds of hills.</p>
<div class='row'>
Expand All @@ -63,11 +63,27 @@ <h2>Hill Climbing Search</h2>
</div>

<h2>Simulated Annealing</h2>
<p>Click on the screen to restart the simulation.</p>
<p>The orange line represents the current position.</p>
<div class="canvas" id="annealingCanvas" height="300px"></div>
<p>Simulated Annealing is a combination of Hill Climbing and Random Walk to gain more efficiency and completeness. In this procedure, instead of always moving to the best neighbor, a random neighbor is chosen. If the new state has better objective
value than the current state, it is always chosen. If not, the algorithm accept the new state with a probability less than one. The probability of choosing a <b>bad state</b> depends on :
<ol>
<li>The difference in objective value of the new state and the current state</li>
<li>The temperature</li>
</ol>
The temperature T denotes how likely it is for a bad state to be accepted. The procedure starts with a high temperature and decreases it with time. The probability of accepting a bad move decreases exponentially with temperature.</p>
<p>The <span class='inline-legend maxima'></span> represents global maximas and <span class='inline-legend anneal-region'></span> represents current state.</p>
<p>Notice how the algorithm shakes violently between states when the temperature is high and then stabilizes to higher states as the temperature decreases.</p>
<p>Try to set the temperature from the slider to different values and notice how the algorithm behaves.</p>
<div class='row'>
<div class="col-md-2">
<div class='btn btn-primary restart-button' id='annealingRestart'>Restart</div>
</div>
<div class="col-md-8">
<b>Temperature</b>
<input style="margin-top:1.5%" type="range" id="tempSelector" name="tempInput" step="0.1" min="0" max="100" value="100">
</div>
</div>
<div id="annealingCanvas"></div>

<pre id="simulatedAnnealingCode"></pre>

<h2>Genetic Algorithm</h2>
<p>Little critters change the color of their fur to match the background to camouflage themselves from predators.</p>
Expand Down
11 changes: 10 additions & 1 deletion 4-Beyond-Classical-Search/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,24 @@
width: 10px;
height: 10px;
}
.anneal-region {
background-color: hsl(303, 100%, 50%);
}
.maxima {
background-color: hsl(110, 100%, 38%);
}
.unvisitedmaxima {
background-color: hsl(102, 100%, 56%);
}
.grma {
.gmra {
background-color: hsl(110, 100%, 60%);
}
.hill {
fill: hsl(217, 30%, 70%);
}
.hill-anneal-current-state {
fill: hsl(303, 100%, 50%);
}
.hill-maxima {
fill: hsl(110, 100%, 75%);
}
Expand All @@ -27,3 +33,6 @@
.hill-gmra {
fill: hsl(110, 25%, 60%);
}
.hill-maxima.hill-anneal-current-state {
fill: hsl(110, 100%, 85%);
}
56 changes: 29 additions & 27 deletions 4-Beyond-Classical-Search/simulatedAnnealing.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
var SimulatedAnnealing = function(x,k,T){
this.x = x; // Starting state
this.k = k; // Boltzmann constant
this.T = T; // Initial temperature
class SimulatedAnnealing {
constructor(hill, initial, k) {
this.states = hill.getStates();
this.initial = initial;
this.current = this.initial;
this.k = k;
}

this.anneal = function(f){
if(this.T == 0) return x;
var new_x = this.getRandomInt(0,f.length);
if(f[new_x] > f[x]){
// If the new chosen value is better
// then just move to new state
x = new_x;
} else {
// Calculate probability of transfer
var p = Math.exp((f[new_x] - f[x])/(k * T));
// If a randomly chosen value is within p
// then move to the new state
if(Math.random() < p)
x = new_x;
}
this.T--;
return x;
};

this.getRandomInt = function(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
};
};
anneal(temperature) {
let nextState = this.getRandomState();
let diff = this.states[nextState] - this.states[this.current];
if (diff > 0) {
this.current = nextState;
} else {
let p = Math.exp((diff) / parseInt(this.k * temperature));
if (Math.random() < p) {
this.current = nextState;
}
}
return {
state: this.current,
temp: temperature
};
}
getRandomState() {
let mini = 0;
let maxi = this.states.length;
return Math.floor(Math.random() * (maxi - mini + 1)) + mini;
}
}