UNPKG

maia-markov

Version:

Markov analysis and generation functions supporting various applications by Music Artificial Intelligence Algorithms, Inc.

255 lines (231 loc) 6.38 kB
// Imports import Vertex from './Vertex' import Edge from './Edge' import PriorityQueue from './PriorityQueue' const mu = require('maia-util') // Constructor for Graph object export default function Graph(arr, vtxStr, nbsStr, distStr){ // If supplied with an input array, this constructor fills the graph with // directed edges by default. this.vertexMap = {} // Workaround for JS context peculiarities. var self = this; if (arr !== undefined){ arr.map(function(a){ a[nbsStr].map(function(n){ if (distStr !== undefined){ self.add_directed_edge(a[vtxStr], n[vtxStr], n[distStr]) } else { self.add_directed_edge(a[vtxStr], n[vtxStr], 1) } }) }) } // Possible to return something. // return sth; } // Methods for Graph object Graph.prototype = { constructor: Graph, add_edge: function(start, end, w){ const u = this.get_vertex(start) const v = this.get_vertex(end) u.nbs.push(new Edge(u, v, w)) v.nbs.push(new Edge(v, u, w)) }, add_directed_edge: function(start, end, w){ const u = this.get_vertex(start) const v = this.get_vertex(end) u.nbs.push(new Edge(u, v, w)) }, get_vertex: function(name){ let v = this.vertexMap[name] if (v == undefined){ v = new Vertex(name) this.vertexMap[name] = v } return v }, get_neighbors: function(name){ let v = this.vertexMap[name] if (v == undefined){ console.log("Error: start vertex not found.") return } return v.nbs.map(function(nb){ return nb.v.name }) }, print_neighbors: function(name){ let v = this.vertexMap[name] if (v == undefined){ console.log("Error: start vertex not found.") return } let str = "" v.nbs.map(function(nb){ str += nb.v.name + ", " }) return str }, // Could write one of these, because there's too much code copy/paste at the // beginnings of bfs, dfs, and shortest_path below. // prep_for_search: function(startName){} // Untested breadth-first search bfs: function(startName){ let startVertex = this.vertexMap[startName] if (startVertex == undefined){ console.log("Error: start vertex not found.") return } this.reset() startVertex.dist = 0 let dq = [startVertex] while (dq.length > 0){ const u = dq.shift() console.log(u.name + " " + u.dist) u.nbs.map(function(nb){ let v = nb.v if (v.dist == Infinity){ v.dist = u.dist + 1 dq.push(v) } }) } }, // Untested depth-first search dfs: function(startName){ let startVertex = this.vertexMap[startName] if (startVertex == undefined){ console.log("Error: start vertex not found.") return } this.reset() startVertex.visited = true let dq = [startVertex] while (dq.length > 0){ const u = dq.pop() console.log(u.name) u.nbs.map(function(nb){ let v = nb.v if (!v.visited){ v.visited = true dq.push(v) } }) } }, // Untested recursive depth-first search // No reseting here, which is a potential problem. recursive_dfs: function(u){ u.visited = true console.log(u.name) u.nbs.map(function(nb){ let v = nb.v if (!v.visited){ this.recursive_dfs(v) } }) }, shortest_path: function(startName){ let startVertex = this.vertexMap[startName] if (startVertex == undefined){ console.log("Error: start vertex not found.") return } this.reset() let q = new PriorityQueue() startVertex.dist = 0 q.enqueue(startVertex.dist, startVertex) // console.log("q:", q) while (!q.heap.isEmpty()){ let u = q.dequeue() if (u.visited) continue u.visited = true // console.log(u.name + " " + u.dist + " " + ((u.prev==null)?"":u.prev.name)) u.nbs.map(function(nb){ let v = nb.v if (v.dist > u.dist + nb.w){ q.heap.removeValue(v) v.dist = u.dist + nb.w v.prev = u q.enqueue(v.dist, v) } }) } }, print_shortest_path: function(startName, endName){ this.shortest_path(startName) let relVtx = this.get_vertex(endName) if (!relVtx.visited){ // These two vertices are not connected. return } let rv = [endName] while (relVtx.prev !== null){ rv.push(relVtx.prev.name) relVtx = this.get_vertex(relVtx.prev.name) } return rv.reverse() }, scenic_path: function(startName, loveOfScenery){ let startVertex = this.vertexMap[startName] if (startVertex == undefined){ console.log("Error: start vertex not found.") return } this.reset() let q = new PriorityQueue() startVertex.dist = 0 q.enqueue(startVertex.dist, startVertex) // console.log("q:", q) while (!q.heap.isEmpty()){ let u = q.dequeue() if (u.visited) continue u.visited = true // console.log(u.name + " " + u.dist + " " + ((u.prev==null)?"":u.prev.name)) u.nbs.map(function(nb){ let v = nb.v if ( // The next line is intended to avoid the undefined error in beginning // to construct the shortest path. v.dist === Infinity || ( // If true, there's a better way to get to vertex v. (v.dist > u.dist + nb.w) && Math.random() > loveOfScenery ) ){ // Update the heap with the more efficient route. q.heap.removeValue(v) v.dist = u.dist + nb.w v.prev = u q.enqueue(v.dist, v) } }) } }, print_scenic_path: function(startName, endName, loveOfScenery){ this.scenic_path(startName, loveOfScenery) let relVtx = this.get_vertex(endName) if (!relVtx.visited){ // These two vertices are not connected. return } let rv = [endName] while (relVtx.prev !== null){ rv.push(relVtx.prev.name) relVtx = this.get_vertex(relVtx.prev.name) } return rv.reverse() }, reset: function(){ let self = this Object.keys(this.vertexMap).map(function(v){ self.vertexMap[v].dist = Infinity self.vertexMap[v].visited = false self.vertexMap[v].prev = null }) } }