Skip to content
Snippets Groups Projects
Commit ef3ea6d1 authored by Brady James Garvin's avatar Brady James Garvin
Browse files

Introduced starter code for Homework 3.6.

parent 5dbe5e02
No related branches found
No related tags found
No related merge requests found
......@@ -30,6 +30,7 @@
<script src="js/undirected_graph.js"></script>
<script src="js/transit.js"></script>
<script src="js/patching.js"></script>
<script src="js/heat_map.js"></script>
<script src="js/positioned_graph.js"></script>
<script src="js/throttled_simulation.js"></script>
<script src="js/visualization_style.js"></script>
......
/* exported computeHeatMap */
class EdgeLabeledGraph {
constructor(vertices, defaultLabel) {
const verticesList = [...vertices]; // copy the vertices to a list in case they can only be iterated over once
this.edges = new Map();
for (const source of verticesList) {
const adjacencies = new Map();
for (const destination of verticesList) {
adjacencies.set(destination, defaultLabel);
}
this.edges.set(source, adjacencies);
}
}
get vertices() {
return this.edges.keys();
}
getLabel(source, destination) {
return this.edges.get(source).get(destination);
}
setLabel(source, destination, label) {
return this.edges.get(source).set(destination, label);
}
capLabel(source, destination, label) {
const adjacencies = this.edges.get(source);
adjacencies.set(destination, Math.min(adjacencies.get(destination), label));
}
increaseLabel(source, destination, increase) {
const adjacencies = this.edges.get(source);
adjacencies.set(destination, adjacencies.get(destination) + increase);
}
}
function computeTransitGraph(city) {
return undefined; // TODO: stub
}
// Preliminaries:
// W[u][v] is the (possibly infinite) weight from u to v.
//
// Standard Floyd–Warshall Recurrence:
// D^(i)[u][v] is the distance from u to v using only the first i vertices as intermediates, so
// D^(n)[u][v] is the distance from u to v.
//
// D^(0)[u][v] = …
// D^(i)[u][v] = … for 1 ≤ i ≤ n
//
// Recurrence for Shortest-Path Successors:
// S^(i)[u][v] is a vertex that immediately follows u in a shortest path from u to v using only the first i vertices as intermediates, so
// S^(n)[u][v] is a vertex that immediately follows u in a shortest path from u to v.
//
// S^(0)[u][v] = … if …
// … otherwise
// S^(i)[u][v] = … if …
// … if …
// … otherwise for 1 ≤ i ≤ n
function computeShortestPathSuccessors(transitGraph) {
return undefined; // TODO: stub
}
// Preliminaries:
// S^(n)[u][v] is defined as above computeShortestPathSuccessors.
//
// Recurrence for Traffic Matrix:
// T^(i)[u][v] is the number of distinct paths that visit a vertex \(u\) in their first \(i\) steps while traveling to a final destination \(v\), so
// T^(n-1)[u][v] is the number of distinct paths that travel via \(u\) to their final destination \(v\).
//
// T^(0)[u][v] = 1
// T^(i)[u][v] = 1 + sum_{w|S^(n)[w][v]=u} T^(i-1)[w][v] for 1 ≤ i ≤ n
//
function computeTrafficMatrix(successors) {
return undefined; // TODO: stub
}
function computeHeatFromTraffic(traffic) {
return undefined; // TODO: stub
}
function computeHeatMap(city) {
return undefined; // TODO: stub
}
QUnit.module('heat_map.js');
/* globals QUnit Vertex UndirectedEdge UndirectedGraph City Route Bus EdgeLabeledGraph */
/* globals computeTransitGraph computeShortestPathSuccessors computeTrafficMatrix computeHeatFromTraffic computeHeatMap */
/* eslint-disable no-magic-numbers */
// This reformatting is not necessary, but makes the output from failed tests easier to read.
function toTriples(edgeLabeledGraph) {
const accumulator = [];
for (const [source, adjacencies] of edgeLabeledGraph.edges) {
for (const [destination, label] of adjacencies) {
accumulator.push([source, destination, label]);
}
}
let result = '';
for (const triple of accumulator.sort()) {
result += `(${triple}); `;
}
return result.slice(0, -2);
}
// Building graphs from strings is not necessary, but makes tests easier to write.
function fromTriples(triplesString) {
const triples = triplesString.split('; ').map((triple) => triple.slice(1, -1).split(','));
const vertices = new Set();
for (const [source, destination, _] of triples) {
vertices.add(source);
vertices.add(destination);
}
const result = new EdgeLabeledGraph(vertices, undefined);
for (const [source, destination, label] of triples) {
let cast = Number(label);
if (label === '') {
cast = undefined;
} else if (Number.isNaN(cast)){
cast = label;
}
result.setLabel(source, destination, cast);
}
return result;
}
const CITY_FOR_SMOKE_TESTS = (() => {
const a = new Vertex('a');
const b = new Vertex('b');
const c = new Vertex('c');
const walkGraph = new UndirectedGraph();
walkGraph.addVertex(a);
walkGraph.addVertex(b);
walkGraph.addVertex(c);
walkGraph.addEdge(a, new UndirectedEdge(2.0), b);
walkGraph.addEdge(a, new UndirectedEdge(4.0), c);
walkGraph.addEdge(b, new UndirectedEdge(8.0), c);
const driveGraph = new UndirectedGraph();
driveGraph.addVertex(a);
driveGraph.addVertex(b);
driveGraph.addVertex(c);
driveGraph.addEdge(a, new UndirectedEdge(1.0), c);
const city = new City(walkGraph, driveGraph);
const route = new Route(city, a, c);
const x = new Bus(route.getArc(a)); // eslint-disable-line no-unused-vars
const y = new Bus(route.getArc(c)); // eslint-disable-line no-unused-vars
return city;
})();
QUnit.test('smoke test computeTransitGraph', (assert) => {
const transitGraph = computeTransitGraph(CITY_FOR_SMOKE_TESTS);
assert.deepEqual(toTriples(transitGraph), '(a,a,Infinity); (a,b,2); (a,c,2); (b,a,2); (b,b,Infinity); (b,c,8); (c,a,2); (c,b,8); (c,c,Infinity)');
});
QUnit.test('smoke test computeShortestPathSuccessors', (assert) => {
const transitGraph = fromTriples('(a,a,Infinity); (a,b,2); (a,c,2); (b,a,2); (b,b,Infinity); (b,c,8); (c,a,2); (c,b,8); (c,c,Infinity)');
const successors = computeShortestPathSuccessors(transitGraph);
assert.deepEqual(toTriples(successors), '(a,a,); (a,b,b); (a,c,c); (b,a,a); (b,b,); (b,c,a); (c,a,a); (c,b,a); (c,c,)');
});
QUnit.test('smoke test computeTrafficMatrix', (assert) => {
const successors = fromTriples('(a,a,); (a,b,b); (a,c,c); (b,a,a); (b,b,); (b,c,a); (c,a,a); (c,b,a); (c,c,)');
const traffic = computeTrafficMatrix(successors);
assert.deepEqual(toTriples(traffic), '(a,a,3); (a,b,2); (a,c,2); (b,a,1); (b,b,3); (b,c,1); (c,a,1); (c,b,1); (c,c,3)');
});
QUnit.test('smoke test computeHeatFromTraffic', (assert) => {
const traffic = fromTriples('(a,a,3); (a,b,2); (a,c,2); (b,a,1); (b,b,3); (b,c,1); (c,a,1); (c,b,1); (c,c,3)');
const heat = computeHeatFromTraffic(traffic);
assert.deepEqual(heat.size, 3);
assert.deepEqual(heat.get('a'), 7); // fromTriples will give us string keys, not vertex keys
assert.deepEqual(heat.get('b'), 5);
assert.deepEqual(heat.get('c'), 5);
});
QUnit.test('smoke test computeHeatMap', (assert) => {
const a = CITY_FOR_SMOKE_TESTS.walkGraph.vertices.find((vertex) => vertex.name === 'a');
const b = CITY_FOR_SMOKE_TESTS.walkGraph.vertices.find((vertex) => vertex.name === 'b');
const c = CITY_FOR_SMOKE_TESTS.walkGraph.vertices.find((vertex) => vertex.name === 'c');
const heat = computeHeatMap(CITY_FOR_SMOKE_TESTS);
assert.deepEqual(heat.size, 3);
assert.deepEqual(heat.get(a), 7);
assert.deepEqual(heat.get(b), 5);
assert.deepEqual(heat.get(c), 5);
});
......@@ -42,6 +42,9 @@
<script src="../js/patching.js"></script>
<script src="test_patching.js"></script>
<script src="../js/heat_map.js"></script>
<script src="test_heat_map.js"></script>
<script src="../js/positioned_graph.js"></script>
<script src="test_positioned_graph.js"></script>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment