diff --git a/src/labelling_algorithm.cpp b/src/labelling_algorithm.cpp index 64886cea45d2961af133ad8fafab1f00615c75e6..9e68e2ff1a428cc32cd30393311eb122b05fb2ad 100644 --- a/src/labelling_algorithm.cpp +++ b/src/labelling_algorithm.cpp @@ -1148,209 +1148,227 @@ bool LabellingAlgorithm::compare_cost(tuple<int, double> first, tuple<int, doubl /** * \fn get_capacity_bound * \brief returns an optimistic bound on the cost of a completion of the path, wrp to the current load - */ -double LabellingAlgorithm::get_capacity_bound(Label *label, bool ng) -{ - int labelNode = label->currentNode->uniqueNodeIndex; - double cost = nodeInfo[labelNode].min_cost_arc; - double resource_left = maxResource.capacity - label->capacity; - double earliest_start_time = label->tMin + nodeInfo[labelNode].serviceTime; - vector<tuple<int, int, int>> visited_in_completion; // node identifier, multiplicit of visits, maximum visits +*/ +double LabellingAlgorithm::get_capacity_bound(Label* label, bool ng) +{ + int labelNode=label->currentNode->uniqueNodeIndex; + + double cost=nodeInfo[labelNode].min_cost_arc; + double resource_left=maxResource.capacity-label->capacity; + + double earliest_start_time=label->tMin+nodeInfo[labelNode].serviceTime; + + vector<tuple<int,int,int>> visited_in_completion; //node identifier, multiple of visits, maximum visits visited_in_completion.reserve(20); - int i = 0; - while (i < least_arc_costs.size()) - { - int currNode = get<0>(least_arc_costs[i]); - if (nodeInfo[currNode].min_cost_arc >= 0) - { - break; + + + int i=0; + while(i<least_arc_costs.size()){ + int currNode=get<0>(least_arc_costs[i]); + if(nodeInfo[currNode].nodeType=='f'){ + i++; + continue; } - else if ((label->visitedForDominance[currNode] == 0 || ng) && nodeInfo[currNode].nodeType != 'f') - { // node has not been visited before - if (ng) - { - // add nodes to completion calculate the number of times it can be visited - int completion_size = visited_in_completion.size(); - if (completion_size < 2) - { // special case when adding the first two nodes - if (label->tMin + nodeInfo[labelNode].serviceTime + arcInfo[labelNode][currNode].time > nodeInfo[currNode].dueDate) - { - i++; // find first customer node that is reachable + if(label->visitedForDominance[currNode]==0 || ng){ //node has not been visited before + if(ng){ + //add nodes to completion calculate the number of times it can be visited + int completion_size=visited_in_completion.size(); + if(completion_size<2){ //special case when adding the first two nodes + if(earliest_start_time+arcInfo[labelNode][currNode].time>nodeInfo[currNode].dueDate){ + i++; //find first customer node that is reachable continue; } - else - { - if (completion_size == 0 && label->visitedForDominance[currNode] == 1) - { // if first node in completion, and label remembers first node - int k = i + 1; // find best node that is not remembered and can be reached - while (k < least_arc_costs.size()) - { - if (label->visitedForDominance[get<0>(least_arc_costs[k])] == 0 && label->tMin + nodeInfo[labelNode].serviceTime + arcInfo[labelNode][get<0>(least_arc_costs[k])].time <= nodeInfo[get<0>(least_arc_costs[k])].dueDate && nodeInfo[get<0>(least_arc_costs[k])].nodeType != 'f') - { - currNode = k; // k is reachable, not remebered by the label, and not a charging node - i = i - 1; // the recent i was not added in the completion, but is valid - break; - } - else - { - k++; - } + if(completion_size==0 && label->visitedForDominance[currNode]==1){ //if first node in completion, and label remembers first node + int k=i+1; //find best node that is not remembered and can be reached + while(k<least_arc_costs.size()){ + if(label->visitedForDominance[get<0>(least_arc_costs[k])]==0 && earliest_start_time+arcInfo[labelNode][get<0>(least_arc_costs[k])].time<=nodeInfo[get<0>(least_arc_costs[k])].dueDate){ + currNode=get<0>(least_arc_costs[k]); //k is reachable, not remebered by the label, and not a charging node + i=i-1; //the recent i was not added in the completion, but is valid + break; + } + else{ + k++; } } - double start_time = max(earliest_start_time + arcInfo[labelNode][currNode].time, nodeInfo[currNode].readyTime); - int multiplicity = ceil((nodeInfo[currNode].dueDate - start_time) / (nodeInfo[currNode].min_time_arc + nodeInfo[currNode].min_time_incoming)); - visited_in_completion.emplace_back(make_tuple(currNode, 1, multiplicity)); - i++; } + + double start_time=max(earliest_start_time+arcInfo[labelNode][currNode].time,nodeInfo[currNode].readyTime); + int multiplicity=ceil((nodeInfo[currNode].dueDate-start_time)/(nodeInfo[currNode].min_time_arc+nodeInfo[currNode].min_time_incoming)); + visited_in_completion.emplace_back(make_tuple(currNode,1,multiplicity)); + i++; + } - else - { - tuple<int, int, int> node = visited_in_completion[completion_size - 2]; - if (get<1>(node) < get<2>(node)) - { // check if any node can still be revisited. Reachability must not be tested here - visited_in_completion.emplace_back(make_tuple(get<0>(node), get<1>(node) + 1, get<2>(node))); - currNode = get<0>(node); + else{ + tuple<int,int,int> node=visited_in_completion[completion_size-2]; + if(get<1>(node)<get<2>(node)){ //check if any node can still be revisited. Reachability must not be tested here + visited_in_completion.emplace_back(make_tuple(get<0>(node), get<1>(node)+1,get<2>(node))); + currNode=get<0>(node); } - else if (label->tMin + nodeInfo[labelNode].serviceTime + arcInfo[labelNode][currNode].time > nodeInfo[currNode].dueDate) - { // verify reachability of new node + else if(earliest_start_time+arcInfo[labelNode][currNode].time>nodeInfo[currNode].dueDate){ //verify reachability of new node i++; continue; } - else - { - double start_time = max(earliest_start_time + arcInfo[labelNode][currNode].time, nodeInfo[currNode].readyTime); // add new node - int multiplicity = ceil((nodeInfo[currNode].dueDate - start_time) / (nodeInfo[currNode].min_time_arc + nodeInfo[currNode].min_time_incoming)); - visited_in_completion.emplace_back(make_tuple(currNode, 1, multiplicity)); + else{ + double start_time=max(earliest_start_time+arcInfo[labelNode][currNode].time,nodeInfo[currNode].readyTime); //add new node + int multiplicity=ceil((nodeInfo[currNode].dueDate-start_time)/(nodeInfo[currNode].min_time_arc+nodeInfo[currNode].min_time_incoming)); + visited_in_completion.emplace_back(make_tuple(currNode,1,multiplicity)); i++; } } + } + + if(nodeInfo[currNode].min_cost_arc>=0){ + if(ng){ + if(visited_in_completion.size()!=1){ //the first added node may have positive cost + break; + } + } + else{ + break; + } } + float value; - value = min((double)1, resource_left / nodeInfo[currNode].demand); - resource_left = resource_left - nodeInfo[currNode].demand * value; - cost = cost + (nodeInfo[currNode].min_cost_arc * value); - if (resource_left <= 0) - { + value=min((double)1,resource_left/nodeInfo[currNode].demand); + + resource_left=resource_left-(nodeInfo[currNode].demand*value); + cost=cost+(nodeInfo[currNode].min_cost_arc*value); + + if(resource_left<=0){ break; } } - if (!ng) - { + + if(!ng){ i++; } } - return (cost); + if(ng){ + return(min(cost,nodeInfo[labelNode].min_cost_arc)); + } + else{ + return(cost); + } } /** * \fn time_bound_special * \brief adapted knapsack time bounds with battery constraints - */ -double LabellingAlgorithm::get_time_bound(Label *label, bool ng) -{ - int labelNode = label->currentNode->uniqueNodeIndex; - double cost = nodeInfo[labelNode].min_cost_arc; - double energy = max(0.0, label->energy - nodeInfo[labelNode].min_fuel_arc); // reduce energy by min fuel arc - double added_time = 0; - if (energy == 0) - { // charging time added if required - double add_charging = nodeInfo[labelNode].min_fuel_arc - label->energy; - added_time = add_charging / charging_rates[0]; +*/ +double LabellingAlgorithm::get_time_bound(Label* label, bool ng) +{ + int labelNode=label->currentNode->uniqueNodeIndex; + double cost=nodeInfo[labelNode].min_cost_arc; + + double energy=max(0.0,label->energy-nodeInfo[labelNode].min_fuel_arc); //reduce energy by min fuel arc + + double added_time=0; + if(energy==0){ //charging time added if required + double add_charging=nodeInfo[labelNode].min_fuel_arc-label->energy; + added_time=add_charging/charging_rates[0]; } - double resource_left = maxResource.tMin - label->tMin - nodeInfo[labelNode].min_time_arc - added_time; // reduce time availability - double earliest_start_time = label->tMin + nodeInfo[labelNode].serviceTime; + + double resource_left=maxResource.tMin-label->tMin-nodeInfo[labelNode].min_time_arc-added_time; //reduce time availability + + double earliest_start_time=label->tMin+nodeInfo[labelNode].serviceTime; + double added_charging; double required_charging; - vector<tuple<int, int, int>> visited_in_completion; // node identifier, multiplicity of visits, maximum visits + vector<tuple <int,int,int>> visited_in_completion; //node identifier, multiplicity of visits, maximum visits visited_in_completion.reserve(15); - int i = 0; - while (i < least_arc_time.size()) - { - int currNode = get<0>(least_arc_time[i]); - if (nodeInfo[currNode].min_cost_arc >= 0) - { - break; + int i=0; + while(i<least_arc_time.size()){ + + int currNode=get<0>(least_arc_time[i]); + + if(nodeInfo[currNode].nodeType=='f'){ + i++; + continue; } - else if ((label->visitedForDominance[currNode] == 0 || ng) && nodeInfo[currNode].nodeType != 'f') - { // node has not been visited before - if (ng) - { + else if(label->visitedForDominance[currNode]==0 || ng){ + if(ng){ // add nodes to completion and calculate the number of times it can be visited - int completion_size = visited_in_completion.size(); - if (completion_size < 2) - { // special case for first two nodes int the completion - if (label->tMin + nodeInfo[labelNode].serviceTime + arcInfo[labelNode][currNode].time > nodeInfo[currNode].dueDate) - { - i++; // find first customer node in list that is reachable + int completion_size=visited_in_completion.size(); + + if(completion_size<2){ //special case for first two nodes int the completion + if(label->tMin+nodeInfo[labelNode].serviceTime+arcInfo[labelNode][currNode].time>nodeInfo[currNode].dueDate){ + i++; //find first customer node in list that is reachable continue; } - else - { - if (completion_size == 0 && label->visitedForDominance[currNode] == 1) - { // first node in completion may not be rememebered byt the label - int k = i + 1; - while (k < least_arc_time.size()) - { - if (label->visitedForDominance[get<0>(least_arc_time[k])] == 0 && label->tMin + nodeInfo[labelNode].serviceTime + arcInfo[labelNode][get<0>(least_arc_time[k])].time <= nodeInfo[get<0>(least_arc_time[k])].dueDate && nodeInfo[get<0>(least_arc_time[k])].nodeType != 'f') - { - currNode = k; - i = i - 1; // i is valid, and has not been added to completion - break; - } - else - { - k++; - } + if(completion_size==0 && label->visitedForDominance[currNode]==1){ //first node in completion may not be rememebered byt the label + int k=i+1; + while(k<least_arc_time.size()){ + if(label->visitedForDominance[get<0>(least_arc_time[k])]==0 && label->tMin+nodeInfo[labelNode].serviceTime+arcInfo[labelNode][get<0>(least_arc_time[k])].time<=nodeInfo[get<0>(least_arc_time[k])].dueDate && nodeInfo[get<0>(least_arc_time[k])].nodeType!='f'){ + currNode=get<0>(least_arc_time[k]); + i=i-1; //i is valid, and has not been added to completion + break; + } + else{ + k++; } } - double start_time = max(earliest_start_time + arcInfo[labelNode][currNode].time, nodeInfo[currNode].readyTime); - int multiplicity = ceil((nodeInfo[currNode].dueDate - start_time) / (nodeInfo[currNode].min_time_arc + nodeInfo[currNode].min_time_incoming)); - visited_in_completion.emplace_back(make_tuple(currNode, 1, multiplicity)); - i++; } + double start_time=max(earliest_start_time+arcInfo[labelNode][currNode].time,nodeInfo[currNode].readyTime); + int multiplicity=ceil((nodeInfo[currNode].dueDate-start_time)/(nodeInfo[currNode].min_time_arc+nodeInfo[currNode].min_time_incoming)); + visited_in_completion.emplace_back(make_tuple(currNode,1,multiplicity)); + i++; } - else - { - tuple<int, int, int> node = visited_in_completion[completion_size - 2]; - if (get<1>(node) < get<2>(node)) - { // check second to last node can still be revisited. Reachability must not be tested - visited_in_completion.emplace_back(make_tuple(get<0>(node), get<1>(node) + 1, get<2>(node))); - currNode = get<0>(node); + else{ + tuple<int,int,int>node=visited_in_completion[completion_size-2]; + + if(get<1>(node)<get<2>(node)){ //check second to last node can still be revisited. Reachability must not be tested + visited_in_completion.emplace_back(make_tuple(get<0>(node), get<1>(node)+1,get<2>(node))); + currNode=get<0>(node); + } - else if (label->tMin + nodeInfo[labelNode].serviceTime + arcInfo[labelNode][currNode].time > nodeInfo[currNode].dueDate) - { - i++; // else find next node that is reachable + else if(label->tMin+nodeInfo[labelNode].serviceTime+arcInfo[labelNode][currNode].time>nodeInfo[currNode].dueDate){ + i++; //else find next node that is reachable continue; } - else - { // add node to completion of the path - double start_time = max(earliest_start_time + arcInfo[labelNode][currNode].time, nodeInfo[currNode].readyTime); - int multiplicity = ceil((nodeInfo[currNode].dueDate - start_time) / (nodeInfo[currNode].min_time_arc + nodeInfo[currNode].min_time_incoming)); - visited_in_completion.emplace_back(make_tuple(currNode, 1, multiplicity)); + else{ //add node to completion of the path + double start_time=max(earliest_start_time+arcInfo[labelNode][currNode].time,nodeInfo[currNode].readyTime); + int multiplicity=ceil((nodeInfo[currNode].dueDate-start_time)/(nodeInfo[currNode].min_time_arc+nodeInfo[currNode].min_time_incoming)); + visited_in_completion.emplace_back(make_tuple(currNode,1,multiplicity)); i++; } } } - if (nodeInfo[currNode].min_cost_arc >= 0) - { - break; + + if(nodeInfo[currNode].min_cost_arc>=0){ + if(ng){ + if(visited_in_completion.size()!=1){ //the first added node may have positive cost + break; + } + } + else{ + break; + } } float value; - added_charging = max((double)0, nodeInfo[currNode].min_fuel_arc - energy) / charging_rates[0]; // charging time at fastest rate - energy = max((double)0.0, energy - nodeInfo[currNode].min_fuel_arc); // update the energy resource - value = min((double)1, resource_left / (nodeInfo[currNode].min_time_arc + added_charging)); - resource_left = resource_left - (nodeInfo[currNode].min_time_arc + added_charging) * value; - cost = cost + (nodeInfo[currNode].min_cost_arc * value); - if (resource_left <= 0) - { + + added_charging=max((double)0,nodeInfo[currNode].min_fuel_arc-energy)/charging_rates[0]; //charging time at fastest rate + energy=max((double)0.0,energy-nodeInfo[currNode].min_fuel_arc); //update the energy resource + value=min((double)1,resource_left/(nodeInfo[currNode].min_time_arc+added_charging)); + + resource_left=resource_left-(nodeInfo[currNode].min_time_arc+added_charging)*value; + + cost=cost+(nodeInfo[currNode].min_cost_arc*value); + + if(resource_left<=0){ break; } + } - if (!ng) - { - i++; - } + if(!ng){ + i++; + } } - return (cost); -} \ No newline at end of file + + if(ng){ + return(min(cost,nodeInfo[labelNode].min_cost_arc)); + } + else{ + return(cost); + } +}