int main( void ){ Timer T(true); int final_nodes_num, edge_addition_num; final_nodes_num = 30000; edge_addition_num = 7; ListGraph mGr; lemon::Random mRandom; mRandom.seedFromTime(); vector<int> nodeChoice; set<int> mRndNodes; vector<int> targets(edge_addition_num, -1); int currentIndex = 0; // First targets are all nodes for(auto &v : targets){ v = currentIndex++; mGr.addNode(); } while (countNodes(mGr)<final_nodes_num ) { // Add new node and connect to targets currentIndex = mGr.id( mGr.addNode() ); for(const auto &v : targets ){ mGr.addEdge( mGr.nodeFromId( currentIndex ), mGr.nodeFromId( v ) ); } // Add the nodes, which were connented again nodeChoice.insert(nodeChoice.end(), targets.begin(), targets.end() ); nodeChoice.insert(nodeChoice.end(), edge_addition_num, currentIndex); mRndNodes.clear(); while (mRndNodes.size() < edge_addition_num) { mRndNodes.insert( nodeChoice[ mRandom.integer( nodeChoice.size() ) ] ); } targets.clear(); targets.insert(targets.begin(), mRndNodes.begin(), mRndNodes.end() ); } cout << "time: " << T.realTime() << endl; cout << countNodes( mGr) << endl; cout << countEdges( mGr) << endl; graphWriter( mGr, "/Users/sonneundasche/Documents/FLI/DATA/05 LEMON Graphs/BaraBasiTEST.txt") .run(); InDegMap<ListGraph> inDeg(mGr); graphWriter( mGr, "/Users/sonneundasche/Documents/FLI/DATA/05 LEMON Graphs/BaraBasi_Degree_TEST.txt") .nodeMap("degree", inDeg) .skipEdges() .run(); }
void ViewTspCircuit(TSP_Data &tsp) { ListGraph h; ListGraph::NodeMap<string> h_vname(h); // node names ListGraph::NodeMap<Node> h_g2h(tsp.g); // maps a node of g to a node of h ListGraph::NodeMap<double> h_posx(h); ListGraph::NodeMap<double> h_posy(h); ListGraph::NodeMap<int> vcolor(h); // color of the vertices ListGraph::EdgeMap<int> acolor(h); // color of edges ListGraph::EdgeMap<string> aname(h); // name of edges for (ListGraph::NodeIt v(tsp.g); v!=INVALID; ++v) { Node hv; hv = h.addNode(); h_g2h[v] = hv; h_posx[hv] = tsp.posx[v]; h_posy[hv] = tsp.posy[v]; h_vname[hv] = tsp.vname[v]; vcolor[hv] = BLUE; } for (int i=0;i<tsp.NNodes;i++) { ListGraph::Node u,v; ListGraph::Edge a; u = tsp.BestCircuit[i]; v = tsp.BestCircuit[(i+1) % tsp.NNodes]; a = h.addEdge(h_g2h[u] , h_g2h[v]); aname[a] = ""; acolor[a] = BLUE; } ViewListGraph(h,h_vname,aname,h_posx,h_posy,vcolor,acolor,"TSP Circuit with cost "+DoubleToString(tsp.BestCircuitValue)); }
//Generate a random complete euclidean ListGraph bool GenerateRandomEuclideanListGraph(ListGraph &g, NodeStringMap &vname, // node names NodePosMap& px, // x-position of the nodes NodePosMap& py, // y-position of the nodes EdgeValueMap& weight, // weight of edges int n, // number of nodes double SizeX, // coordinate x is a random number in [0,SizeX) double SizeY) // coordinate y is a random number in [0,SizeY) { int i,j; // n=number of nodes Node *V; V = new Node[n]; if (V==NULL){ cout << "Memory allocation error, number of nodes " << n << " too large\n"; exit(0);} for (i=0;i<n;i++) { // insert nodes (random points in [0,100] x [0,100] ) V[i] = g.addNode(); // generate a new node px[V[i]] = SizeX*drand48(); py[V[i]] = SizeY*drand48(); vname[V[i]] = IntToString(i+1); // name of the node is i+1 } for (i=0;i<n;i++) for (j=i+1;j<n;j++) { Edge e = g.addEdge(V[i],V[j]); // generate an edge weight[e] = sqrt(pow(px[V[i]]-px[V[j]],2) + pow(py[V[i]]-py[V[j]],2)); } delete[] V; return(true); }
// To read list of nodes in the format: <node_name> <double1> <double2> void ReadListGraphNodes(ListGraph &g,int nnodes,ifstream & ifile, #if __cplusplus >= 201103L std::unordered_map<string,Node> & string2node, #else std::tr1::unordered_map<string,Node> & string2node, #endif NodeStringMap &vname, NodePosMap &posx, NodePosMap &posy) { string STR; Node u,v; string token; for (int i=0;i<nnodes;i++) { getline(ifile,STR); if (ifile.eof()) {cout<<"Reached unexpected end of file.\n";exit(0);} while (STR=="") getline(ifile,STR); { istringstream ins; // Declare an input string stream. ins.str(STR); // Specify string to read. for (int p=0; getline(ins, token, ' ') ; p++) { if (p==0) { // For example, to read: node_name posx posy auto test = string2node.find(token); if (test!=string2node.end()){cout<<"ERROR: Repeated node: "<<token<<endl;exit(0);} v = g.addNode(); string2node[token] = v; vname[v] = token; posx[v]=DBL_MAX; posy[v]=DBL_MAX; } else if (p==1) { posx[v] = atof(token.c_str());} else if (p==2) { posy[v] = atof(token.c_str());} }} } }
int ViewGomoryHuTree(ListGraph &g, NodeStringMap& vname, GomoryHu<ListGraph, EdgeValueMap > &ght, double threshold, string text) { ListGraph T; NodeNodeMap map(g); Edge te; EdgeStringMap tename(T); // name of T edges NodeStringMap tvname(T); // name of T nodes NodeColorMap tvcolor(T); // color of the vertices EdgeColorMap tecolor(T); // color of the edges for (NodeIt v(g); v != INVALID; ++v) { map[v] = T.addNode(); tvname[map[v]] = vname[v]; tvcolor[map[v]] = BLACK; } for (NodeIt u(g); u != INVALID; ++u) { if ((g).id(ght.predNode(u))==-1) continue; te = T.addEdge(map[u], map[ght.predNode(u)]); tename[te] = DoubleToString(ght.predValue(u)); if (ght.predValue(u)<threshold-MY_EPS) tecolor[te] = RED; else tecolor[te] = BLUE; } return(ViewListGraph(g,tvname,tename,tvcolor,tecolor,text)); }
int ViewGomoryHuTree(ListGraph &g, NodeStringMap &vname, NodePosMap &px, // xy-coodinates for each node NodePosMap &py, // GomoryHu<ListGraph, EdgeValueMap > &ght, string text) { ListGraph T; NodeNodeMap map(g); Edge te; EdgeStringMap tename(T); // name of T edges EdgeValueMap teweight(T); // name of T edges NodeStringMap tvname(T); // name of T nodes NodePosMap tpx(T); // xy-coodinates for each node NodePosMap tpy(T); // NodeColorMap tvcolor(T); // color of the vertices EdgeColorMap tecolor(T); // color of the edges for (NodeIt v(g); v != INVALID; ++v) { map[v] = T.addNode(); tvname[map[v]] = vname[v]; tvcolor[map[v]] = WHITE; tpx[map[v]] = px[v]; tpy[map[v]] = py[v]; } for (NodeIt u(g); u != INVALID; ++u) { if ((g).id(ght.predNode(u))==-1) continue; te = T.addEdge(map[u], map[ght.predNode(u)]); tename[te] = DoubleToString(ght.predValue(u)); teweight[te] = ght.predValue(u); tecolor[te] = BLUE; } return(ViewListGraph(T,tvname,tename,tpx,tpy,tvcolor,tecolor,text)); }
// Generate a triangulated ListGraph, building the Delaunay // triangulation of random points // Uses the geompack program, available in // http://people.sc.fsu.edu/~jburkardt/cpp_src/geompack/geompack.html bool GenerateTriangulatedListGraph(ListGraph &g, // return with generated graph NodeStringMap &vname, // return with name of the nodes NodePosMap& px, // return with x-position of the nodes NodePosMap& py, // return with y-position of the nodes EdgeValueMap& weight, // return with weight of edges int n, // number of nodes double SizeX, // coordinate x is a random number in [0,SizeX) double SizeY) // coordinate y is a random number in [0,SizeY) { int i; // n=number of nodes int ntri; // number of Delaunay triangles Node *V = new Node[n]; double *p = new double[2*n+2];// node coodinates are (x;y) = ( p[2*i] ; p[2*i+1] ) int *tri = new int[6*n]; // Each 3 elements are the indexes of a triangle int *tri_nabe = new int[6*n]; if ((V==NULL)||(p==NULL)||(tri==NULL)||(tri_nabe==NULL)){ cout << "Memory allocation error, number of nodes " << n << " too large\n"; exit(0);} for (i=0;i<n;i++) { V[i] = g.addNode(); // gera um vértice nó do grafo px[V[i]] = SizeX*drand48(); // nodes are random points py[V[i]] = SizeY*drand48(); p[2*i] = px[V[i]]; p[2*i+1] = py[V[i]]; vname[V[i]] = IntToString(i+1); // name of the node is i+1 } if (r8tris2 ( n, p, &ntri, tri, tri_nabe )) { printf("ERROR\n");Pause(); } for (i=0;i<ntri;i++) { int a,b,c; a = tri[3*i]-1; b = tri[3*i+1]-1; c = tri[3*i+2]-1; // each triangle if formed with nodes V[a] , V[b] , V[c] // insert edges without duplications if ((findEdge(g,V[a],V[b])==INVALID) && (findEdge(g,V[b],V[a])==INVALID)){ Edge e = g.addEdge(V[a],V[b]); weight[e] = sqrt(pow(px[V[a]]-px[V[b]],2) + pow(py[V[a]]-py[V[b]],2)); } if ((findEdge(g,V[a],V[c])==INVALID) && (findEdge(g,V[c],V[a])==INVALID)){ Edge e = g.addEdge(V[a],V[c]); weight[e] = sqrt(pow(px[V[a]]-px[V[c]],2) + pow(py[V[a]]-py[V[c]],2)); } if ((findEdge(g,V[b],V[c])==INVALID) && (findEdge(g,V[c],V[b])==INVALID)) { Edge e = g.addEdge(V[b],V[c]); weight[e] = sqrt(pow(px[V[b]]-px[V[c]],2) + pow(py[V[b]]-py[V[c]],2)); } } delete[] V; delete[] p; delete[] tri; delete[] tri_nabe; return(true); }
int main( void ){ Timer T(true); int init_nodes_num, final_nodes_num, edge_addition_num; init_nodes_num = 10; final_nodes_num = 50; edge_addition_num = 7; typedef ListEdgeSet< ListGraph > EdgeSet; ListGraph mListGraph; EdgeSet mNewEdges( mListGraph ); FullGraph fg(init_nodes_num); GraphCopy<FullGraph, ListGraph> cg( fg, mListGraph); // Create the seed nodes cg.run(); int mNumEdges = countEdges( mListGraph ); EdgeSet::Edge e; lemon::Random mRandom; mRandom.seedFromTime(); ListGraph::Node newNode, randNode; // new edges will be saved seperatly in an EdgeSet, not to change the original node degrees for ( int i = init_nodes_num; i < final_nodes_num; i++){ mNumEdges = countEdges( mListGraph ); mNewEdges.clear(); newNode = mListGraph.addNode(); while ( countEdges( mNewEdges ) != edge_addition_num ) { randNode = mListGraph.nodeFromId( mRandom[ mListGraph.maxNodeId() ] ) ; // --- CALCULATE THE PROBABILITY if ( mRandom.real() < (( (double)(countIncEdges(mListGraph, randNode)) / (double)( 2*mNumEdges ) )) ){ if ( findEdge( mNewEdges, newNode, randNode ) == INVALID){ // does the edge already exist? mNewEdges.addEdge( newNode, randNode ); } } } // Create the new edges in the original graph for (EdgeSet::EdgeIt e( mNewEdges ); e!=INVALID; ++e){ mListGraph.addEdge( mNewEdges.u( e ), mNewEdges.v(e) ); } } cout << T.realTime() << endl; cout << countEdges( mListGraph) << endl; cout << countEdges( fg ) << endl; }
bool ReadEuclideanListGraph(string filename, ListGraph &g, NodeStringMap & vname, EdgeValueMap & custo, NodePosMap & posx, NodePosMap & posy, NodeBoolMap& is_terminal) { int i,n,m, terminal; Node nu,nv; Edge a; char nomev[100]; Node v; double px,py; ifstream ifile; ifile.open(filename.c_str()); if (!ifile) return(false); PulaBrancoComentario(ifile); // format: <number_of_nodes> -1 // The value -1 is to indicate that there is no edge/arc, as edge weights // are given by the euclidean distance ifile >> n; ifile >> m; if (m!=-1) { printf("Wrong format in the euclidean graph of file %s.\n",filename.c_str()); return(false); } for (i=0;i<n;i++) { ifile >> nomev; ifile >> px; ifile >> py; ifile >> terminal; v = g.addNode(); vname[v] = nomev; posx[v] = px; posy[v] = py; if(terminal == 0) is_terminal[v] = false; else is_terminal[v] = true; } for (NodeIt v(g); v!=INVALID; ++v) { NodeIt u(g); u=v; for (++u; u!=INVALID; ++u) { a = g.addEdge(u,v); custo[a] = sqrt((posx[u]-posx[v])*(posx[u]-posx[v]) + (posy[u]-posy[v])*(posy[u]-posy[v])); } } ifile.close(); return(true); }
//指定一些特殊分支,要求搜索一条路径时尽可能多的通过这些特殊分支 //例如:搜索一条串联通风路径(通过多个用风地点的一条路径) //采用二分匹配实现失败!!! static bool MaxKeyEdgePass_Match(Digraph& dg, EdgeArray& airEdges, Digraph::Node s, Digraph::Node t, EdgeArray& mpp) { EdgeArray p; if(!GraphUtils::DFS_Path(dg, s, t, p)) return false; typedef Digraph::NodeMap<Digraph::Node> DDMap; DDMap ddm(dg, INVALID); NodeArray left, right; left.push_back(s); right.push_back(t); for(size_t i=0;i<airEdges.size();i++) { Digraph::Arc e = airEdges[i]; Digraph::Node u = dg.source(e); Digraph::Node v = dg.target(e); p.clear(); bool ret = GraphUtils::DFS_Path(dg, v, t, p); if(!ret) continue; p.clear(); ret = GraphUtils::DFS_Path(dg, s, u, p); if(!ret) continue; left.push_back(v); right.push_back(u); } //cout<<"left="<<left.size()<<" right="<<right.size()<<endl; ListGraph g; ListGraph::NodeMap<Digraph::Node> udm(g); typedef std::vector<ListGraph::Node> UNodeArray; UNodeArray left_nodes, right_nodes; typedef std::map<Digraph::Node, ListGraph::Node> DUMap; DUMap dum; //添加节点 for(size_t i=0;i<left.size();i++) { Digraph::Node u = left[i]; ListGraph::Node uu = g.addNode(); udm[uu] = u; left_nodes.push_back(uu); //cout<<dg.id(u)<< " "; } //cout<<endl; for(size_t i=0;i<right.size();i++) { Digraph::Node u = right[i]; ListGraph::Node uu = g.addNode(); udm[uu] = u; right_nodes.push_back(uu); //cout<<dg.id(u)<<" "; } //cout<<endl; for(size_t i=0;i<right.size();i++) { Digraph::Node u = right[i]; ListGraph::Node uu = g.addNode(); udm[uu] = u; left_nodes.push_back(uu); //cout<<dg.id(u)<< " "; } //cout<<endl; for(size_t i=0;i<left.size();i++) { Digraph::Node u = left[i]; ListGraph::Node uu = g.addNode(); udm[uu] = u; right_nodes.push_back(uu); //cout<<dg.id(u)<< " "; } //cout<<endl; //添加分支 for(size_t i=0;i<left_nodes.size();i++) { ListGraph::Node uv = left_nodes[i]; for(size_t j=0;j<right_nodes.size();j++) { ListGraph::Node uu = right_nodes[j]; Digraph::Node v = udm[uv]; Digraph::Node u = udm[uu]; if(u == v) continue; p.clear(); if(GraphUtils::DFS_Path(dg, v, u, p)) { //ListGraph::Node uv = left_nodes[i]; //ListGraph::Node uu = right_nodes[j]; ListGraph::Edge e = g.addEdge(uu,uv); //cout<<"二分图:"<<dg.id(v)<<"<-->"<<dg.id(u)<<endl; } } } //二分图最大匹配 MaxMatching<ListGraph> mm(g); mm.run(); //cout<<"分支数:"<<countEdges(g)<<" 匹配数:"<<mm.matchingSize()<<endl; for(ListGraph::EdgeIt e(g);e!=INVALID;++e) { if(mm.matching(e)) { ListGraph::Node du = g.u(e); ListGraph::Node dv = g.v(e); Digraph::Node u = udm[du]; Digraph::Node v = udm[dv]; //cout<<"匹配:"<<dg.id(v)<<"<-->"<<dg.id(u)<<endl; if(ddm[u] != INVALID && ddm[v] == INVALID) { ddm[v] = u; //cout<<" v"<<dg.id(v)<<"-->v"<<dg.id(u) <<" v"<<dg.id(u)<<"-->"<<dg.id(ddm[u])<<endl; } else if(ddm[v] != INVALID && ddm[u] == INVALID) { ddm[u] = v; //cout<<" v"<<dg.id(v)<<"-->v"<<dg.id(ddm[v]) <<" v"<<dg.id(u)<<"-->"<<dg.id(v)<<endl; } } } NodeArray node_path; Digraph::Node u = s; bool ret = true; while(u != t) { Digraph::Node v = ddm[u]; //cout<<dg.id(u)<<"->"<<endl; if(v == INVALID) { //cout<<"错误"<<endl; ret = false; break; } //cout<<" ->"<<dg.id(v)<<" "<<endl; node_path.push_back(v); u = v; } if(ret) { u = s; for(size_t i=0;i<node_path.size();i++) { Digraph::Node v = node_path[i]; GraphUtils::DFS_Path(dg, u, v, mpp); u = v; } } return ret; }
int Steiner::steiner(const set<ListGraph::Node> terminals) { if (this->s != 0) delete this->s; this->s = new ListGraph(); if (this->sweight != 0) delete this->sweight; this->sweight = new ListGraph::EdgeMap<int>(*this->s); // perform dijkstra for every terminal ListGraph::NodeMap<Dijkstra*> dijk(this->g); for (set<ListGraph::Node>::iterator it = terminals.begin(); it != terminals.end(); ++it) { dijk[*it] = new Dijkstra(this->g, this->weight); dijk[*it]->dijkstra(*it); } // build intermediate graph ListGraph intermediate; ListGraph::EdgeMap<int> iweight(intermediate); map<ListGraph::Node, ListGraph::Node> imapper; for (set<ListGraph::Node>::iterator it = terminals.begin(); it != terminals.end(); ++it) { ListGraph::Node n = intermediate.addNode(); imapper[n] = *it; } for (ListGraph::NodeIt it1(intermediate); it1 != INVALID; ++it1) { ListGraph::NodeIt it2 = it1; for (++it2; it2 != INVALID; ++it2) { ListGraph::Edge e = intermediate.addEdge(it1, it2); iweight[e] = (*dijk[imapper[it1]]->dist)[imapper[it2]]; } } // compute mst MST mst(intermediate, iweight); mst.prim(); // Kruskal mst(intermediate, iweight); // mst.kruskal(); // build final graph map<ListGraph::Node, ListGraph::Node> smapper; for (set<ListGraph::Edge>::iterator it = mst.mst->begin(); it != mst.mst->end(); ++it) { // for each edge in the mst // add end nodes to graph ListGraph::Node u = imapper[intermediate.u(*it)]; if (smapper.count(u) == 0) smapper[u] = this->s->addNode(); ListGraph::Node v = imapper[intermediate.v(*it)]; if (smapper.count(v) == 0) smapper[v] = this->s->addNode(); ListGraph::Node last = v; ListGraph::Node cur = v; do { // walk through path cur = (*dijk[u]->pred)[cur]; if (smapper.count(cur) == 0) smapper[cur] = this->s->addNode(); // add edge to graph, if not already existing if (findEdge(*this->s, smapper[last], smapper[cur]) == INVALID) { ListGraph::Edge e = this->s->addEdge(smapper[last], smapper[cur]); (*this->sweight)[e] = (*dijk[u]->dist)[last] - (*dijk[u]->dist)[cur]; } last = cur; } while (cur != u); } // compute overall weight int overallw = 0; for (ListGraph::EdgeIt e(*this->s); e != INVALID; ++e) { overallw += (*this->sweight)[e]; } // clean up dijkstras for (set<ListGraph::Node>::iterator it = terminals.begin(); it != terminals.end(); ++it) { delete dijk[*it]; } return overallw; }
void callback() { // -------------------------------------------------------------------------------- // get the correct function to obtain the values of the lp variables if (where==GRB_CB_MIPSOL) // if this condition is true, all variables are integer {solution_value = &subtourelim::getSolution;} else if ((where==GRB_CB_MIPNODE) && (getIntInfo(GRB_CB_MIPNODE_STATUS)==GRB_OPTIMAL))// node with optimal fractional solution {solution_value = &subtourelim::getNodeRel;} else return; // return, as this code do not take advantage of the other options // -------------------------------------------------------------------------------- // Stores the edges with fractional values and integer values vector<Edge> FracEdges,OneEdges; // produces a subgraph h of g, with edges e with x[e]==1 // contracted, so we can apply Gomory-Hu tree in a small graph ListGraph::EdgeMap<bool> one_filter(tsp.g, false); // start without any edge ListGraph::EdgeMap<bool> non_zero_filter(tsp.g, false); // start without any edge for (EdgeIt e(tsp.g); e != INVALID; ++e) { if ((this->*solution_value)(x[e]) > 1-MY_EPS) OneEdges.push_back(e); // stores the edges with x[e]==1 else if ((this->*solution_value)(x[e]) > MY_EPS) FracEdges.push_back(e); // includes edges with 0 < x[e] < 1 }// define the subgraph with edges that have x[e]==1 try { // -------------------------------------------------------------------------------- // Use union-find to contract nodes (to obtain graph where each componente of g is contracted) //for (int i=0;i<tsp.NNodes;i++) UFIndexToNode[i]=INVALID; ListGraph::NodeMap<int> aux_map(tsp.g); UnionFind<ListGraph::NodeMap<int> > UFNodes(aux_map); for (NodeIt v(tsp.g); v!=INVALID; ++v) UFNodes.insert(v); for (vector<Edge>::iterator e_it=OneEdges.begin(); e_it != OneEdges.end(); ++e_it) UFNodes.join(tsp.g.u(*e_it),tsp.g.v(*e_it));// No problem if they are in a same component // -------------------------------------------------------------------------------- // Put in a separate set all edges that are not inside a component vector<Edge> CrossingEdges; for (EdgeIt e(tsp.g); e != INVALID; ++e) if (UFNodes.find(tsp.g.u(e)) != UFNodes.find(tsp.g.v(e))) CrossingEdges.push_back(e); // -------------------------------------------------------------------------------- // Generate an inverted list UFIndexToNode to find the node that represents a component vector<bool> ComponentIndex(tsp.NNodes); vector<Node> Index2h(tsp.NNodes); for(int i=0;i<tsp.NNodes;i++) ComponentIndex[i]=false; for (NodeIt v(tsp.g); v!=INVALID; ++v) ComponentIndex[UFNodes.find(v)]=true; // -------------------------------------------------------------------------------- // Generate graph of components, add one node for each component and edges ListGraph h; EdgeValueMap h_capacity(h); for(int i=0;i<tsp.NNodes;i++) // add nodes to the graph h if (ComponentIndex[i]) Index2h[i]=h.addNode(); for (vector<Edge>::iterator e_it=FracEdges.begin(); e_it != FracEdges.end(); ++e_it){ Node u = tsp.g.u(*e_it), v = tsp.g.v(*e_it), hu = Index2h[UFNodes.find(u)], hv = Index2h[UFNodes.find(v)]; Edge a = h.addEdge(hu , hv ); // add edges to the graph h h_capacity[a] = (this->*solution_value)(x[*e_it]); } // create a map to terminals NodeBoolMap HasTerminal(h); for (NodeIt uit(tsp.g); uit!=INVALID; ++uit) { // if it is not a station if(!postos[uit]) { HasTerminal[Index2h[UFNodes.find(uit)]] = true; } } // add the source to the 'terminal' HasTerminal[Index2h[UFNodes.find(source)]] = true; // -------------------------------------------------------------------------------- GomoryHu<ListGraph, EdgeValueMap> ght(h, h_capacity); ght.run(); // The Gomory-Hu tree is given as a rooted directed tree. Each node has // an arc that points to its father. The root node has father -1. // Remember that each arc in this tree represents a cut and the value of // the arc is the weight of the corresponding cut. So, if an arc has weight // less than 2, then we found a violated cut and in this case, we insert the // corresponding constraint. NodeBoolMap cutmap(h); for (NodeIt u(h); u != INVALID; ++u) { GRBLinExpr expr = 0; if (ght.predNode(u)==INVALID) continue; // skip the root node if (ght.predValue(u) > 2.0 - MY_EPS) continue; // value of the cut is good // this cut violate this conditions // check if there is a terminal in both components if (HasTerminal[u] && HasTerminal[ght.predNode(u)]) { ght.minCutMap(u, ght.predNode(u), cutmap); // now, we have a violated cut // Percorre as arestas que cruzam alguma componente e insere as que pertencem ao corte for (vector<Edge>::iterator e_it=CrossingEdges.begin();e_it!=CrossingEdges.end();++e_it){ Node u=tsp.g.u(*e_it), v=tsp.g.v(*e_it), hu = Index2h[UFNodes.find(u)], hv=Index2h[UFNodes.find(v)]; if (cutmap[hu] != cutmap[hv]) expr += x[*e_it]; } addLazy( expr >= 2 ); } } // Insere a restricao de sub caminho ------------------------------- // ----------------------------------------------------------------- // Mapeia as arestas da solucao int uncovered = 0; EdgeBoolMap covered(tsp.g, false); EdgeBoolMap active(tsp.g, false); for (EdgeIt a(tsp.g); a!=INVALID; ++a) { if (getSolution(x[a]) > 1 - MY_EPS) { active[a] = true; uncovered++; } else { active[a] = false; } } // ----------------------------------------------------------------- // Percorre os caminhos e insere as restricoes de consumo GRBLinExpr expr = 0; Node u = source; bool changed = false; while (uncovered > 0) { // u := vertice atual // v := vertice destino // a := arco percorrido for (ListGraph::IncEdgeIt ait(tsp.g,u); ait!=INVALID; ++ait) { // verifica se o arco esta na solucao Edge a(ait); if (active[a] && !covered[a]) { // soma a distancia percorrida changed = true; expr += x[a]*tsp.weight[a]; // verifica se o node destino e um posto Node v = tsp.g.v(a); if (u == v) { v = tsp.g.u(a); } if (postos[v]) { // se for um posto, termina aqui uma restricao de consumo addLazy( expr <= delta); expr = 0; } // atualiza o valor do vertice atual e diminui as arestas // que ainda nao foram cobertas u = v; covered[a] = true; uncovered--; break; } } // check the changed if (changed) { changed = false; } else // it is a dead end { break; } } // cout << "TERMINANDO CALLBACK" << endl; } catch (...) { cout << "Error during callback..." << endl; } }
// ATENÇÃO: Não modifique a assinatura deste método. bool brach_and_bound999999(TSP_Data_R &tsp, const vector<DNode> &terminais, const vector<DNode> &postos, const DNode source, int delta, int maxTime, vector<DNode> &sol, double &lbound){ // Converte o TSP direcionado para um nao direcionado com duas arestas ListGraph graph; EdgeValueMap weights(graph); // Adiciona os nos for (ListDigraph::NodeIt u(tsp.g); u!=INVALID; ++u) { Node v = graph.addNode(); } // Adiciona as arestas for (ListDigraph::ArcIt ait(tsp.g); ait!=INVALID; ++ait) { // pega os dois nos incidentes Arc a(ait); DNode u = tsp.g.source(a); DNode v = tsp.g.target(a); // cria a mesma aresta no grafo não direcionado Node gu = graph.nodeFromId(tsp.g.id(u)); Node gv = graph.nodeFromId(tsp.g.id(v)); // insere a aresta no grafo nao direcionado Edge e = graph.addEdge(gu, gv); // Atribui pesos as arestas weights[e] = tsp.weight[a]; } NodeStringMap nodename(graph); NodePosMap posicaox(graph); NodePosMap posicaoy(graph); TSP_Data utsp(graph, nodename, posicaox, posicaoy, weights); // utiliza o convertido ListGraph::EdgeMap<GRBVar> x(graph); GRBEnv env = GRBEnv(); GRBModel model = GRBModel(env); // TODO: [Opcional] Comente a linha abaixo caso não queira inserir cortes durante a execução do B&B model.getEnv().set(GRB_IntParam_LazyConstraints, 1); model.getEnv().set(GRB_IntParam_Seed, 0); model.set(GRB_StringAttr_ModelName, "TSPR - TSP with Refueling"); // name to the problem model.set(GRB_IntAttr_ModelSense, GRB_MINIMIZE); // is a minimization problem // Add one binary variable for each arc and also sets its cost in the objective function for (EdgeIt e(utsp.g); e!=INVALID; ++e) { char name[100]; Edge edge(e); unsigned uid = utsp.g.id(utsp.g.u(edge)); unsigned vid = utsp.g.id(utsp.g.v(edge)); sprintf(name,"x_%s_%s",tsp.vname[tsp.g.nodeFromId(uid)].c_str(),tsp.vname[tsp.g.nodeFromId(vid)].c_str()); x[e] = model.addVar(0.0, 1.0, utsp.weight[e],GRB_BINARY,name); } model.update(); // run update to use model inserted variables // converte os terminais e os postos vector<Node> uterminais; for (auto t : terminais) { unsigned tid = tsp.g.id(t); uterminais.push_back(utsp.g.nodeFromId(tid)); } NodeBoolMap upostos(utsp.g, false); for (auto p: postos) { unsigned pid = tsp.g.id(p); // upostos.push_back(utsp.g.nodeFromId(pid)); upostos[utsp.g.nodeFromId(pid)] = true; } // Adicione restrições abaixo // (1) Nós terminais devem ser visitados exatamente uma vez for (auto v : uterminais) { GRBLinExpr expr = 0; for (IncEdgeIt e(utsp.g,v); e!=INVALID; ++e){ expr += x[e]; } model.addConstr(expr == 2 ); } // (3) Nó source sempre presente no início do caminho Node usource = utsp.g.nodeFromId(tsp.g.id(source)); GRBLinExpr expr = 0; for (IncEdgeIt e(utsp.g,usource); e!=INVALID; ++e){ expr += x[e]; } model.addConstr(expr >= 1 ); try { model.update(); // Process any pending model modifications. //if (maxTime >= 0) model.getEnv().set(GRB_DoubleParam_TimeLimit,maxTime); subtourelim cb = subtourelim(utsp , x, usource, upostos, delta); model.setCallback(&cb); // TODO: [Opcional] Pode-se utilizar o valor de uma solução heurística p/ acelerar o algoritmo B&B (cutoff value). //cutoff = tsp.BestCircuitValue-MY_EPS; double cutoff = 0.0; if (cutoff > MY_EPS) model.getEnv().set(GRB_DoubleParam_Cutoff, cutoff ); model.update(); // Process any pending model modifications. model.optimize(); // Obtém o status da otimização int status = model.get(GRB_IntAttr_Status); if(status == GRB_INFEASIBLE || status == GRB_INF_OR_UNBD){ cout << "Modelo inviavel ou unbounded." << endl; return false; } // Limitante inferior e superior do modelo //lbound = model.get(GRB_DoubleAttr_ObjBoundC); if( model.get(GRB_IntAttr_SolCount) <= 0 ){ cout << "Modelo nao encontrou nenhuma solucao viavel no tempo. LowerBound = " << lbound << endl; return false; } else if (status == GRB_OPTIMAL){ if(verbose) cout << "O modelo foi resolvido ate a otimalidade." << endl; } else { if(verbose) cout << "O modelo encontrou uma solucao sub-otima (i.e. nao ha garantia de otimalidade)." << endl; } double custo_solucao = model.get(GRB_DoubleAttr_ObjVal); int uncovered=0; EdgeBoolMap cover(utsp.g, false); for (EdgeIt e(utsp.g); e!=INVALID; ++e) { if (BinaryIsOne(x[e].get(GRB_DoubleAttr_X))) { cover[e] = true; uncovered++; } } sol.push_back(tsp.g.nodeFromId(utsp.g.id(usource))); convertSol(x, sol, tsp, utsp, usource, cover, uncovered); // Calculo manual do custo da solução (deve ser igual ao ObjVal do Gurobi). double soma=0.0; ArcName aname(tsp.g); vector<Arc> edgesSol; ArcColorMap acolor(tsp.g); // if( verbose ) cout << "####### " << endl << "Edges of Solution (B&B):" << endl; // for (EdgeIt e(utsp.g); e!=INVALID; ++e){ // if (BinaryIsOne(x[e].get(GRB_DoubleAttr_X))){ // Note que se este método serve para variáveis binárias, p/ inteiras terá de usar outro método. // soma += utsp.weight[e]; // edgesSol.push_back(tsp.g.arcFromId(utsp.g.id(e))); // if( verbose) cout << "(" << tsp.vname[tsp.g.nodeFromId(utsp.g.id(utsp.g.u(e)))] << "," << tsp.vname[tsp.g.nodeFromId(utsp.g.id(utsp.g.v(e)))] << ")" << endl; // acolor[tsp.g.arcFromId(utsp.g.id(e))] = BLUE; // } // } // if( verbose ) cout << "####### " << endl; if( verbose ) cout << "####### " << endl << "Edges of Solution (B&B):" << endl; DNode u = sol[0]; for (int i=1; i<sol.size(); i++) { DNode v = sol[i]; soma += tsp.AdjMatD.Cost(u,v); if ( verbose ) cout << "(" << tsp.vname[u] << "," << tsp.vname[v] << ")" << endl; u = v; } if( verbose ) cout << "####### " << endl; if( verbose ) cout << "Custo calculado pelo B&B = "<< soma << " / " << custo_solucao << endl; if( verbose ){ cout << "Caminho encontrado a partir do vértice de origem (" << tsp.vname[source] << "): "; for(auto node : sol){ cout << tsp.vname[node] << " "; } // Obs: O caminho é gerado a partir do nó source, se o conjunto de arestas retornado pelo B&B for desconexo, o caminho retornado por 'path_search' será incompleto. cout << endl << "Custo calculado da solucao (caminho a partir do no origem) = " << solutionCost(tsp, sol) << endl; ostringstream out; out << "TSP with Refueling B&B, cost= " << custo_solucao; ViewListDigraph(tsp.g, tsp.vname, tsp.posx, tsp.posy, tsp.vcolor, acolor, out.str()); } return true; } catch(GRBException e) { cerr << "Gurobi exception has been thrown." << endl; cerr << "Error code = " << e.getErrorCode() << endl; cerr << e.getMessage(); } catch (...) { cout << "Model is infeasible" << endl; return false; } return false; }
void IMFT<Ptr>::twoFrameCorresponding(vector<ListGraph::Node> vecUFrame, vector<ListGraph::Node> vecVFrame) { if(m_isDebug) printf("2-Frame Corresponding : # F1 - %d, # F2 - %d\n", vecUFrame.size(), vecVFrame.size()); // make graph, weight map ListGraph g; ListGraph::NodeMap<V> gNodeMap(g); ListGraph::EdgeMap<double> gEdgeMap(g); // make nodes of UFrame : save node id of UFrame for(int i=0;i<vecUFrame.size();i++){ ListGraph::Node n = g.addNode(); V v; v.id = m_g.id(vecUFrame.at(i)); v.ptr = (*m_gNodeMap)[vecUFrame.at(i)].ptr; v.nFrame = 1; gNodeMap[n] = v; } // make nodes of VFrame : save node id of VFrame for(int i=0;i<vecVFrame.size();i++){ ListGraph::Node n = g.addNode(); V v; v.id = m_g.id(vecVFrame.at(i)); v.ptr = (*m_gNodeMap)[vecVFrame.at(i)].ptr; v.nFrame = 2; gNodeMap[n] = v; // connection for(ListGraph::NodeIt pn(g); pn != INVALID; ++pn){ if(gNodeMap[pn].nFrame != v.nFrame){ double weight = gain(gNodeMap[pn], v); gEdgeMap[g.addEdge(pn,n)] = weight; // ListGraph::Edge e = g.addEdge(pn,n); // gEdgeMap[e] = weight; // gNodeMap[m_g.u(e)].edgeID = g.id(e); // gNodeMap[m_g.v(e)].edgeID = g.id(e); } } } // maximum weighted matching MaxWeightedMatching<ListGraph, ListGraph::EdgeMap<double> > mwm(g, gEdgeMap); mwm.run(); int wsum = mwm.matchingWeight(); if(m_isDebug) printf("2-Frame Max = %d\n", wsum); // make edges of original graph using original nodes' ids for(ListGraph::EdgeIt e(g); e != INVALID; ++e){ if(mwm.matching(e)){ int origUId = gNodeMap[g.u(e)].id; int origVId = gNodeMap[g.v(e)].id; ListGraph::Node newU, newV; newU = m_g.nodeFromId(origUId); newV = m_g.nodeFromId(origVId); if(m_isDebug) printf("2-Frame Connection %d, %d nodes\n", origUId, origVId); double weight = gain((*m_gNodeMap)[newU], (*m_gNodeMap)[newV]); ListGraph::Edge e = m_g.addEdge(newU,newV); (*m_gEdgeMap)[e] = weight; (*m_gNodeMap)[m_g.u(e)].edgeID = m_g.id(e); (*m_gNodeMap)[m_g.v(e)].edgeID = m_g.id(e); // if u가 track이 없으면, track 생성하고, v도 track에 집어 넣음. // u가 track이 있으면, v를 그 track에 집어 넣음. if(cnt > m_nWindow){ int vId = m_g.id(m_g.u(e))-1; if(!(*m_gNodeMap)[m_g.nodeFromId(vId)].isTrack){ // generate a track of vId m_cntTrack ++; Track track; track.setNum(m_cntTrack); track.putNode((*m_gNodeMap)[m_g.nodeFromId(vId)].ptr, vId, (*m_gNodeMap)[m_g.nodeFromId(vId)].nFrame); (*m_gNodeMap)[m_g.nodeFromId(vId)].isTrack = 1; (*m_gNodeMap)[m_g.nodeFromId(vId)].nTrack = m_cntTrack; if(m_isDebug) printf("Generate new track # %d of node %d\n", m_cntTrack, vId); // add v(e) to the track track.putNode((*m_gNodeMap)[m_g.v(e)].ptr, m_g.id(m_g.v(e)), (*m_gNodeMap)[m_g.v(e)].nFrame); (*m_gNodeMap)[m_g.v(e)].isTrack = 1; (*m_gNodeMap)[m_g.v(e)].nTrack = m_cntTrack; m_tracks.push_back(track); } else{ // add v(e) to the track for(int i=0;i<m_tracks.size();i++){ if(m_tracks.at(i).num() == (*m_gNodeMap)[m_g.nodeFromId(vId)].nTrack){ m_tracks.at(i).putNode((*m_gNodeMap)[m_g.v(e)].ptr, m_g.id(m_g.v(e)), (*m_gNodeMap)[m_g.v(e)].nFrame); (*m_gNodeMap)[m_g.v(e)].nTrack = (*m_gNodeMap)[m_g.nodeFromId(vId)].nTrack; (*m_gNodeMap)[m_g.v(e)].isTrack = 1; if(m_isDebug) printf("put node %d to the track %d\n", m_g.id(m_g.v(e)), (*m_gNodeMap)[m_g.v(e)].nTrack); break; } } } } } } }