Skip to content

Commit

Permalink
fix: move cleanPath to utils and utils::isEqual to compare floating p…
Browse files Browse the repository at this point in the history
…oint types
  • Loading branch information
Akhil-CM committed Apr 23, 2024
1 parent b6dbe79 commit eae55a2
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 53 deletions.
23 changes: 3 additions & 20 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include "tsp_discrete_enn.hpp"
#include "utils.hpp"

#include <filesystem>
#include <chrono>

namespace stdfs = std::filesystem;
Expand All @@ -13,23 +12,12 @@ using TimeUnit_t = TimeMilliS_t;
using TimePoint_t = std::chrono::steady_clock::time_point;
const std::string& time_unit{ "ms" };

template <typename F,
typename std::enable_if<std::is_convertible_v<F, stdfs::path>>::type* =
nullptr>
stdfs::path getCleanPath(const F& src)
{
const stdfs::path tmp_src{ src };
const stdfs::path lexical_src{ tmp_src.lexically_normal() };
const stdfs::path abs_src{ stdfs::absolute(lexical_src) };
return stdfs::weakly_canonical(abs_src);
}

const std::string& Data_Optimal_Filename{ "./tsp_optimal_distances.csv" };
const stdfs::path Data_Optimal_Path{ getCleanPath(
const stdfs::path Data_Optimal_Path{ utils::getCleanPath(
stdfs::current_path() / stdfs::path(Data_Optimal_Filename)) };

const std::string& Data_Dir{ "Data/ALL_tsp" };
stdfs::path Data_Path{ getCleanPath(stdfs::current_path() /
stdfs::path Data_Path{ utils::getCleanPath(stdfs::current_path() /
stdfs::path(Data_Dir)) };

const std::string& Data_Filename_berlin{ "berlin52.tsp" };
Expand Down Expand Up @@ -90,7 +78,7 @@ int main(int argc, char** argv)
}
} else {
if (not Data_Filename.empty()) {
Data_Path = getCleanPath(Data_Filename);
Data_Path = utils::getCleanPath(Data_Filename);
}
runs_failed = runPipelineDir(Data_Path, rng, draw_path, draw_coords, distance_map, optimal_distance_map);
}
Expand Down Expand Up @@ -205,11 +193,6 @@ int runPipelineSingle(const stdfs::path&data_path, std::default_random_engine& r
// Create and setup Discrete ENN Solver
// -------------------------------------------
DiscreteENN_TSP enn_tsp;
enn_tsp.initialSize() = Num_Nodes_Initial;
enn_tsp.validIntersectCK() = Validation_Intersection;
enn_tsp.rmIntersectRecurse() = Intersection_Recursive;
enn_tsp.iterRandomize() = Iter_Randomize;
enn_tsp.repeatLength() = Repeat_Check_Length;

// -------------------------------------------
// Construct Stack
Expand Down
5 changes: 0 additions & 5 deletions tsp_discrete_enn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ int main(int argc, char** argv)
// Create and setup Discrete ENN Solver
// -------------------------------------------
DiscreteENN_TSP enn_tsp;
enn_tsp.initialSize() = Num_Nodes_Initial;
enn_tsp.validIntersectCK() = Validation_Intersection;
enn_tsp.rmIntersectRecurse() = Intersection_Recursive;
enn_tsp.iterRandomize() = Iter_Randomize;
enn_tsp.repeatLength() = Repeat_Check_Length;

// -------------------------------------------
// Construct Stack
Expand Down
55 changes: 28 additions & 27 deletions tsp_discrete_enn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ using namespace std::string_literals;
using utils::ErrorBool, utils::ErrorMsg;

typedef float Value_t;
constexpr Value_t VALUE_ZERO{ Value_t{ 0 } };
constexpr Value_t VALUE_ONE_NEG{ Value_t{ -1 } };

constexpr std::size_t Num_Nodes_Initial{ 3 };
constexpr bool Validation_Intersection{ true };
Expand Down Expand Up @@ -74,12 +76,12 @@ typedef std::map<int, Cities_t> CityLayers_t;
typedef std::optional<Node_t> NodeOpt_t;
template <typename T> using NodeExp_t = utils::Expected<Node_t, T>;

template <> bool utils::MatchItem<City>::operator()(const City& city)
template <> inline bool utils::MatchItem<City>::operator()(const City& city)
{
return (city.id == m_item.id);
}

template <> bool utils::MatchItem<Node_t>::operator()(const Node_t& node)
template <> inline bool utils::MatchItem<Node_t>::operator()(const Node_t& node)
{
return (node->id == m_item->id);
}
Expand Down Expand Up @@ -127,9 +129,9 @@ class MinMaxCoords
public:
MinMaxCoords()
: min_x{ std::numeric_limits<Value_t>::max() }
, max_x{ -1.0 }
, max_x{ VALUE_ONE_NEG }
, min_y{ std::numeric_limits<Value_t>::max() }
, max_y{ -1.0 }
, max_y{ VALUE_ONE_NEG }
{
}
MinMaxCoords(Value_t minx, Value_t maxx, Value_t miny, Value_t maxy)
Expand Down Expand Up @@ -160,9 +162,9 @@ class MinMaxCoords
void reset()
{
min_x = std::numeric_limits<Value_t>::max();
max_x = -1.0;
max_x = VALUE_ONE_NEG;
min_y = std::numeric_limits<Value_t>::max();
max_y = -1.0;
max_y = VALUE_ONE_NEG;
}

void update(const Path_t& path)
Expand Down Expand Up @@ -311,58 +313,57 @@ void createStack(const Cities_t& cities, Cities_t& stack, int& layers)
}
}

Value_t getDistance(const City& a, const City& b)
inline Value_t getDistance(const City& a, const City& b)
{
const auto x_sqr = (a.x - b.x) * (a.x - b.x);
const auto y_sqr = (a.y - b.y) * (a.y - b.y);
return std::sqrt(x_sqr + y_sqr);
}

Value_t insertionCost(const City& new_city, const City& cityA,
inline Value_t insertionCost(const City& new_city, const City& cityA,
const City& cityB)
{
return getDistance(new_city, cityA) + getDistance(new_city, cityB) -
getDistance(cityA, cityB);
}

double getArea(const City& a, const City& b, const City& c)
inline double getArea(const City& a, const City& b, const City& c)
{
return std::abs(a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)) /
2.0;
}
bool isCollinearAndBetween(const City& c, const City& a, const City& b)
inline bool isCollinearAndBetween(const City& c, const City& a, const City& b)
{
return std::min(a.x, b.x) <= c.x && c.x <= std::max(a.x, b.x) &&
std::min(a.y, b.y) <= c.y && c.y <= std::max(a.y, b.y);
}

bool isCollinear(Node_t nodeA, Node_t nodeB, Node_t nodeC)
inline bool isCollinear(Node_t nodeA, Node_t nodeB, Node_t nodeC)
{
const Value_t area_total = getArea(*nodeA, *nodeB, *nodeC);

return (std::abs(area_total) < utils::tolerance);
return utils::isEqual(area_total, VALUE_ZERO);
}

bool isInside(Node_t node, Node_t nodeA, Node_t nodeB, Node_t nodeC)
inline bool isInside(Node_t node, Node_t nodeA, Node_t nodeB, Node_t nodeC)
{
const Value_t area_total = getArea(*nodeA, *nodeB, *nodeC);

const Value_t area1 = getArea(*node, *nodeA, *nodeB);
const Value_t area2 = getArea(*node, *nodeB, *nodeC);
const Value_t area3 = getArea(*node, *nodeC, *nodeA);

if (std::abs(area1) < utils::tolerance) {
if (utils::isEqual(area1, VALUE_ZERO)) {
return isCollinearAndBetween(*node, *nodeA, *nodeB);
}
if (std::abs(area2) < utils::tolerance) {
if (utils::isEqual(area2, VALUE_ZERO)) {
return isCollinearAndBetween(*node, *nodeB, *nodeC);
}
if (std::abs(area3) < utils::tolerance) {
if (utils::isEqual(area3, VALUE_ZERO)) {
return isCollinearAndBetween(*node, *nodeC, *nodeA);
}

const Value_t area_diff = std::abs(area_total - (area1 + area2 + area3));
return (area_diff < utils::tolerance);
return utils::isEqual(area_total, (area1 + area2 + area3));
}

class DiscreteENN_TSP
Expand Down Expand Up @@ -463,7 +464,7 @@ class DiscreteENN_TSP
return std::make_pair(false, true);
}
const Value_t cost_current{ node->cost };
if (cost_current < utils::tolerance) {
if (utils::isEqual(cost_current, VALUE_ZERO)) {
return std::make_pair(true, false);
}
if (index != 0 and index != static_cast<int>(num_nodes - 1)) {
Expand Down Expand Up @@ -519,7 +520,7 @@ class DiscreteENN_TSP
node_next{ m_path[idx_next] };
const Value_t cost =
isCollinear(node_curr, node_prev, node_next) ?
Value_t{ 0.0 } :
VALUE_ZERO :
insertionCost(*node_curr, *node_prev, *node_next);
node_curr->cost = cost;
}
Expand All @@ -529,15 +530,15 @@ class DiscreteENN_TSP
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 };
return VALUE_ONE_NEG;
}
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 Value_t{ -1.0 };
return VALUE_ONE_NEG;
}
updateCost(static_cast<std::size_t>(index));
return true;
Expand Down Expand Up @@ -1000,12 +1001,12 @@ class DiscreteENN_TSP
}

