/** * Eliminate cycles for origin_id in the graph. Start searching at next_id and * work recursively. Also "summarize" paths: Add up the flows along parallel * paths in one. * @param path Paths checked in parent calls to this method. * @param origin_id Origin of the paths to be checked. * @param next_id Next node to be checked. * @return If any cycles have been found and eliminated. */ bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id) { static Path *invalid_path = new Path(INVALID_NODE, true); Path *at_next_pos = path[next_id]; /* this node has already been searched */ if (at_next_pos == invalid_path) return false; if (at_next_pos == NULL) { /* Summarize paths; add up the paths with the same source and next hop * in one path each. */ PathList &paths = this->job[next_id].Paths(); PathViaMap next_hops; for (PathList::iterator i = paths.begin(); i != paths.end(); ++i) { Path *new_child = *i; if (new_child->GetOrigin() == origin_id) { PathViaMap::iterator via_it = next_hops.find(new_child->GetNode()); if (via_it == next_hops.end()) { next_hops[new_child->GetNode()] = new_child; } else { Path *child = via_it->second; uint new_flow = new_child->GetFlow(); child->AddFlow(new_flow); new_child->ReduceFlow(new_flow); } } } bool found = false; /* Search the next hops for nodes we have already visited */ for (PathViaMap::iterator via_it = next_hops.begin(); via_it != next_hops.end(); ++via_it) { Path *child = via_it->second; if (child->GetFlow() > 0) { /* Push one child into the path vector and search this child's * children. */ path[next_id] = child; found = this->EliminateCycles(path, origin_id, child->GetNode()) || found; } } /* All paths departing from this node have been searched. Mark as * resolved if no cycles found. If cycles were found further cycles * could be found in this branch, thus it has to be searched again next * time we spot it. */ path[next_id] = found ? NULL : invalid_path; return found; } /* This node has already been visited => we have a cycle. * Backtrack to find the exact flow. */ uint flow = this->FindCycleFlow(path, at_next_pos); if (flow > 0) { this->EliminateCycle(path, at_next_pos, flow); return true; } return false; }
/** * Map the paths generated by the MCF solver into flows associated with nodes. * @param component the link graph component to be used. */ void FlowMapper::Run(LinkGraphJob &job) const { for (NodeID node_id = 0; node_id < job.Size(); ++node_id) { Node prev_node = job[node_id]; StationID prev = prev_node.Station(); PathList &paths = prev_node.Paths(); for (PathList::iterator i = paths.begin(); i != paths.end(); ++i) { Path *path = *i; uint flow = path->GetFlow(); if (flow == 0) break; Node node = job[path->GetNode()]; StationID via = node.Station(); StationID origin = job[path->GetOrigin()].Station(); assert(prev != via && via != origin); /* Mark all of the flow for local consumption at "first". */ node.Flows().AddFlow(origin, via, flow); if (prev != origin) { /* Pass some of the flow marked for local consumption at "prev" on * to this node. */ prev_node.Flows().PassOnFlow(origin, via, flow); } else { /* Prev node is origin. Simply add flow. */ prev_node.Flows().AddFlow(origin, via, flow); } } } for (NodeID node_id = 0; node_id < job.Size(); ++node_id) { /* Remove local consumption shares marked as invalid. */ Node node = job[node_id]; FlowStatMap &flows = node.Flows(); flows.FinalizeLocalConsumption(node.Station()); if (this->scale) { /* Scale by time the graph has been running without being compressed. */ uint runtime = job.JoinDate() - job.Settings().recalc_time - job.LastCompression(); for (FlowStatMap::iterator i = flows.begin(); i != flows.end(); ++i) { i->second.ScaleToMonthly(runtime); } } /* Clear paths. */ PathList &paths = node.Paths(); for (PathList::iterator i = paths.begin(); i != paths.end(); ++i) { delete *i; } paths.clear(); } }
/** * Clean up paths that lead nowhere and the root path. * @param source_id ID of the root node. * @param paths Paths to be cleaned up. */ void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths) { Path *source = paths[source_id]; paths[source_id] = NULL; for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) { Path *path = *i; if (path == NULL) continue; if (path->GetParent() == source) path->Detach(); while (path != source && path != NULL && path->GetFlow() == 0) { Path *parent = path->GetParent(); path->Detach(); if (path->GetNumChildren() == 0) { paths[path->GetNode()] = NULL; delete path; } path = parent; } } delete source; paths.clear(); }
//Retorna la descomposicion en key-path del grafo pasado por parametro Collection* KeyPathLocalSearch::KeyPathDecomp(Graph *g){ Graph *grafo = g->Copy(); Collection *K = new Collection(); //nodos que pueden ser extremos de los key-path, son terminales o key-nodes Collection * terminals = g->GetTerminals(); Collection * key_nodes = g->GetKeyNodes(true); Collection * end_nodes = terminals->Union(key_nodes); int node, currentNode, lastIdentifier, degree; bool isTerminal, isKeyNode; //para cada posible nodo extremo de key-path for (int i=0; i<end_nodes->Size(); i++){ node = ((Integer*)end_nodes->GetItem(i))->GetValue(); Collection * end_node_adyacents = grafo->GetAdyacents(node); //para cada adyacente al nodo extremo for (int j = 0; j < end_node_adyacents->Size(); j++){ lastIdentifier = node; //creo el camino Path * aux = new Path(g); //agrego el extremo aux->Add(node); //calculo el nodo siguiente del camino currentNode = ((Integer*)end_node_adyacents->GetItem(j))->GetValue(); degree = grafo->GetNodeDegree(currentNode); if (grafo->IsNodeEnabled(currentNode) && degree != 0){ do { //agrego nodo al camino aux->Add(currentNode); Collection * adyacents = grafo->GetAdyacents(currentNode); //calculo si es terminal y si es key-node isTerminal = g->IsTerminal(currentNode); isKeyNode = g->IsKeyNode(currentNode); //si es nodo intermedio actualizo el currentNode if(! isTerminal && ! isKeyNode){ if(((Integer*)adyacents->GetItem(0))->GetValue() == lastIdentifier){ lastIdentifier = currentNode; currentNode = ((Integer*)adyacents->GetItem(1))->GetValue(); } else{ lastIdentifier = currentNode; currentNode = ((Integer*)adyacents->GetItem(0))->GetValue(); } } adyacents->Destroy(); }while(! isTerminal && ! isKeyNode); //mientras este en nodos intermedios K->Add((Object*)aux); //apago aristas y nodos del path, dejo prendidos los extremos if (aux->Length() > 2) { for (int ind=1; ind<aux->Length()-1; ind++){ Collection *adyacents = grafo->GetAdyacents(aux->GetNode(ind)); //apago aristas si es que existen for (int iter=0; iter<adyacents->Size();iter++){ if (grafo->ExistEdge(aux->GetNode(ind),((Integer*)adyacents->GetItem(iter))->GetValue())) grafo->DisableEdge(aux->GetNode(ind),((Integer*)adyacents->GetItem(iter))->GetValue()); } grafo->DisableNode(aux->GetNode(ind)); adyacents->Destroy(); } } else //key-path de dos nodos { grafo->DisableEdge(aux->GetNode(0),aux->GetNode(1)); } } else{ delete aux; } } end_node_adyacents->Destroy(); } terminals->Destroy(); key_nodes->Destroy(); delete end_nodes; delete grafo; return K; }