├── .gitignore ├── index.js ├── binding.gyp ├── graph ├── addon.cc ├── directed_graph.h ├── binding.cc └── directed_graph.cc ├── test.js ├── package.json └── Readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var graph_constructor = require('./build/Release/graph'); 2 | 3 | module.exports = graph_constructor.Graph; -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "graph", 5 | "sources": [ 6 | "graph/addon.cc", 7 | "graph/directed_graph.cc", 8 | "graph/binding.cc" 9 | ] 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /graph/addon.cc: -------------------------------------------------------------------------------- 1 | // #ifndef BUILDING_NODE_EXTENSION 2 | #define BUILDING_NODE_EXTENSION 3 | 4 | #include 5 | #include "directed_graph.h" 6 | 7 | using namespace v8; 8 | 9 | void InitAll(Handle exports) { 10 | Graph::Init(exports); 11 | } 12 | 13 | NODE_MODULE(graph, InitAll) 14 | 15 | // #endif -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var bellman_ford = require('./build/Release/graph'); 2 | 3 | var graph = new bellman_ford.Graph(); 4 | 5 | 6 | graph.add_node("a"); 7 | graph.add_node("b"); 8 | graph.add_node("d"); 9 | graph.add_node("e"); 10 | graph.add_node("c"); 11 | 12 | graph.add_edge("a", "b", -0.1); 13 | graph.add_edge("b", "a", 0.2); 14 | graph.add_edge("a", "c", 0.9); 15 | graph.add_edge("c", "e", -0.1); 16 | graph.add_edge("e", "c", 0.2); 17 | graph.add_edge("e", "d", 0.2); 18 | graph.add_edge("d", "e", 0.1); 19 | graph.add_edge("d", "a", 0.4); 20 | graph.add_edge("b", "d", 0.3); 21 | 22 | graph.print(); 23 | 24 | console.log(graph.bellmanford("c")); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bellman-ford", 3 | "version": "0.0.6", 4 | "gypfile": true, 5 | "scripts": { 6 | "start": "node test.js" 7 | }, 8 | "description": "Bellman Ford algorithm for node.js", 9 | "main": "index.js", 10 | "keywords": [ 11 | "bellman-ford", 12 | "bellmanford", 13 | "graph", 14 | "directed-graph", 15 | "c++", 16 | "shortest", 17 | "path" 18 | ], 19 | "author": "Gabriel Ferrin ", 20 | "dependencies": { 21 | "node-gyp": "~0.9.6" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git://github.com/gferrin/bellman-ford.git" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /graph/directed_graph.h: -------------------------------------------------------------------------------- 1 | /* 2 | Description: Directed Graph container designed to facilitate bellman-ford algorithm. 3 | 4 | Author: Gabriel Ferrin 5 | Date: May 7th 2013 6 | */ 7 | #define BUILDING_NODE_EXTENSION 8 | #ifndef DIRECTED_GRAPH_H 9 | #define DIRECTED_GRAPH_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class Graph : public node::ObjectWrap { 17 | public: 18 | 19 | Graph(); 20 | Graph( std::string & ); 21 | ~Graph(); 22 | 23 | static void Init(v8::Handle target); 24 | 25 | void print(); 26 | void trim(); 27 | void add_node( std::string & name ); 28 | void add_edge( std::string &, std::string &, double ); 29 | void update_edge( std::string &, std::string &, double ); 30 | bool search( std::string & name ); 31 | bool bellman_ford( std::string & name, std::vector > & ); 32 | 33 | private: 34 | /* Structs */ 35 | struct GEdge; 36 | 37 | struct GNode 38 | { 39 | std::string name; 40 | std::vector edges; 41 | int key; 42 | 43 | GNode( std::string name, int k ) : name( name ), key( k ) {} 44 | }; 45 | 46 | struct GEdge 47 | { 48 | double weight; 49 | GNode * node; // node that the edge is pointed towards 50 | 51 | GEdge( double weight, GNode *& n ) : weight( weight ), node( n ) {} 52 | }; 53 | 54 | /* Variables */ 55 | 56 | GNode *source; 57 | std::vector nodes; 58 | 59 | /* V8 binding functions */ 60 | static v8::Handle New(const v8::Arguments& args); 61 | static v8::Handle add_node(const v8::Arguments& args); 62 | static v8::Handle add_edge(const v8::Arguments& args); 63 | static v8::Handle update_edge(const v8::Arguments& args); 64 | static v8::Handle print(const v8::Arguments& args); 65 | static v8::Handle trim(const v8::Arguments& args); 66 | static v8::Handle bellmanford(const v8::Arguments& args); 67 | 68 | /* Functions */ 69 | void add_edge( GNode *& origin, GNode *& destination, double weight ); 70 | bool bellman_ford( GNode *& origin, std::vector > & ); 71 | GNode * get_node( std::string & name ) 72 | { 73 | for( unsigned long int i = 0; i < nodes.size(); ++i ){ 74 | if( name == nodes.at(i).name ){ 75 | return &nodes.at(i); 76 | } 77 | } 78 | // this should be fixed to an empty node 79 | return &nodes.at(0); 80 | } 81 | }; 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # bellman-ford 2 | 3 | bellman-ford allows you to run the [bellman ford algorithm](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm) in node.js. 4 | 5 | It is written in C++ and ported to node.js. It uses a directed graph 6 | as it's underlying data structure. 7 | 8 | ## Install 9 | 10 | `npm install bellman-ford` 11 | 12 | ## Examples 13 | 14 | ### Create Graph 15 | ```js 16 | var bellman_ford = require('bellman-ford'); 17 | 18 | var graph = new bellman_ford(); 19 | ``` 20 | 21 | ### Add Nodes 22 | ```js 23 | graph.add_node("a"); 24 | graph.add_node("b"); 25 | graph.add_node("c"); 26 | graph.add_node("d"); 27 | graph.add_node("e"); 28 | ``` 29 | 30 | ### Add Edges 31 | ```js 32 | graph.add_edge("a", "b", -0.1); 33 | graph.add_edge("b", "a", 0.2); 34 | graph.add_edge("a", "c", 0.9); 35 | graph.add_edge("c", "e", -0.1); 36 | graph.add_edge("e", "c", 0.2); 37 | graph.add_edge("e", "d", 0.2); 38 | graph.add_edge("d", "e", 0.1); 39 | graph.add_edge("d", "a", 0.4); 40 | graph.add_edge("b", "d", 0.3); 41 | ``` 42 | 43 | ### Run Bellman-Ford 44 | ```js 45 | console.log(graph.bellmanford("c")); 46 | ``` 47 | which will output 48 | 49 | ```js 50 | [ [ 'a', '0.5' ], 51 | [ 'b', '0.4' ], 52 | [ 'd', '0.1' ], 53 | [ 'e', '-0.1' ], 54 | [ 'c', '0' ] ] 55 | ``` 56 | 57 | where each subarray contains a value in the graph say `a` and 58 | the distance to the source node `c` whcich in this case is `0.5` 59 | 60 | ## Functions 61 | 62 | ### add_node 63 | 64 | This function adds a node to directed graph. 65 | It takes one parameter `add_node(node_name)` 66 | If a node with `node_name` already exists then nothing wil happen 67 | 68 | ### add_edge 69 | 70 | This function adds edges to directed graph. 71 | It takes three parameters `add_edge(node_from, node_to, edge_weight)` 72 | If `node_from` or `node_to` has not yet beed added to the graph then 73 | the function call will fail 74 | 75 | ### update_edge 76 | 77 | This function updates edge weights between nodes 78 | It takes three parameters `update_edge(node_from, node_to, edge_weight)` 79 | 80 | ### print 81 | 82 | This function prints out the current graph 83 | 84 | ```js 85 | graph.print(); 86 | ``` 87 | for the given example will output 88 | ``` 89 | a: 90 | weight: -0.1 to: b 91 | weight: 0.9 to: c 92 | b: 93 | weight: 0.2 to: a 94 | weight: 0.3 to: d 95 | d: 96 | weight: 0.1 to: e 97 | weight: 0.4 to: a 98 | e: 99 | weight: 0.2 to: c 100 | weight: 0.2 to: d 101 | c: 102 | weight: -0.1 to: e 103 | ``` 104 | 105 | ### trim 106 | 107 | This function removes all nodes with less then two edges as well 108 | as removing all associated edges. 109 | 110 | ### bellmanford 111 | 112 | This is the main function which will run the bellman ford algorithm on 113 | the current graph. It will return a 2d array of the form 114 | `[node_name, distance_from_source]` 115 | 116 | If the graph contains negative weight cycles then it will return an empty array 117 | 118 | ## Compiling from Source 119 | 120 | To compile the code from source you must have `python` `gcc` and `node-gyp` 121 | installed on your machine. 122 | 123 | Then run 124 | 125 | `node-gyp configure` 126 | 127 | and 128 | 129 | `node-gyp build` 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /graph/binding.cc: -------------------------------------------------------------------------------- 1 | // #ifndef BUILDING_NODE_EXTENSION 2 | #define BUILDING_NODE_EXTENSION 3 | 4 | #include "directed_graph.h" 5 | 6 | using namespace v8; 7 | 8 | void Graph::Init(Handle target) { 9 | // Prepare constructor template 10 | Local tpl = FunctionTemplate::New(New); // this calls the New member function 11 | tpl->SetClassName(String::NewSymbol("Graph")); 12 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 13 | // Prototype 14 | 15 | tpl->PrototypeTemplate()->Set(String::NewSymbol("add_node"), 16 | FunctionTemplate::New(add_node)->GetFunction()); 17 | 18 | tpl->PrototypeTemplate()->Set(String::NewSymbol("add_edge"), 19 | FunctionTemplate::New(add_edge)->GetFunction()); 20 | 21 | tpl->PrototypeTemplate()->Set(String::NewSymbol("update_edge"), 22 | FunctionTemplate::New(update_edge)->GetFunction()); 23 | 24 | tpl->PrototypeTemplate()->Set(String::NewSymbol("print"), 25 | FunctionTemplate::New(print)->GetFunction()); 26 | 27 | tpl->PrototypeTemplate()->Set(String::NewSymbol("trim"), 28 | FunctionTemplate::New(trim)->GetFunction()); 29 | 30 | tpl->PrototypeTemplate()->Set(String::NewSymbol("bellmanford"), 31 | FunctionTemplate::New(bellmanford)->GetFunction()); 32 | 33 | Persistent constructor = Persistent::New(tpl->GetFunction()); 34 | target->Set(String::NewSymbol("Graph"), constructor); 35 | } 36 | // this is the "New member function" 37 | Handle Graph::New(const Arguments& args) { 38 | HandleScope scope; 39 | 40 | Graph* obj = new Graph(); 41 | obj->Wrap(args.This()); 42 | return args.This(); 43 | } 44 | 45 | Handle Graph::add_node(const v8::Arguments& args) 46 | { 47 | HandleScope scope; 48 | 49 | if (args.Length() != 1 ) { 50 | ThrowException(Exception::TypeError(String::New("add_node: wrong number of arguments"))); 51 | return scope.Close(Undefined()); 52 | } 53 | 54 | Graph* graph = ObjectWrap::Unwrap(args.This()); 55 | 56 | v8::String::Utf8Value param(args[0]->ToString()); 57 | std::string name = std::string(*param); 58 | 59 | graph->add_node( name ); 60 | return scope.Close(Boolean::New(true)); 61 | } 62 | 63 | Handle Graph::add_edge(const v8::Arguments& args) 64 | { 65 | HandleScope scope; 66 | 67 | Graph* graph = ObjectWrap::Unwrap(args.This()); 68 | 69 | if( args.Length() == 3 ){ 70 | v8::String::Utf8Value param1(args[0]->ToString()); 71 | v8::String::Utf8Value param2(args[1]->ToString()); 72 | 73 | std::string from = std::string(*param1); 74 | std::string to = std::string(*param2); 75 | double weight = args[2]->NumberValue(); 76 | 77 | graph->add_edge( from, to, weight ); 78 | return scope.Close(Boolean::New(true)); 79 | 80 | } else { 81 | ThrowException(Exception::TypeError(String::New("add_edge: wrong number of arguments"))); 82 | return scope.Close(Undefined()); 83 | } 84 | } 85 | 86 | Handle Graph::update_edge(const v8::Arguments& args) 87 | { 88 | HandleScope scope; 89 | 90 | Graph* graph = ObjectWrap::Unwrap(args.This()); 91 | if( args.Length() == 3 ){ 92 | v8::String::Utf8Value param1(args[0]->ToString()); 93 | v8::String::Utf8Value param2(args[1]->ToString()); 94 | 95 | std::string from = std::string(*param1); 96 | std::string to = std::string(*param2); 97 | double weight = args[2]->NumberValue(); 98 | 99 | graph->update_edge( from, to, weight ); 100 | return scope.Close(Boolean::New(true)); 101 | 102 | } else { 103 | ThrowException(Exception::TypeError(String::New("update_edge: wrong number of arguments"))); 104 | return scope.Close(Undefined()); 105 | } 106 | } 107 | 108 | Handle Graph::print(const v8::Arguments& args) 109 | { 110 | HandleScope scope; 111 | 112 | Graph* graph = ObjectWrap::Unwrap(args.This()); 113 | graph->print(); 114 | 115 | return scope.Close(Boolean::New(true)); 116 | } 117 | 118 | Handle Graph::trim(const v8::Arguments& args) 119 | { 120 | HandleScope scope; 121 | 122 | Graph* graph = ObjectWrap::Unwrap(args.This()); 123 | graph->trim(); 124 | 125 | return scope.Close(Boolean::New(true)); 126 | } 127 | 128 | Handle Graph::bellmanford(const v8::Arguments& args) 129 | { 130 | HandleScope scope; 131 | std::vector > path; 132 | 133 | if( args.Length() != 1 ) { 134 | ThrowException(Exception::TypeError(String::New("bellmanford(source_node): wrong number of arguments"))); 135 | return scope.Close(Undefined()); 136 | } 137 | Graph* graph = ObjectWrap::Unwrap(args.This()); 138 | v8::String::Utf8Value param1(args[0]->ToString()); 139 | std::string source = std::string(*param1); 140 | 141 | graph->bellman_ford(source, path); 142 | 143 | Handle result = Array::New(path.size()); 144 | 145 | for(unsigned long int i = 0; i < path.size(); ++i){ 146 | Handle keyvalue = Array::New(2); 147 | 148 | keyvalue->Set(0, String::New(path.at(i).at(0).c_str())); 149 | keyvalue->Set(1, String::New(path.at(i).at(1).c_str())); 150 | 151 | result->Set(i, keyvalue); 152 | } 153 | 154 | return scope.Close( result ); 155 | 156 | } 157 | 158 | // #endif 159 | -------------------------------------------------------------------------------- /graph/directed_graph.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Gabriel Ferrin 3 | Date: May 7th 2013 4 | */ 5 | 6 | #include "directed_graph.h" 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | Graph::Graph() : source( NULL ) {} 13 | 14 | Graph::Graph( string & name ) 15 | { 16 | source = new GNode( name, nodes.size() ); 17 | nodes.push_back( *source ); 18 | } 19 | 20 | Graph::~Graph() 21 | { 22 | for( unsigned long int i = 0; i < nodes.size(); ++i ){ 23 | nodes.at(i).edges.clear(); 24 | } 25 | nodes.clear(); 26 | } 27 | 28 | void Graph::add_node( string & name ) 29 | { 30 | if( !search(name) ){ 31 | GNode *temp = new GNode( name, nodes.size() ); 32 | nodes.push_back( *temp ); 33 | } 34 | } 35 | 36 | void Graph::add_edge( std::string & begin, std::string & end, double weight ) 37 | { 38 | if( search(begin) ){ 39 | GNode *origin = get_node( begin ); 40 | GNode *dest; 41 | 42 | if( search(end) ){ 43 | dest = get_node( end ); 44 | add_edge( origin, dest, weight ); 45 | } else { 46 | cout << "Error: no node \"" << end << "\" exists \n"; 47 | } 48 | } else { 49 | cout << "Error: no node \"" << begin << "\" exists \n"; 50 | } 51 | } 52 | 53 | void Graph::update_edge( std::string & begin, std::string & end, double weight ) 54 | { 55 | if( search(begin) ){ 56 | GNode *origin = get_node( begin ); 57 | GNode *dest; 58 | 59 | if( search(end) ){ 60 | dest = get_node( end ); 61 | for( unsigned long int i = 0; i < origin->edges.size(); ++i ){ 62 | if( origin->edges.at(i).node->name == dest->name ){ 63 | origin->edges.at(i).weight = weight; 64 | } 65 | } 66 | } else { 67 | cout << "Error: no node \"" << end << "\" exists \n"; 68 | } 69 | } else { 70 | cout << "Error: no node \"" << begin << "\" exists \n"; 71 | } 72 | } 73 | 74 | void Graph::print() 75 | { 76 | for( unsigned long int i = 0; i < nodes.size(); ++i ){ 77 | cout << nodes.at(i).name << ": \n"; 78 | 79 | for( unsigned long int j = 0; j < nodes.at(i).edges.size(); ++j ){ 80 | cout << "\t" << "weight: "<< nodes.at(i).edges.at(j).weight 81 | << " to: " <name << "\n"; 82 | } 83 | } 84 | } 85 | 86 | void Graph::trim() 87 | { 88 | // remove all bad edges from nodes 89 | for( unsigned long int i = 0; i < nodes.size(); ++i ){ // this needs to be done probably fewer times, try and prove this 90 | for( unsigned long int k = 0; k < nodes.size(); ++k ){ 91 | for( unsigned long int x = 0; x < nodes.at(k).edges.size(); ++x ){ 92 | if( nodes.at(k).edges.at(x).node->edges.size() < 2 ){ 93 | nodes.at(k).edges.erase( nodes.at(k).edges.begin() + x ); 94 | } 95 | } 96 | } 97 | } 98 | 99 | 100 | // remove all nodes with only one edge 101 | for( unsigned long int i = 0; i < nodes.size(); ++i){ 102 | if( nodes.at(i).edges.size() < 2 ){ 103 | nodes.erase( nodes.begin() + i ); 104 | if( i < 2 ){ 105 | i = 0; 106 | } else { 107 | i -= 2; 108 | } 109 | } 110 | } 111 | 112 | // reset all of the key values 113 | for( unsigned long int j = 0; j < nodes.size(); ++j){ 114 | nodes.at(j).key = j; 115 | } 116 | 117 | } 118 | 119 | bool Graph::search( std::string & name ) 120 | { 121 | for( unsigned long int i = 0; i < nodes.size(); ++i ){ 122 | if( name == nodes.at(i).name ){ 123 | return true; 124 | } 125 | } 126 | return false; 127 | } 128 | 129 | bool Graph::bellman_ford( std::string & name, std::vector >& path ) 130 | { 131 | for( unsigned long int i = 0; i < nodes.size(); ++i ){ 132 | if( name == nodes.at(i).name ){ 133 | GNode *temp = get_node( name ); 134 | return bellman_ford( temp, path ); 135 | } 136 | } 137 | return false; 138 | } 139 | 140 | void Graph::add_edge( GNode *& origin, GNode *& destination, double weight ) 141 | { 142 | GEdge *temp = new GEdge( weight, destination ); 143 | origin->edges.push_back( *temp ); 144 | } 145 | 146 | bool Graph::bellman_ford( GNode *& origin, std::vector >& path ) 147 | { 148 | vector distances, parents; 149 | const double infinity = 99999999; 150 | 151 | // Initilize 152 | for( unsigned long int i = 0; i < nodes.size(); ++i ){ 153 | if( nodes.at(i).name == origin->name ){ 154 | distances.push_back( 0 ); 155 | } else { 156 | distances.push_back( infinity ); 157 | } 158 | 159 | parents.push_back( 0.0 ); 160 | } 161 | 162 | // Relaxe Edges 163 | for( unsigned long int v = 0; v < nodes.size() - 1; ++v ){ // do the main loop v - 1 times, or v times to find negative weights 164 | bool changed = false; 165 | 166 | for( unsigned long int l = 0; l < nodes.size(); ++l ){ // these two loops - for every edge in the graph 167 | for( unsigned long int m = 0; m < nodes.at(l).edges.size(); ++m ){ 168 | GEdge * temp = &nodes.at( l ).edges.at( m ); 169 | GNode * tempNode = &nodes.at( l ); 170 | // If distances[u] + w < distances[v] 171 | if( distances.at( tempNode->key ) + temp->weight < distances.at( temp->node->key ) && distances.at( tempNode->key ) != infinity ){ 172 | changed = true; 173 | distances.at( temp->node->key ) = temp->weight + distances.at( tempNode->key ); 174 | parents.at( temp->node->key ) = tempNode->key; 175 | } 176 | } 177 | } 178 | if(!changed){ 179 | break; 180 | } else { 181 | changed = false; 182 | } 183 | } 184 | 185 | bool negative_weight = false; 186 | // Check for negative weight cycles 187 | for( unsigned long int l = 0; l < nodes.size(); ++l ){ // these two loops - for every edge in the graph 188 | for( unsigned long int m = 0; m < nodes.at(l).edges.size(); ++m ){ 189 | GEdge * temp = &nodes.at( l ).edges.at( m ); 190 | GNode * tempNode = &nodes.at( l ); 191 | // If distances[u] + w < distances[v] 192 | if( distances.at( tempNode->key ) + temp->weight < distances.at( temp->node->key ) && distances.at( tempNode->key ) != infinity ){ 193 | negative_weight = true; 194 | } 195 | } 196 | } 197 | 198 | if(!negative_weight){ 199 | 200 | stringstream weight; 201 | vector key_value; 202 | 203 | for(unsigned long int i = 0; i < nodes.size(); ++i){ 204 | 205 | key_value.push_back(nodes.at(i).name); 206 | // convery doulbe to string 207 | weight << distances.at(i); 208 | key_value.push_back(weight.str()); 209 | path.push_back(key_value); 210 | 211 | key_value.clear(); 212 | weight.clear(); 213 | weight.str(std::string()); 214 | } 215 | } 216 | 217 | return negative_weight; 218 | 219 | } 220 | 221 | 222 | 223 | 224 | 225 | --------------------------------------------------------------------------------