/******************************************************************************* * @fn void *compute_routes_thread( void *rp_tables ) * * @brief Thread that takes care of routing * ****************************************************************************/ void *compute_routes_thread( void *rp_tables ) { static uint32_t index; uint8_t node_index; uint8_t *route_table = &((uint8_t*)rp_tables)[0]; uint8_t *power_table = &((uint8_t*)rp_tables)[MAX_DEVICES]; // loop forever for (;;) { // Block until next table is ready pthread_mutex_lock ( &mutex_route_start ); // Assuming rssi_table has been updated clean_table( rssi_table ); add_links_from_table( rssi_table ); // Run dijkstra's algorithm with 0 being the access point dijkstra( AP_NODE_ID, c_factor ); // Display shortest paths and update energies for( node_index = 1; node_index < (MAX_DEVICES + 1); node_index++ ) { compute_shortest_path( node_index ); print_shortest_path( node_index ); } // Compute routing table compute_rp_tables( route_table, link_powers ); // Debug memcpy( previous_powers_debug, previous_powers, sizeof(previous_powers) ); memcpy( route_table_debug, route_table, sizeof(route_table_debug) ); // Compute power table compute_required_powers( link_powers, power_table ); print_rssi_table(); print_node_energy( AP_NODE_ID, fp_energies ); index++; printf("\nRound %d\n", index); // Block until next table is ready pthread_mutex_unlock ( &mutex_route_done ); } return NULL; }
auto replan(Cells const& cells_to_toggle = {}) { reset_statistics(); for (auto c : cells_to_toggle) { at(c).bad = !at(c).bad; if (!at(c).bad) update_vertex(at(c)); else at(c).g = at(c).r = huge(); update_neighbours_of(c); } compute_shortest_path(); }
// e - supply(positive) and demand(negative). // c[i] - edges that goes from node i. first is the second nod // x - the flow is returned in it NUM_T operator()(std::vector<NUM_T>& e, const std::vector< std::list< edge<NUM_T> > >& c, std::vector< std::list< edge0<NUM_T> > >& x) { //for (NODE_T i=0; i<e.size(); ++i) cout << e[i]<< " "; //cout << endl; //tictoc_all_function.tic(); assert(e.size()==c.size()); assert(x.size()==c.size()); _num_nodes= (NODE_T)e.size(); _nodes_to_Q.resize(_num_nodes); // init flow {for (NODE_T from=0; from<_num_nodes; ++from) { {for (typename std::list< edge<NUM_T> >::const_iterator it= c[from].begin(); it!=c[from].end(); ++it) { x[from].push_back( edge0<NUM_T> (it->_to, it->_cost, 0) ); x[it->_to].push_back( edge0<NUM_T> (from, -it->_cost,0) ); }} // it }} // from // reduced costs for forward edges (c[i,j]-pi[i]+pi[j]) // Note that for forward edges the residual capacity is infinity std::vector< std::list< edge1<NUM_T> > > r_cost_forward(_num_nodes); {for (NODE_T from=0; from<_num_nodes; ++from) { {for (typename std::list< edge<NUM_T> >::const_iterator it= c[from].begin(); it!=c[from].end(); ++it) { r_cost_forward[from].push_back( edge1<NUM_T>(it->_to,it->_cost) ); }} }} // reduced costs and capacity for backward edges (c[j,i]-pi[j]+pi[i]) // Since the flow at the beginning is 0, the residual capacity is also zero std::vector< std::list< edge2<NUM_T> > > r_cost_cap_backward(_num_nodes); {for (NODE_T from=0; from<_num_nodes; ++from) { {for (typename std::list< edge<NUM_T> >::const_iterator it= c[from].begin(); it!=c[from].end(); ++it) { r_cost_cap_backward[ it->_to ].push_back( edge2<NUM_T>(from,-it->_cost,0) ); }} // it }} // from // Max supply TODO:demand?, given U?, optimization-> min out of demand,supply NUM_T U= 0; {for (NODE_T i=0; i<_num_nodes; ++i) { if (e[i]>U) U= e[i]; }} NUM_T delta= static_cast<NUM_T>(pow(2.0l,ceil(log(static_cast<long double>(U))/log(2.0)))); std::vector< NUM_T > d(_num_nodes); std::vector< NODE_T > prev(_num_nodes); delta= 1; //while (delta>=1) { // delta-scaling phase //cout << "delta==" << delta << endl; //tictoc_while_true.tic(); while (true) { //until we break when S or T is empty NUM_T maxSupply= 0; NODE_T k=0; for (NODE_T i=0; i<_num_nodes; ++i) { if (e[i]>0) { if (maxSupply<e[i]) { maxSupply= e[i]; k= i; } } } if (maxSupply==0) break; delta= maxSupply; NODE_T l; //tictoc_shortest_path.tic(); compute_shortest_path(d,prev, k,r_cost_forward,r_cost_cap_backward , e,l); //tictoc_shortest_path.toc(); //--------------------------------------------------------------- // find delta (minimum on the path from k to l) //delta= e[k]; //if (-e[l]<delta) delta= e[k]; NODE_T to= l; do { NODE_T from= prev[to]; assert(from!=to); // residual typename std::list< edge2<NUM_T> >::iterator itccb= r_cost_cap_backward[from].begin(); while ( (itccb!=r_cost_cap_backward[from].end()) && (itccb->_to!=to) ) { ++itccb; } if (itccb!=r_cost_cap_backward[from].end()) { if (itccb->_residual_capacity<delta) delta= itccb->_residual_capacity; } to= from; } while (to!=k); //--------------------------------------------------------------- //--------------------------------------------------------------- // augment delta flow from k to l (backwards actually...) to= l; do { NODE_T from= prev[to]; assert(from!=to); // TODO - might do here O(n) can be done in O(1) typename std::list< edge0<NUM_T> >::iterator itx= x[from].begin(); while (itx->_to!=to) { ++itx; } itx->_flow+= delta; // update residual for backward edges typename std::list< edge2<NUM_T> >::iterator itccb= r_cost_cap_backward[to].begin(); while ( (itccb!=r_cost_cap_backward[to].end()) && (itccb->_to!=from) ) { ++itccb; } if (itccb!=r_cost_cap_backward[to].end()) { itccb->_residual_capacity+= delta; } itccb= r_cost_cap_backward[from].begin(); while ( (itccb!=r_cost_cap_backward[from].end()) && (itccb->_to!=to) ) { ++itccb; } if (itccb!=r_cost_cap_backward[from].end()) { itccb->_residual_capacity-= delta; } // update e e[to]+= delta; e[from]-= delta; to= from; } while (to!=k); //--------------------------------------------------------------------------------- } // while true (until we break when S or T is empty) //tictoc_while_true.toc(); //cout << "while true== " << tictoc_while_true.totalTimeSec() << endl; //delta= delta/2; //} // (delta-scaling phase) // compute distance from x //cout << endl << endl; NUM_T dist= 0; {for (NODE_T from=0; from<_num_nodes; ++from) { {for (typename std::list< edge0<NUM_T> >::const_iterator it= x[from].begin(); it!=x[from].end(); ++it) { // if (it->_flow!=0) cout << from << "->" << it->_to << ": " << it->_flow << "x" << it->_cost << endl; dist+= (it->_cost*it->_flow); }} // it }} // from //tictoc_all_function.toc(); //cout << "operator() time==" << tictoc_all_function.totalTimeSec() << endl; //cout << "compute_shortest_path_time==" << tictoc_shortest_path.totalTimeSec() << endl; //cout << "tmp_tic_toc== " << tmp_tic_toc.totalTimeSec() << endl; return dist; } // operator()
auto plan() { reset_statistics(); initialize(); compute_shortest_path(); }
static int compute_shortest_path(char* sql, int start_vertex, int end_vertex, bool directed, bool has_reverse_cost, path_element_t **path, int *path_count) { int SPIcode; void *SPIplan; Portal SPIportal; bool moredata = TRUE; int ntuples; edge_t *edges = NULL; int total_tuples = 0; edge_columns_t edge_columns = {id: -1, source: -1, target: -1, cost: -1, reverse_cost: -1}; int v_max_id=0; int v_min_id=INT_MAX; int s_count = 0; int t_count = 0; char *err_msg; int ret = -1; register int z; DBG("start shortest_path\n"); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "shortest_path: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "shortest_path: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "shortest_path: SPI_cursor_open('%s') returns NULL", sql); return -1; } while (moredata == TRUE) { SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT); if (edge_columns.id == -1) { if (fetch_edge_columns(SPI_tuptable, &edge_columns, has_reverse_cost) == -1) return finish(SPIcode, ret); } ntuples = SPI_processed; total_tuples += ntuples; if (!edges) edges = palloc(total_tuples * sizeof(edge_t)); else edges = repalloc(edges, total_tuples * sizeof(edge_t)); if (edges == NULL) { elog(ERROR, "Out of memory"); return finish(SPIcode, ret); } if (ntuples > 0) { int t; SPITupleTable *tuptable = SPI_tuptable; TupleDesc tupdesc = SPI_tuptable->tupdesc; for (t = 0; t < ntuples; t++) { HeapTuple tuple = tuptable->vals[t]; fetch_edge(&tuple, &tupdesc, &edge_columns, &edges[total_tuples - ntuples + t]); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } //defining min and max vertex id DBG("Total %i tuples", total_tuples); for(z=0; z<total_tuples; z++) { if(edges[z].source<v_min_id) v_min_id=edges[z].source; if(edges[z].source>v_max_id) v_max_id=edges[z].source; if(edges[z].target<v_min_id) v_min_id=edges[z].target; if(edges[z].target>v_max_id) v_max_id=edges[z].target; DBG("%i <-> %i", v_min_id, v_max_id); } //:::::::::::::::::::::::::::::::::::: //:: reducing vertex id (renumbering) //:::::::::::::::::::::::::::::::::::: for(z=0; z<total_tuples; z++) { //check if edges[] contains source and target if(edges[z].source == start_vertex || edges[z].target == start_vertex) ++s_count; if(edges[z].source == end_vertex || edges[z].target == end_vertex) ++t_count; edges[z].source-=v_min_id; edges[z].target-=v_min_id; DBG("%i - %i", edges[z].source, edges[z].target); } DBG("Total %i tuples", total_tuples); if(s_count == 0) { elog(ERROR, "Source vertex: %d was not found as vertex of any of the input edges.", start_vertex); return -1; } if(t_count == 0) { elog(ERROR, "Target vertex: %d was not found as vertex of any of the input edges.", end_vertex); return -1; } DBG("Calling boost_dijkstra\n"); start_vertex -= v_min_id; end_vertex -= v_min_id; ret = boost_dijkstra(edges, total_tuples, start_vertex, end_vertex, directed, has_reverse_cost, path, path_count, &err_msg); DBG("SIZE %i\n",*path_count); //:::::::::::::::::::::::::::::::: //:: restoring original vertex id //:::::::::::::::::::::::::::::::: for(z=0;z<*path_count;z++) { //DBG("vetex %i\n",(*path)[z].vertex_id); (*path)[z].vertex_id+=v_min_id; } DBG("ret = %i\n", ret); DBG("*path_count = %i\n", *path_count); DBG("ret = %i\n", ret); if (ret < 0) { //elog(ERROR, "Error computing path: %s", err_msg); ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing path: %s", err_msg))); } if (edges) { /* clean up input egdes */ pfree (edges); } return finish(SPIcode, ret); } PG_FUNCTION_INFO_V1(shortest_path); Datum shortest_path(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; path_element_t *path = NULL; char *sql = NULL; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int path_count = 0; int ret; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* edge sql query */ sql = text2char(PG_GETARG_TEXT_P(0)); ret = compute_shortest_path(sql, PG_GETARG_INT32(1), PG_GETARG_INT32(2), PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), &path, &path_count); /* clean up sql query string */ if (sql) { pfree (sql); } #ifdef DEBUG DBG("Ret is %i", ret); if (ret >= 0) { int i; for (i = 0; i < path_count; i++) { DBG("Step %i vertex_id %i ", i, path[i].vertex_id); DBG(" edge_id %i ", path[i].edge_id); DBG(" cost %f ", path[i].cost); } } #endif /* total number of tuples to be returned */ funcctx->max_calls = path_count; funcctx->user_fctx = path; funcctx->tuple_desc = BlessTupleDesc(RelationNameGetTupleDesc("path_result")); MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; tuple_desc = funcctx->tuple_desc; path = (path_element_t*) funcctx->user_fctx; if (call_cntr < max_calls) /* do when there is more left to send */ { HeapTuple tuple; Datum result; Datum *values; char* nulls; /* This will work for some compilers. If it crashes with segfault, try to change the following block with this one values = palloc(4 * sizeof(Datum)); nulls = palloc(4 * sizeof(char)); values[0] = call_cntr; nulls[0] = ' '; values[1] = Int32GetDatum(path[call_cntr].vertex_id); nulls[1] = ' '; values[2] = Int32GetDatum(path[call_cntr].edge_id); nulls[2] = ' '; values[3] = Float8GetDatum(path[call_cntr].cost); nulls[3] = ' '; */ values = palloc(3 * sizeof(Datum)); nulls = palloc(3 * sizeof(char)); values[0] = Int32GetDatum(path[call_cntr].vertex_id); nulls[0] = ' '; values[1] = Int32GetDatum(path[call_cntr].edge_id); nulls[1] = ' '; values[2] = Float8GetDatum(path[call_cntr].cost); nulls[2] = ' '; tuple = heap_formtuple(tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); /* clean up (this is not really necessary) */ pfree(values); pfree(nulls); SRF_RETURN_NEXT(funcctx, result); } else /* do when there is no more left */ { if (path) { /* clean up returned edge paths must be a free because it's malloc'd */ free (path); path = NULL; } SRF_RETURN_DONE(funcctx); } }
Datum shortest_path(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; pgr_path_element3_t *ret_path = 0; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int path_count = 0; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); compute_shortest_path(pgr_text2char(PG_GETARG_TEXT_P(0)), PG_GETARG_INT64(1), PG_GETARG_INT64(2), PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), &ret_path, &path_count); /* total number of tuples to be returned */ funcctx->max_calls = path_count; funcctx->user_fctx = ret_path; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); funcctx->tuple_desc = tuple_desc; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; tuple_desc = funcctx->tuple_desc; ret_path = (pgr_path_element3_t*) funcctx->user_fctx; /* do when there is more left to send */ if (call_cntr < max_calls) { HeapTuple tuple; Datum result; Datum *values; char* nulls; values = palloc(6 * sizeof(Datum)); nulls = palloc(6 * sizeof(char)); values[0] = Int32GetDatum(ret_path[call_cntr].seq); nulls[0] = ' '; values[1] = Int32GetDatum(ret_path[call_cntr].seq); nulls[1] = ' '; values[2] = Int64GetDatum(ret_path[call_cntr].vertex); nulls[2] = ' '; values[3] = Int64GetDatum(ret_path[call_cntr].edge); nulls[3] = ' '; values[4] = Float8GetDatum(ret_path[call_cntr].cost); nulls[4] = ' '; values[5] = Float8GetDatum(ret_path[call_cntr].tot_cost); nulls[5] = ' '; tuple = heap_formtuple(tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); /* clean up (this is not really necessary) */ pfree(values); pfree(nulls); SRF_RETURN_NEXT(funcctx, result); } else { /* do when there is no more left */ if (ret_path) free(ret_path); SRF_RETURN_DONE(funcctx); } }