Hidden_Line_Problem/src/HiddenLines.cpp
2022-03-09 13:24:19 -06:00

306 lines
9.1 KiB
C++

//Hidden Lines work
#include <iostream>
#include <set>
#include <string>
#include <fstream>
#include <limits>
#include <math.h>
#include <utility>
#include <algorithm>
#include "HiddenLines.h"
HL::HL()
{
//Read from CSV and construct the problem from the given lines
lines = construct_HWprob();
}
std::map<int, Line> HL::get_map()
{
return line_holder;
}
void HL::print_sol()
{
auto sol = get_sol();
for(auto itr = sol.begin(); itr != sol.end(); itr++){
double start_range = std::get<0>(std::get<1>(*itr));
std::string start_print = std::to_string(start_range);
if(start_range == std::numeric_limits<double>::lowest())
start_print = "-inf";
double stop_range = std::get<1>(std::get<1>(*itr));
std::string stop_print = std::to_string(stop_range);
if(stop_range == std::numeric_limits<double>::max())
stop_print = "inf";
std::cout << "Line ID " << std::get<0>(*itr) << " visible from x=" <<
start_print << " to x=" << stop_print << std::endl;
}
}
//Divide and Conquer Strategy using recursive call to divide ls and merge using merge()
std::vector<Line> HL::gen_sol(std::vector<Line>& ls){
HL inst = *this;
auto line_holder = inst.get_map();
if (ls.size() > 2){
//Create left and right half sets
int split = ceil(ls.size()/2);
std::vector<Line> lh;
std::vector<Line> rh;
//No index access for sets
auto end_itr = ls.begin();
std::advance(end_itr, split);
for(auto itr = ls.begin(); itr != end_itr; itr++){
lh.push_back(*itr);
}
for(auto itr = end_itr; itr != ls.end(); itr++){
rh.push_back(*itr);
}
std::cout << "Left half is size " << lh.size() << " and right half is size " << rh.size() << std::endl;
//Recursive call
auto merged = merge(inst.gen_sol(lh), inst.gen_sol(rh));
for (auto itr = merged.begin(); itr != merged.end(); itr++){
Line l1 = *itr;
sol.push_back(std::make_pair(l1.get_id(), std::make_pair(l1.get_vis_start(), l1.get_vis_end())));
}
//Cleanup Solution
/*
std::set<std::pair<int, std::pair<double, double>>> new_sol;
for(std::set<std::pair<int, std::pair<double, double>>>::iterator itr = sol.begin(); itr != sol.end(); itr++){
auto start_range = std::get<0>(std::get<1>(*itr));
auto stop_range = std::get<1>(std::get<1>(*itr));
double my_slope = std::get<1>(*line_holder.find(std::get<0>(*itr))).get_slope();
int my_id = std::get<0>(*itr);
if(start_range == stop_range)
continue;
//Handle overlaps
std::set<std::pair<int, std::pair<double, double>>>::iterator it = std::find_if(sol.begin(), sol.end(),
[start_range, my_id](const std::pair<int, std::pair<double, double>>& p )
{ return (std::get<0>(std::get<1>(p)) == start_range && std::get<0>(p) != my_id); });
if (it != sol.end()){
double stored_stop = std::get<1>(std::get<1>(*it));
double stored_slope = std::get<1>(*line_holder.find(std::get<0>(*it))).get_slope();
int stored_id = std::get<0>(*it);
std::cout << "Matched" << std::endl;
//Change lines' vis starts and ends
if (my_slope < stored_slope){
std::get<1>(*line_holder.find(std::get<0>(*itr))).set_vis_start(start_range);
std::get<1>(*line_holder.find(std::get<0>(*itr))).set_vis_end(stored_stop);
new_sol.insert(std::make_pair(my_id, std::make_pair(start_range, stored_stop)));
std::get<1>(*line_holder.find(std::get<0>(*it))).set_vis_start(stored_stop);
std::get<1>(*line_holder.find(std::get<0>(*it))).set_vis_end(stop_range);
new_sol.insert(std::make_pair(stored_id, std::make_pair(stored_stop, stop_range)));
}
else{
std::get<1>(*line_holder.find(std::get<0>(*it))).set_vis_start(start_range);
std::get<1>(*line_holder.find(std::get<0>(*it))).set_vis_end(stored_stop);
new_sol.insert(std::make_pair(stored_id, std::make_pair(start_range, stored_stop)));
std::get<1>(*line_holder.find(std::get<0>(*itr))).set_vis_start(stored_stop);
std::get<1>(*line_holder.find(std::get<0>(*itr))).set_vis_end(stop_range);
new_sol.insert(std::make_pair(my_id, std::make_pair(stored_stop, stop_range)));
}
}
else{
new_sol.insert(*itr);
}
}
inst.set_sol(new_sol);
*/
return merged;
}
//Set with 2 lines is a base case: both are visible at +-inf respectively, and intersection is where they change
//visibility
else if (ls.size() == 2){
Line l1 = *(ls.begin());
Line l2 = *(ls.end());
double isec = (l2.get_ycept() - l1.get_ycept())/(l1.get_slope() - l2.get_slope());
if (l1.get_slope() < l2.get_slope()){
l1.set_vis_end(isec);
l2.set_vis_start(isec);
}
else{
l2.set_vis_end(isec);
l1.set_vis_start(isec);
}
//Insert partial solutions
sol.push_back(std::make_pair(l1.get_id(), std::make_pair(l1.get_vis_start(), l1.get_vis_end())));
sol.push_back(std::make_pair(l2.get_id(), std::make_pair(l2.get_vis_start(), l2.get_vis_end())));
return ls;
}
//Set with 1 line: Just return
else{
return ls;
}
}
std::vector<Line> HL::construct_HWprob(){
//Set to hold all our Lines
std::set<Line> sorted_lines;
std::vector<Line> lines;
//Hold our doubles from each line
std::vector<double> tmp_data;
std::ifstream data("../data/data.csv");
if(data.is_open()){
std::string csvline;
//Throw header row away
std::getline(data, csvline);
while(std::getline(data, csvline, ',')){
if(!csvline.empty()){
tmp_data.emplace_back(std::stod(csvline));
}
}
}
//Close file
data.close();
while(!tmp_data.empty()){
double slope = *tmp_data.begin();
tmp_data.erase(tmp_data.begin());
if(tmp_data.empty()){
std::cout << "Error in CSV file: Number of slope entries does not match the number of y-intercept entries. ";
std::cout << "Please correct the CSV file and try again." << std::endl;
exit(-1);
}
double ycept = *tmp_data.begin();
tmp_data.erase(tmp_data.begin());
Line newline = Line(slope, ycept);
newline.set_id();
sorted_lines.insert(newline);
lines.push_back(newline);
auto line_holder = get_map();
//line_holder[newline.get_id()] = newline;
line_holder.insert(std::pair<int, Line> (newline.get_id(), newline));
}
//Set most neg slope to start range of -inf, and most pos to stop of inf
Line lend = *lines.end();
Line lbegin = *lines.begin();
lend.set_vis_end(std::numeric_limits<double>::max());
lbegin.set_vis_start(std::numeric_limits<double>::lowest());
std::string lend_stop = std::to_string(lend.get_vis_end());
std::string lbegin_start = std::to_string(lbegin.get_vis_start());
if(lend.get_vis_end() == std::numeric_limits<double>::max())
lend_stop = "inf";
if(lbegin.get_vis_start() == std::numeric_limits<double>::lowest())
lbegin_start = "-inf";
std::cout << "---------------Sorted Lines by slope:---------------" << std::endl;
for(Line line : sorted_lines)
{
std::cout << "Line " << line.get_id() << " has slope " << line.get_slope()
<< " and a y-intercept of " << line.get_ycept() << std::endl;
std::cout << "Line " << line.get_id() << " visible from x=" << line.get_vis_start() << " to x=" <<line.get_vis_end() << std::endl;
}
std::cout << "-----------------------------------------------------" << std::endl;
std::cout << "From the sorted lines, we can derive that Line " << lend.get_id() << " is visible from x=" << lend.get_vis_start() <<
" to x=" << lend_stop << std::endl;
std::cout << "From the sorted lines, we can derive that Line " << lbegin.get_id() << " is visible from x=" << lbegin.get_vis_start() <<
" to x=" << lbegin.get_vis_end() << std::endl;
return lines;
}
std::vector<Line> merge(std::vector<Line> lh, std::vector<Line> rh){
std::vector<Line> merged;
auto litr = lh.begin();
auto ritr = rh.begin();
while(litr != lh.end() && ritr != rh.end()){
Line l1 = *litr;
Line l2 = *ritr;
//3 Cases: lh slope is less, slopes are equal, and lh slope is greater
//Case 1:
if (l1.get_slope() < l2.get_slope()){
double isec = (l2.get_ycept() - l1.get_ycept())/(l1.get_slope() - l2.get_slope());
if(isec < l1.get_vis_end()){
l1.set_vis_end(isec);
l2.set_vis_start(isec);
}
merged.push_back(l1);
merged.push_back(l2);
litr++;
}
else if (l1.get_slope() == l2.get_slope() && l1.get_id() != l2.get_id()){
if (l1.get_ycept() > l2.get_ycept()){
l2.set_vis_start(0);
l2.set_vis_end(0);
merged.push_back(l1);
}
else{
l1.set_vis_start(0);
l1.set_vis_end(0);
merged.push_back(l2);
}
litr++;
ritr++;
}
//lh slope > rh
else{
double isec = (l2.get_ycept() - l1.get_ycept())/(l1.get_slope() - l2.get_slope());
if(isec < l1.get_vis_start()){
l1.set_vis_start(isec);
l2.set_vis_end(isec);
}
merged.push_back(l1);
merged.push_back(l2);
ritr++;
}
}
return merged;
}
std::vector<Line> HL::get_lines() const{
return lines;
}
std::vector<std::pair<int, std::pair<double, double>>> HL::get_sol() const{
return sol;
}
void HL::set_sol(std::vector<std::pair<int, std::pair<double, double>>> &new_sol)
{
sol = new_sol;
}