diff --git a/DiscreteENN_TSP_table.csv b/DiscreteENN_TSP_table.csv index 3fcb9a5..3e9744c 100644 --- a/DiscreteENN_TSP_table.csv +++ b/DiscreteENN_TSP_table.csv @@ -1,18 +1,18 @@ name,distance,points,error,time(ms) -pr1002,280407.968750,1002.000000,0.082468,15315.000000 -pcb442,54114.605469,442.000000,0.065710,276.000000 -a280,1844.404663,181.000000,0.284837,10.000000 -eil76,560.789551,76.000000,0.042360,0.000000 -pr76,114190.000000,76.000000,0.055760,0.000000 -kroA100,22749.457031,100.000000,0.068953,1.000000 -pr2392,411187.187500,2392.000000,0.087705,1049157.000000 -st70,735.881836,70.000000,0.090195,0.000000 -kroC100,22543.697266,100.000000,0.086496,1.000000 -kroD100,22713.125000,100.000000,0.066644,1.000000 -berlin52,8191.641602,52.000000,0.086137,0.000000 -eil101,669.608093,101.000000,0.064560,2.000000 -rd100,8263.841797,100.000000,0.044733,1.000000 -lin105,15141.876953,105.000000,0.053055,1.000000 -ch130,6425.749023,130.000000,0.051677,3.000000 -ch150,6910.962891,150.000000,0.058665,5.000000 -tsp225,2754.485596,126.000000,0.296607,3.000000 +pr1002,276678.937500,1002.000000,0.068073,10194.000000 +pcb442,53866.402344,442.000000,0.060822,111.000000 +a280,1874.166870,181.000000,0.273297,7.000000 +eil76,567.772827,76.000000,0.055340,0.000000 +pr76,111553.796875,76.000000,0.031387,1.000000 +kroA100,22999.716797,100.000000,0.080712,1.000000 +pr2392,409888.656250,2392.000000,0.084270,127181.000000 +st70,689.609680,70.000000,0.021644,0.000000 +kroC100,21787.464844,100.000000,0.050049,1.000000 +kroD100,22821.566406,100.000000,0.071737,1.000000 +berlin52,8053.304688,52.000000,0.067794,0.000000 +eil101,664.361877,101.000000,0.056219,1.000000 +rd100,8295.532227,100.000000,0.048740,1.000000 +lin105,15260.703125,105.000000,0.061319,1.000000 +ch130,6436.513184,130.000000,0.053439,3.000000 +ch150,6888.052734,150.000000,0.055155,5.000000 +tsp225,2736.984619,126.000000,0.301076,3.000000 diff --git a/DiscreteENN_TSP_table.txt b/DiscreteENN_TSP_table.txt index 8d7a7e0..6a5cad2 100644 --- a/DiscreteENN_TSP_table.txt +++ b/DiscreteENN_TSP_table.txt @@ -1,18 +1,18 @@ name distance points error time(ms) -pr1002 280407.968750 1002.000000 0.082468 15315.000000 -pcb442 54114.605469 442.000000 0.065710 276.000000 -a280 1844.404663 181.000000 0.284837 10.000000 -eil76 560.789551 76.000000 0.042360 0.000000 -pr76 114190.000000 76.000000 0.055760 0.000000 -kroA100 22749.457031 100.000000 0.068953 1.000000 -pr2392 411187.187500 2392.000000 0.087705 1049157.000000 -st70 735.881836 70.000000 0.090195 0.000000 -kroC100 22543.697266 100.000000 0.086496 1.000000 -kroD100 22713.125000 100.000000 0.066644 1.000000 -berlin52 8191.641602 52.000000 0.086137 0.000000 -eil101 669.608093 101.000000 0.064560 2.000000 -rd100 8263.841797 100.000000 0.044733 1.000000 -lin105 15141.876953 105.000000 0.053055 1.000000 -ch130 6425.749023 130.000000 0.051677 3.000000 -ch150 6910.962891 150.000000 0.058665 5.000000 -tsp225 2754.485596 126.000000 0.296607 3.000000 +pr1002 276678.937500 1002.000000 0.068073 10194.000000 +pcb442 53866.402344 442.000000 0.060822 111.000000 +a280 1874.166870 181.000000 0.273297 7.000000 +eil76 567.772827 76.000000 0.055340 0.000000 +pr76 111553.796875 76.000000 0.031387 1.000000 +kroA100 22999.716797 100.000000 0.080712 1.000000 +pr2392 409888.656250 2392.000000 0.084270 127181.000000 +st70 689.609680 70.000000 0.021644 0.000000 +kroC100 21787.464844 100.000000 0.050049 1.000000 +kroD100 22821.566406 100.000000 0.071737 1.000000 +berlin52 8053.304688 52.000000 0.067794 0.000000 +eil101 664.361877 101.000000 0.056219 1.000000 +rd100 8295.532227 100.000000 0.048740 1.000000 +lin105 15260.703125 105.000000 0.061319 1.000000 +ch130 6436.513184 130.000000 0.053439 3.000000 +ch150 6888.052734 150.000000 0.055155 5.000000 +tsp225 2736.984619 126.000000 0.301076 3.000000 diff --git a/a.out b/a.out index 8c9d2ee..8d28a5b 100755 Binary files a/a.out and b/a.out differ diff --git a/algo.txt b/algo.txt new file mode 100644 index 0000000..7a42934 --- /dev/null +++ b/algo.txt @@ -0,0 +1,37 @@ +Paper: +--------- +1. Looking for an edge r_i: h()..... +2. Create a new node vec( y ) that matches the city vec(x), and add it between nodes vec(y_i), vec(y_(i+1)). +3. We check if criterion 1 is met. The traversed cities that do not satisfy this criterion are released (i.e., returned to the stack S of untraversed cities) and traversed again. + +When a node vec( y ) is added to the route, two new edges (vec(y_i), vec(y)) and (vec( y ), vec(y_(i+1)))) are added. The values of h(vec(y_i)) and h(vec(y_()i+1)) change, so to check if the criterion is fulfilled it is enough to check it for vec(y_i) and vec(y_(i+1)), and to compare h(vec(y_k)) with h(vec(y_k)); vec(y_i), vec(y)) and with h(vec(y_k); vec( y ), vec(y_(i+1)))) for the remaining nodes. +When a node vec(y_k) is removed from the route, we need to check if the criterion is fulfilled given the new edge (vec(y_(k-1)), vec(y_(k+1))) and changed values of h(vec(y_(k-1))) and h(vec(y_(k+1)))). +To ensure that there are no self-intersections in the route, it is sufficient, when adding a node vec( y ) between nodes vec(y_i), vec(y_(i+1)), to first remove all nodes from the route, lying inside the triangle (vec(y)), vec(y_i), vec(y_(i+1))), and when removing node vec(y_i), remove all nodes from the triangle (vec(y)), vec(y_(i-1)), vec(y_(i+1))). + +Implementation: +-------------- +Let the city indices be: +ci element of [0, num_cities) +Let the node indices be: +ni element of [0, num_nodes) + +1. Take a city on stack, x_ci +2. Find nodes y_ni and y_(ni+1) which satisfies step (1) in paper. +3. Remove city x_ci from stack +4. Add new node at (ni+1) which is equal to x_ci and increase by value 1, the indies of node from original (ni+1) and higher. So, (ni+1), (ni+2), (ni+3)...(ni+N) becomes (ni+2), (ni+3), (ni+4)...(ni+N+1) +5. Update cost values of y_ni, y_(ni+1) and y_(ni+2) + +6. Check whether y_ni and y_(ni+2) satisfy criterion 1 +7. Check whether all other nodes except y_(ni+1) satisfy criterion 1 by comparing with new edges {y_ni, y_(ni+1)} except node y_ni and {y_(ni+1), y_(ni+2)} except node y_(ni+2) +*order invariant impl* +8. Mark all nodes that don't satisfy the criteria for removal. +9. For each node marked for removal construct new edges that will be formed after their removal. +10. The neighbours have to be selected from the two adjacent nodes on the path (those ones not marked for removal) to the left and right of the current node marked for removal +11. Update the node cost of neighbours, check if they satisfy criterion. +12. Compare the node cost of other nodes with the newly formed edges +(this is bad because any of the newly formed edge might invalidate the newly added node. So, all the nodes removed because of the addition of the newly added node doesn't make sense) +*order non-invariant impl* +8. For each node not satisfying the criterion 1, we remove it +9. A new adge is created between its neighbours. +10. Update the node cost of neighbours, check if they satisfy criterion. +11. Compare the node cost of other nodes with the newly formed edges diff --git a/main.cpp b/main.cpp index 0b4662f..05a94cd 100644 --- a/main.cpp +++ b/main.cpp @@ -206,8 +206,8 @@ int runPipelineSingle(const stdfs::path&data_path, std::default_random_engine& r // ------------------------------------------- DiscreteENN_TSP enn_tsp; enn_tsp.initialSize() = Num_Nodes_Initial; - enn_tsp.intersection() = Validation_Intersection; - enn_tsp.recursive() = Intersection_Recursive; + enn_tsp.validIntersectCK() = Validation_Intersection; + enn_tsp.rmIntersectRecurse() = Intersection_Recursive; enn_tsp.iterRandomize() = Iter_Randomize; enn_tsp.repeatLength() = Repeat_Check_Length; diff --git a/tsp_discrete_enn.cpp b/tsp_discrete_enn.cpp index 6a3a5e2..35a58b3 100644 --- a/tsp_discrete_enn.cpp +++ b/tsp_discrete_enn.cpp @@ -73,8 +73,8 @@ int main(int argc, char** argv) // ------------------------------------------- DiscreteENN_TSP enn_tsp; enn_tsp.initialSize() = Num_Nodes_Initial; - enn_tsp.intersection() = Validation_Intersection; - enn_tsp.recursive() = Intersection_Recursive; + enn_tsp.validIntersectCK() = Validation_Intersection; + enn_tsp.rmIntersectRecurse() = Intersection_Recursive; enn_tsp.iterRandomize() = Iter_Randomize; enn_tsp.repeatLength() = Repeat_Check_Length; diff --git a/tsp_discrete_enn.hpp b/tsp_discrete_enn.hpp index e643d72..17244d6 100644 --- a/tsp_discrete_enn.hpp +++ b/tsp_discrete_enn.hpp @@ -382,13 +382,13 @@ class DiscreteENN_TSP { return m_initialSize; } - bool& recursive() + bool& rmIntersectRecurse() { - return m_recursive; + return m_rmIntersectRecurse; } - bool& intersection() + bool& validIntersectCK() { - return m_intersection; + return m_validIntersectCK; } int& iterRandomize() { @@ -399,14 +399,6 @@ class DiscreteENN_TSP return m_repeatLen; } - int properIndex(int index) - { - const int n = m_path.size(); - index = (index < 0) ? (n + index) : index; - index = (index > (n - 1)) ? (index - n) : index; - return index; - } - int findNode(Node_t node) { const Path_t::const_iterator& it_begin{ m_path.begin() }; @@ -416,26 +408,18 @@ class DiscreteENN_TSP return (it == it_end) ? -1 : std::distance(it_begin, it); } - bool removeNode(int index) + void removeNode(int index) { -#if (TSP_DEBUG_CHECK > 1) - if (index >= static_cast(m_path.size())) { - utils::printErr("Request to remove a node not present in path.", - "removeNode"); - return false; - } - if (index < 0) { - utils::printErr("given index is negative", "removeNode"); - return false; - } -#endif + // const std::string& node_idx_str{ + // "|" + std::to_string(m_path[static_cast(index)]->id) + + // "|" + // }; + // std::string::size_type idx_erase = m_pattern.find(node_idx_str); + // m_pattern.erase(idx_erase, node_idx_str.length()); + const Path_t::iterator node_iter{ m_path.begin() + index }; (*node_iter)->on_stack = true; -#if (TSP_DEBUG_PRINT > 0) - (*node_iter)->print(); -#endif m_path.erase(node_iter); - return true; } bool removeNode(Node_t node) @@ -446,38 +430,42 @@ class DiscreteENN_TSP "removeNode"); return false; } - return removeNode(index); + removeNode(index); + return true; } void addNode(int index, Node_t node) { + // const std::string& node_idx_str{ + // "|" + std::to_string(m_path[static_cast(index)]->id) + + // "|" + // }; + // const std::string& node_idx_added_str{ "|" + std::to_string(node->id) + + // "|" }; + // std::string::size_type idx_insert = m_pattern.find(node_idx_str); + // m_pattern.insert(idx_insert, node_idx_added_str); + node->on_stack = false; m_path.insert(m_path.begin() + index, node); -#if (TSP_DEBUG_PRINT > 1) - m_path[0]->print(); - std::cout << "FIRST CITY\n"; - node->print(); - std::cout << "Added City\n"; - const std::string& msg{ "path size (" + std::to_string(m_path.size()) + - ") position : " + std::to_string(index) }; - std::cout << ("[Debug] (addNode): " + msg + "\n"); -#endif } std::pair validateNode(Node_t node) { + const std::size_t num_nodes = m_path.size(); + if (num_nodes < 3) { + utils::printErr("given path size less than 3", "validateNode"); + return std::make_pair(false, true); + } const int index = findNode(node); if (index == -1) { utils::printErr("Request to validate a node not present in path.", "validateNode"); return std::make_pair(false, true); } - const std::size_t num_nodes = m_path.size(); - if (num_nodes < 3) { - utils::printErr("given path size less than 3", "validateNode"); - return std::make_pair(false, true); - } const Value_t cost_current{ node->cost }; + if (cost_current < utils::tolerance) { + return std::make_pair(true, false); + } if (index != 0 and index != static_cast(num_nodes - 1)) { if (insertionCost(*node, *(m_path[num_nodes - 1]), *(m_path[0])) < cost_current) { @@ -497,11 +485,17 @@ class DiscreteENN_TSP return std::make_pair(true, false); } + std::size_t properIndex(int index) + { + const int n = m_path.size(); + index = (index < 0) ? (n + index) : index; + index = (index > (n - 1)) ? (index - n) : index; + return static_cast(index); + } + auto getNeigbhours(int index) { - const int curr = properIndex(index); - return std::make_tuple(properIndex(curr - 1), curr, - properIndex(curr + 1)); + return std::make_pair(properIndex(index - 1), properIndex(index + 1)); } auto getNeigbhours(Node_t node) @@ -511,222 +505,89 @@ class DiscreteENN_TSP utils::printErr( "Request to find neighbours for a node not present in path.", "getNeigbhours"); - utils::Expected{ std::make_tuple(Node_t{}, Node_t{}, Node_t{}), - true }; + return utils::Expected{ std::make_pair(Node_t{}, Node_t{}), true }; } - const auto [prev, curr, next] = getNeigbhours(index); - return utils::Expected{ std::make_tuple( - m_path[static_cast(prev)], - m_path[static_cast(curr)], - m_path[static_cast(next)]), + const auto [prev, next] = getNeigbhours(index); + return utils::Expected{ std::make_pair(m_path[prev], m_path[next]), false }; } - Value_t nodeCost(int index, bool update) + void updateCost(std::size_t index) { - const int num_nodes = m_path.size(); - if (num_nodes < 3) { - utils::printErr("given path size less than 3", "nodeCost"); - return -1.0; - } - const auto [idx_prev, idx_curr, idx_next] = getNeigbhours(index); + const auto [idx_prev, idx_next] = getNeigbhours(index); const auto node_prev{ m_path[idx_prev] }, node_curr{ m_path[index] }, node_next{ m_path[idx_next] }; const Value_t cost = isCollinear(node_curr, node_prev, node_next) ? - Value_t{0.0} : + Value_t{ 0.0 } : insertionCost(*node_curr, *node_prev, *node_next); - if (update) { - node_curr->cost = cost; - } - return cost; + node_curr->cost = cost; } - Value_t nodeCost(Node_t node, bool update) + + bool updateCost(Node_t node) { + const int num_nodes = m_path.size(); + if (num_nodes < 3) { + utils::printErr("given path size less than 3", "nodeCost"); + return Value_t{ -1.0 }; + } const int index = findNode(node); if (index == -1) { utils::printErr( "Request to calculate cost for a node not present in path. Current path size " + std::to_string(m_path.size()), "nodeCost"); - return -1.0; + return Value_t{ -1.0 }; } - return nodeCost(index, update); - } - - NodeOpt_t removeIntersection(Node_t node_prev, Node_t node_curr, - Node_t node_next) - { - NodeOpt_t node_erased{ std::nullopt }; - int num_nodes = m_path.size(); - const int id_prev{ node_prev->id }; - const int id_curr{ node_curr->id }; - const int id_next{ node_next->id }; - for (int idx{ 0 }; idx != num_nodes;) { -#if (TSP_DEBUG_PRINT > 1) - const std::string& msg_first{ - "idx (" + std::to_string(idx) + ") num_nodes (" + - std::to_string(num_nodes) + ") path size (" + - std::to_string(m_path.size()) + ")." - }; - std::cout << ("[Debug] (removeIntersection): " + msg_first + "\n"); -#endif - const Node_t node{ m_path[static_cast(idx)] }; - const int id{ node->id }; - if ((id == id_prev) or (id == id_curr) or (id == id_next)) { - ++idx; - continue; - } - if (not isInside(node, node_prev, node_curr, node_next)) { - ++idx; - continue; - } -#if (TSP_DEBUG_PRINT > 1) - std::cout << ("[Debug] (removeIntersection): Done 1\n"); -#endif - removeNode(node); - --num_nodes; -#if (TSP_DEBUG_PRINT > 1) - std::cout << ("[Debug] (removeIntersection): Done 2\n"); -#endif - if (node_erased.has_value()) { - node_erased = (node->id < (*node_erased)->id) ? node : - node_erased; - } else { - node_erased = node; - } -#if (TSP_DEBUG_PRINT > 0) - path[0]->print(); - std::cout << "FIRST City\n"; - node->print(); - std::cout << "Removed City\n"; - node_prev->print(); - std::cout << "Triangle A City\n"; - node_curr->print(); - std::cout << "Triangle B City\n"; - node_next->print(); - std::cout << "Triangle C City\n"; - const std::string& msg{ "path size (" + - std::to_string(m_path.size()) + - ") num_nodes (" + - std::to_string(num_nodes) + ") idx (" + - std::to_string(idx) + ")." }; - std::cout << ("[Debug] (removeIntersection): " + msg + "\n"); -#endif - const auto idx_next = static_cast(properIndex(idx)); - const auto idx_prev = - static_cast(properIndex(idx_next - 1)); - nodeCost(idx_next, true); - nodeCost(idx_prev, true); - if (m_recursive) { - auto node_erased_tmp = removeIntersection( - m_path[idx_prev], node, m_path[idx_next]); - if (node_erased_tmp.has_value()) { - node_erased = - ((*node_erased_tmp)->id < (*node_erased)->id) ? - node_erased_tmp : - node_erased; - } - num_nodes = m_path.size(); - idx = 0; - } - } - return node_erased; - } - - int findBestInsertion(Node_t node) - { - const std::size_t num_nodes = m_path.size(); - if (num_nodes < 2) { - utils::printErr("given path size less than 2", "findBestInsertion"); - return -1; - } - - const City& new_city{ *node }; - - Value_t min_cost{ insertionCost(new_city, *(m_path[num_nodes - 1]), - *(m_path[0])) }; - int best_index{ 0 }; - - for (std::size_t idx{ 0 }; idx != num_nodes; ++idx) { - if (new_city.id == (m_path[idx])->id) { - utils::printErr( - "trying to add city that already exists in path", - "findBestInsertion"); - return -1; - } - if (idx == (num_nodes - 1)) { - continue; - } - const Value_t cost = - insertionCost(new_city, *(m_path[idx]), *(m_path[idx + 1])); - if (cost < min_cost) { - min_cost = cost; - best_index = idx + 1; - } - } - - return best_index; + updateCost(static_cast(index)); + return true; } - std::pair updateCostNeighbour(Node_t node) + std::pair updateCostNeighbour(Node_t node, bool self) { const std::size_t num_nodes = m_path.size(); if (num_nodes < 3) { utils::printErr("given path size less than 3", "updateCostNeighbour"); - return std::make_pair(-1, true); - } - const int index = findNode(node); - if (index == -1) { - utils::printErr( - "Request to update neighbour costs for a node not present in path. Current path size " + - std::to_string(m_path.size()), - "updateCostNeighbour"); - return std::make_pair(-1, true); + return std::make_pair(Node_t{}, true); } const utils::Expected nodes = getNeigbhours(node); if (nodes.err()) { - utils::printErr("Failed to get the neighbour nodes for index " + - std::to_string(index) + " current path size " + + utils::printErr("Failed to get the neighbour nodes for node " + + std::to_string(findNode(node)) + + " current path size " + std::to_string(m_path.size()), "updateCostNeighbour"); - return std::make_pair(-1, true); - } - const auto [node_prev, node_curr, node_next] = nodes.value(); - if (node != node_curr) { - utils::printErr( - "The node fetched from getNeigbhours doesn't match original node for index " + - std::to_string(index) + " current path size " + - std::to_string(m_path.size()), - "updateCostNeighbour"); - return std::make_pair(-1, true); + utils::printErr("Failed node details:", "updateCostNeighbour"); + node->print(); + return std::make_pair(Node_t{}, true); } - if (nodeCost(node_curr, true) < 0.0) { + const auto [node_prev, node_next] = nodes.value(); + if (self and updateCost(node) < 0.0) { utils::printErr("Invalid node cost calculate for node curr at " + - std::to_string(index) + " current path size " + + std::to_string(findNode(node)) + + " current path size " + std::to_string(m_path.size()), "updateCostNeighbour"); utils::printErr("Previous node " + std::to_string(findNode(node_prev)), "updateCostNeighbour"); node_prev->print(); - utils::printErr("Current node " + - std::to_string(findNode(node_curr)), + utils::printErr("Current node " + std::to_string(findNode(node)), "updateCostNeighbour"); - node_curr->print(); + node->print(); utils::printErr("Next node " + std::to_string(findNode(node_next)), "updateCostNeighbour"); node_next->print(); utils::printErr( "Distances : " + - std::to_string(getDistance(*node_curr, *node_next)) + ", " + - std::to_string(getDistance(*node_curr, *node_prev)) + ", " + + std::to_string(getDistance(*node, *node_next)) + ", " + + std::to_string(getDistance(*node, *node_prev)) + ", " + std::to_string(getDistance(*node_prev, *node_next)), "updateCostNeighbour"); - return std::make_pair(index, true); + return std::make_pair(node, true); } - if (nodeCost(node_prev, true) < 0.0) { + if (updateCost(node_prev) < 0.0) { const utils::Expected nodes = getNeigbhours(node_prev); if (nodes.err()) { utils::printErr("Failed to get the neighbour nodes for index " + @@ -735,32 +596,35 @@ class DiscreteENN_TSP std::to_string(m_path.size()), "updateCostNeighbour"); } - const auto [node_prev, node_curr, node_next] = nodes.value(); + const auto [node_prev_tmp, node_next_tmp] = nodes.value(); utils::printErr("Invalid node cost calculate for node prev at " + - std::to_string(properIndex(index - 1)) + + std::to_string(findNode(node_prev)) + " current path size " + std::to_string(m_path.size()), "updateCostNeighbour"); utils::printErr("Previous node " + - std::to_string(findNode(node_prev)), + std::to_string(findNode(node_prev_tmp)), "updateCostNeighbour"); - node_prev->print(); + node_prev_tmp->print(); utils::printErr("Current node " + - std::to_string(findNode(node_curr)), + std::to_string(findNode(node_prev)), "updateCostNeighbour"); - node_curr->print(); - utils::printErr("Next node " + std::to_string(findNode(node_next)), + node_prev->print(); + utils::printErr("Next node " + + std::to_string(findNode(node_next_tmp)), "updateCostNeighbour"); - node_next->print(); + node_next_tmp->print(); utils::printErr( "Distances : " + - std::to_string(getDistance(*node_curr, *node_next)) + ", " + - std::to_string(getDistance(*node_curr, *node_prev)) + ", " + - std::to_string(getDistance(*node_prev, *node_next)), + std::to_string(getDistance(*node_prev, *node_next_tmp)) + + ", " + + std::to_string(getDistance(*node_prev, *node_prev_tmp)) + + ", " + + std::to_string(getDistance(*node_prev_tmp, *node_next_tmp)), "updateCostNeighbour"); - return std::make_pair(properIndex(index - 1), true); + return std::make_pair(node_prev, true); } - if (nodeCost(node_next, true) < 0.0) { + if (updateCost(node_next) < 0.0) { const utils::Expected nodes = getNeigbhours(node_next); if (nodes.err()) { utils::printErr("Failed to get the neighbour nodes for index " + @@ -769,43 +633,46 @@ class DiscreteENN_TSP std::to_string(m_path.size()), "updateCostNeighbour"); } - const auto [node_prev, node_curr, node_next] = nodes.value(); + const auto [node_prev_tmp, node_next_tmp] = nodes.value(); utils::printErr("Invalid node cost calculate for node next at " + - std::to_string(properIndex(index + 1)) + + std::to_string(findNode(node_next)) + " current path size " + std::to_string(m_path.size()), "updateCostNeighbour"); utils::printErr("Previous node " + - std::to_string(findNode(node_prev)), + std::to_string(findNode(node_prev_tmp)), "updateCostNeighbour"); - node_prev->print(); + node_prev_tmp->print(); utils::printErr("Current node " + - std::to_string(findNode(node_curr)), - "updateCostNeighbour"); - node_curr->print(); - utils::printErr("Next node " + std::to_string(findNode(node_next)), + std::to_string(findNode(node_next)), "updateCostNeighbour"); node_next->print(); + utils::printErr("Next node " + + std::to_string(findNode(node_next_tmp)), + "updateCostNeighbour"); + node_next_tmp->print(); utils::printErr( "Distances : " + - std::to_string(getDistance(*node_curr, *node_next)) + ", " + - std::to_string(getDistance(*node_curr, *node_prev)) + ", " + - std::to_string(getDistance(*node_prev, *node_next)), + std::to_string(getDistance(*node_next, *node_next_tmp)) + + ", " + + std::to_string(getDistance(*node_next, *node_prev_tmp)) + + ", " + + std::to_string(getDistance(*node_prev_tmp, *node_next_tmp)), "updateCostNeighbour"); - return std::make_pair(properIndex(index + 1), true); + return std::make_pair(node_next, true); } - return std::make_pair(index, false); + return std::make_pair(node, false); } std::pair updateCostAll() { - const int num_nodes = m_path.size(); - for (int idx{ 0 }; idx != num_nodes; ++idx) { - if (nodeCost(m_path[static_cast(idx)], true) < 0.0) { + const std::size_t num_nodes = m_path.size(); + for (std::size_t idx{ 0 }; idx != num_nodes; ++idx) { + if (updateCost(m_path[idx]) < 0.0) { utils::printErr("Invalid node cost calculate for node at " + std::to_string(idx) + " current path size " + - std::to_string(m_path.size()), + std::to_string(num_nodes), "updateCostAll"); return std::make_pair(idx, true); } @@ -813,20 +680,101 @@ class DiscreteENN_TSP return std::make_pair(num_nodes, false); } + int findBestInsertion(Node_t node) + { + const std::size_t num_nodes = m_path.size(); + if (num_nodes < 2) { + utils::printErr("given path size less than 2", "findBestInsertion"); + return -1; + } + + const City& new_city{ *node }; + + Value_t min_cost{ insertionCost(new_city, *(m_path[num_nodes - 1]), + *(m_path[0])) }; + int best_index{ 0 }; + + for (std::size_t idx{ 0 }; idx != (num_nodes - 1); ++idx) { + if (new_city.id == (m_path[idx])->id) { + utils::printErr( + "trying to add city that already exists in path", + "findBestInsertion"); + return -1; + } + const Value_t cost = + insertionCost(new_city, *(m_path[idx]), *(m_path[idx + 1])); + if (cost < min_cost) { + min_cost = cost; + best_index = idx + 1; + } + } + + return best_index; + } + + NodeOpt_t removeIntersection(Node_t node_prev, Node_t node_curr, + Node_t node_next) + { + NodeOpt_t node_erased{ std::nullopt }; + int num_nodes = m_path.size(); + const int id_prev{ node_prev->id }; + const int id_curr{ node_curr->id }; + const int id_next{ node_next->id }; + for (int idx{ 0 }; idx != num_nodes;) { + if (num_nodes == 3) { + break; + } + if (node_prev->on_stack or node_next->on_stack) { + break; + } + const Node_t node{ m_path[static_cast(idx)] }; + const int id{ node->id }; + if ((id == id_prev) or (id == id_curr) or (id == id_next)) { + ++idx; + continue; + } + if (not isInside(node, node_prev, node_curr, node_next)) { + ++idx; + continue; + } + removeNode(node); + --num_nodes; + if (node_erased.has_value()) { + node_erased = (node->id < (*node_erased)->id) ? node : + node_erased; + } else { + node_erased = node; + } + const auto idx_next = properIndex(idx); + const auto idx_prev = properIndex(idx_next - 1); + updateCost(idx_next); + updateCost(idx_prev); + if (m_rmIntersectRecurse) { + auto node_erased_tmp = removeIntersection( + m_path[idx_prev], node, m_path[idx_next]); + if (node_erased_tmp.has_value()) { + node_erased = + ((*node_erased_tmp)->id < (*node_erased)->id) ? + node_erased_tmp : + node_erased; + } + num_nodes = m_path.size(); + idx = 0; + } + } + return node_erased; + } + NodeExp_t validatePath() { NodeOpt_t node_erased{ std::nullopt }; int num_nodes = m_path.size(); - int num_nodes_prev{ 0 }; + [[maybe_unused]] int num_nodes_prev{ 0 }; for (int idx{ 0 }; idx != num_nodes;) { -#if (TSP_DEBUG_PRINT > 1) - const std::string& msg{ "idx (" + std::to_string(idx) + - ") num_nodes (" + - std::to_string(num_nodes) + - ") path size (" + - std::to_string(m_path.size()) + ")." }; - std::cout << ("[Debug] (validatePath): " + msg + "\n"); -#endif + if (num_nodes == 2) { + m_fromScratch = true; + break; + } const Node_t node{ m_path[static_cast(idx)] }; const auto [valid, err1] = validateNode(node); if (err1) { @@ -840,9 +788,6 @@ class DiscreteENN_TSP ++idx; continue; } -#if (TSP_DEBUG_PRINT > 1) - std::cout << ("[Debug] (validatePath): Done 1\n"); -#endif removeNode(node); num_nodes_prev = num_nodes; --num_nodes; @@ -852,15 +797,11 @@ class DiscreteENN_TSP } else { node_erased = node; } -#if (TSP_DEBUG_PRINT > 1) - std::cout << ("[Debug] (validatePath): Done 2\n"); -#endif - const auto idx_next = static_cast(properIndex(idx)); - const auto idx_prev = - static_cast(properIndex(idx_next - 1)); - nodeCost(idx_next, true); - nodeCost(idx_prev, true); - if (m_intersection) { + const auto idx_next = properIndex(idx); + const auto idx_prev = properIndex(idx_next - 1); + updateCost(idx_next); + updateCost(idx_prev); + if (m_validIntersectCK) { NodeOpt_t node_erased_tmp = removeIntersection( m_path[idx_prev], node, m_path[idx_next]); if (node_erased_tmp.has_value()) { @@ -871,13 +812,7 @@ class DiscreteENN_TSP } num_nodes = m_path.size(); } -#if (TSP_DEBUG_PRINT > 1) - std::cout << ("[Debug] (validatePath): Done 3\n"); -#endif idx = 0; -#if (TSP_DEBUG_PRINT > 1) - std::cout << ("[Debug] (validatePath): Done 4\n"); -#endif } return NodeExp_t{ node_erased, false }; } @@ -928,9 +863,19 @@ class DiscreteENN_TSP if (not it->on_stack) { ++it; } else { -#if (TSP_DEBUG_PRINT > 0) - std::cout << ("\n[Debug] (run): addNode\n"); -#endif + if (m_fromScratch) { + m_fromScratch = false; + addNode(0, it); + const auto [discard1, err1] = updateCostNeighbour(it, true); + if (err1) { + utils::printErr( + "updateCostNeighbour failed at index 0 for for path size " + + std::to_string(m_path.size()), + "run"); + return false; + } + continue; + } const int idx_added = findBestInsertion(it); if (idx_added == -1) { utils::printErr("findBestInsertion failed at index " + @@ -941,7 +886,7 @@ class DiscreteENN_TSP return false; } addNode(idx_added, it); - const auto [discard1, err1] = updateCostNeighbour(it); + const auto [discard1, err1] = updateCostNeighbour(it, true); if (err1) { utils::printErr("updateCostNeighbour failed at index " + std::to_string(idx_added) + @@ -952,9 +897,6 @@ class DiscreteENN_TSP } indices_added[repeat_check] = idx_added; ++repeat_check; -#if (TSP_DEBUG_PRINT > 0) - std::cout << ("\n[Debug] (run): addNode removeIntersection\n"); -#endif const utils::Expected nodes = getNeigbhours(it); if (nodes.err()) { @@ -965,39 +907,20 @@ class DiscreteENN_TSP "run"); return false; } - const auto [node_prev, node_curr, node_next] = nodes.value(); - if (it != node_curr) { - utils::printErr( - "The node fetched from getNeigbhours doesn't match original node for index " + - std::to_string(idx_added) + " current path size " + - std::to_string(m_path.size()), - "run"); - return false; - } + const auto [node_prev, node_next] = nodes.value(); const auto it_erased1 = - removeIntersection(node_prev, node_curr, node_next); - if (it_erased1.has_value()) { -#if (TSP_DEBUG_PRINT > 0) - std::cout << ("\n[Debug] (run): addNode updateCostAll\n"); -#endif - // const auto [idx_fail, err] = updateCostAll(); - // if (err) { - // utils::printErr("updateCostAll failed at index " + - // std::to_string(idx_fail) + - // " path size " + - // std::to_string(m_path.size()), - // "run"); - // return false; - // } - } -#if (TSP_DEBUG_PRINT > 0) - std::cout << ("\n[Debug] (run): validatePath\n"); -#endif + removeIntersection(node_prev, it, node_next); + const auto it_erased2 = validatePath(); if (it_erased2.err()) { utils::printErr("validatePath failed", "run"); return false; } + if (m_fromScratch) { + const int idx_rand{ distrib(gen) }; + it = it_begin + idx_rand; + continue; + } // if (it_erased1.has_value() or it_erased2.has_value()) { // it = it_begin; @@ -1030,12 +953,11 @@ class DiscreteENN_TSP std::to_string(m_path.size()) + "/" + std::to_string(num_cities), "run"); - utils::printInfo("Repeating pattern:", - "run"); + utils::printInfo("Repeating pattern:", "run"); const auto idx_it_end{ indices_added.end() }; - for (auto idx_it{idx_it_end - m_repeatLen}; idx_it != idx_it_end; ++idx_it) { + for (auto idx_it{ idx_it_end - m_repeatLen }; + idx_it != idx_it_end; ++idx_it) { std::cout << *idx_it << ","; - } std::cout << std::endl; const int idx_rand{ distrib(gen) }; @@ -1078,11 +1000,14 @@ class DiscreteENN_TSP } private: - bool m_recursive; - bool m_intersection; + bool m_rmIntersectRecurse; + bool m_validIntersectCK; + bool m_fromScratch{ false }; int m_initialSize; int m_iterRandomize; int m_repeatLen; + std::string m_pattern; + std::vector m_patternSizes; Cities_t m_stack; Path_t m_path; };