private:
bool m_rmIntersectRecurse;
bool m_validIntersectCK;
bool m_rmIntersectRecurse{ Intersection_Recursive };
bool m_validIntersectCK{ Validation_Intersection };
bool m_fromScratch{ false };
int m_initialSize;
int m_iterRandomize;
int m_repeatLen;
int m_initialSize{ Num_Nodes_Initial };
int m_iterRandomize{ Iter_Randomize };
int m_repeatLen{ Repeat_Check_Length };
std::string m_pattern;
std::vector<std::size_t> m_patternSizes;
Cities_t m_stack;
Expand Down
21 changes: 20 additions & 1 deletion utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@
#include <cassert>
#include <optional>
#include <vector>
#include <filesystem>

namespace utils {

namespace stdfs = std::filesystem;

using namespace std::string_literals;

// Floating point precision helpers
constexpr float tolerance = 1e-4;
constexpr float epsilonf = 1e-4;
inline bool isEqual(float a, float b)
{
return std::abs(a - b) < epsilonf;
}

// Console write related helpers
const std::string Line_Str = std::string{}.assign(30, '-');
Expand Down Expand Up @@ -77,6 +84,18 @@ inline void printErr(const std::string& msg, const std::string& fname = "")
std::cerr << Line_Str << '\n';
}

template <typename F,
typename std::enable_if<std::is_convertible_v<F, stdfs::path>>::type* =
nullptr>
stdfs::path getCleanPath(const F& src)
{
const stdfs::path tmp_src{ src };
const stdfs::path lexical_src{ tmp_src.lexically_normal() };
const stdfs::path abs_src{ stdfs::absolute(lexical_src) };
return stdfs::weakly_canonical(abs_src);
}


// "Expected" type helpers
template <typename T, typename E> class Expected
{
Expand Down

0 comments on commit eae55a2

Please sign in to comment.