423 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
| #include <thread>
 | |
| #include <chrono>
 | |
| #include <ctime>
 | |
| #include <cstdlib>
 | |
| #include <iostream>
 | |
| #include <mutex>
 | |
| #include <vector>
 | |
| #include <queue>
 | |
| #include <atomic>
 | |
| #include <condition_variable>
 | |
| #include <cmath>
 | |
| #include <map>
 | |
| #include <random>
 | |
| #include "libpoly.h"
 | |
| 
 | |
| 
 | |
| //############################################################ GLOBALS
 | |
| 
 | |
| std::condition_variable can_pop;
 | |
| std::condition_variable can_push;
 | |
| 
 | |
| std::atomic_uint32_t active_producents;
 | |
| std::atomic_uint32_t active_consuments;
 | |
| std::ostream& os = std::cout;
 | |
| std::mutex os_l;
 | |
| 
 | |
| //############################# MODIFY HERE
 | |
| 
 | |
| constexpr unsigned NUM_PRODUCENTS = 2;
 | |
| constexpr unsigned NUM_WORKERS = 5;
 | |
| 
 | |
| //############################################################ COMMON STRUCTURES
 | |
| 
 | |
| struct Temp_Task: public std::enable_shared_from_this< Temp_Task > {
 | |
|     LP_Polygon p;
 | |
|     double minimal_triangulation;
 | |
|     Temp_Task(LP_Polygon&& _p): p(_p){}
 | |
| };
 | |
| 
 | |
| using Temp_Task_p = std::shared_ptr< Temp_Task >;
 | |
| 
 | |
| class Task {
 | |
| private:
 | |
|     Temp_Task_p task;
 | |
| 
 | |
|     double triangulate_basic(LP_Polygon* p);
 | |
|     double triangulate();
 | |
|     double triangulate_subpolys(std::vector<bool> poly_key, std::map<int, double>* m);
 | |
|     std::vector<bool> create_key(std::vector<int>* indices);
 | |
| 
 | |
| public:
 | |
|     Task(): task(nullptr){};
 | |
|     Task(const Task&) = delete;
 | |
|     Task(Task&& t): task(t.task){
 | |
|         t.task.reset();
 | |
|     }
 | |
|     Task(Temp_Task_p&& tp): task(tp){}
 | |
| 
 | |
|     double solution() const { return task->minimal_triangulation; }
 | |
|     bool is_empty() const {
 | |
|         return task.get() == nullptr;
 | |
|     }
 | |
| 
 | |
|     void solve_stupid(){
 | |
|         task->minimal_triangulation = triangulate_basic(&(task->p));
 | |
|     }
 | |
|     void solve_less_stupid(){ task->minimal_triangulation = triangulate(); }
 | |
| 
 | |
|     Temp_Task_p unwrap(){ //  TODO: vymyslet jinak, zaručit po tomto kroku selfdestruct
 | |
|         return std::move(task);
 | |
|     }
 | |
| };
 | |
| 
 | |
| class Queue{
 | |
|     std::queue<Task> q;
 | |
|     std::mutex q_l;
 | |
|     const size_t MAX_LENGHT = 100'000;
 | |
|     
 | |
| public:
 | |
| 
 | |
|     void push(Task&& t){
 | |
|         std::unique_lock<std::mutex> pushlock(q_l);
 | |
|         can_push.wait(pushlock, [this](){ return (q.size() < MAX_LENGHT); });
 | |
| 
 | |
|         q.push(std::move(t));
 | |
|         pushlock.unlock();
 | |
|         can_pop.notify_one();
 | |
|     }
 | |
| 
 | |
|     Task pop(){
 | |
|         std::unique_lock<std::mutex> poplock(q_l);
 | |
|         can_pop.wait(poplock, [this](){ return !is_empty(); });
 | |
|         
 | |
|         Task t(std::move(q.front()));
 | |
|         q.pop();
 | |
|         poplock.unlock();
 | |
|         can_push.notify_one();
 | |
|         return t;
 | |
|     }
 | |
| 
 | |
|     bool is_empty( ){
 | |
|         return q.empty();
 | |
|     }
 | |
| };
 | |
| 
 | |
| using task_queue_ptr = std::shared_ptr<Queue>;
 | |
| 
 | |
| //############################################################ PRODUCE THREAD
 | |
| /*
 | |
| class Producent{
 | |
| private:
 | |
|     task_queue_ptr task_queue;
 | |
| public:
 | |
|     Producent(task_queue_ptr tq): task_queue(tq){ active_producents++; }
 | |
|     Producent(const Producent&) = delete;
 | |
|     ~Producent(){ active_producents--; }
 | |
| 
 | |
|     Task get_task(){
 | |
|         //LP_Task_p tp = pickup_task();
 | |
|         os_l.lock();
 | |
|         os << "picked up" << std::endl;
 | |
|         os_l.unlock();
 | |
| 
 | |
|         //#########################3TEMP_PART:
 | |
|         // std::vector< LP_Point > points;
 | |
|         // srand(static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()));
 | |
|         // int num_of_points = (rand()%10) + 1;
 | |
|         // for(int i = 0; i < num_of_points; i++){
 | |
|         //     LP_Point p;
 | |
| 
 | |
|         //     p.x = rand()%199 +1;
 | |
|         //     p.y = rand()%199 +1; 
 | |
|         //     points.push_back(p);
 | |
|         // }
 | |
|         // LP_Polygon p(std::move(points));
 | |
|         // Temp_Task_p tp = std::make_shared<Temp_Task>(std::move( p ));
 | |
| 
 | |
|         return Task(std::move(tp));
 | |
|     }
 | |
| 
 | |
|     void fill_queue(){
 | |
|         while(1){
 | |
|             Task t = get_task();
 | |
|             if(t.is_empty()) break;
 | |
|             else{
 | |
|                 task_queue->push(std::move(t));
 | |
|                 os_l.lock();
 | |
|                 os << "queued" << std::endl;
 | |
|                 os_l.unlock();
 | |
|             }
 | |
|         }
 | |
|         os_l.lock();
 | |
|         os << "p ready to join" << std::endl;
 | |
|         os_l.unlock();
 | |
|     }
 | |
| };
 | |
| 
 | |
| void produce_thread(task_queue_ptr task_queue){
 | |
|     Producent p(task_queue);
 | |
|     p.fill_queue();
 | |
| }
 | |
| 
 | |
| //############################################################ WORKER THREAD
 | |
| 
 | |
| class Consument {
 | |
| private:
 | |
|     task_queue_ptr task_queue;
 | |
| public:
 | |
|     Consument(task_queue_ptr tq): task_queue(tq){ active_consuments++; }
 | |
|     Consument(const Consument&) = delete;
 | |
|     ~Consument() { active_consuments--; }
 | |
| 
 | |
|     Task get_task(){ // might be redundant
 | |
|         os_l.lock();
 | |
|         os << "processing" << std::endl;
 | |
|         os_l.unlock();
 | |
|         return task_queue->pop();
 | |
|     }
 | |
| 
 | |
|     void work(){
 | |
|         while(active_producents || ! task_queue->is_empty()){
 | |
|             Task t = get_task();
 | |
|             t.solve_stupid();
 | |
|             submit_task(std::move(t.unwrap()));
 | |
|             os_l.lock();
 | |
|             os << t.solution() << std::endl;
 | |
|             os_l.unlock();
 | |
|         }
 | |
|         os_l.lock();
 | |
|         os << "c ready to join" << std::endl;
 | |
|         os_l.unlock();
 | |
|     }
 | |
| };
 | |
| 
 | |
| void consume_thread(task_queue_ptr task_queue){
 | |
|     Consument c(task_queue);
 | |
|     c.work();
 | |
| }
 | |
| */
 | |
| //############################################################ TRIANGULATION
 | |
| 
 | |
| struct Line{
 | |
|     LP_Point a;
 | |
|     LP_Point b;
 | |
|     double length;
 | |
| 
 | |
|     Line() = delete;
 | |
|     Line(LP_Point _a, LP_Point _b): a(_a), b(_b){
 | |
|         LP_Point vec_ba;
 | |
|         vec_ba.x = b.x - a.x;
 | |
|         vec_ba.y = b.y - a.y;
 | |
|         length = sqrt(vec_ba.x*vec_ba.x + vec_ba.y*vec_ba.y);
 | |
|     }
 | |
|     Line(Line& l): a(l.a), b(l.b), length(l.length){}
 | |
| };
 | |
| 
 | |
| double Task::triangulate_basic(LP_Polygon* p){
 | |
|     size_t poly_size = p->points.size();
 | |
| 
 | |
|     if(poly_size == 3) return 0.;
 | |
|     if(poly_size == 4){
 | |
|         Line cut1(p->points.at( 0 ),
 | |
|                   p->points.at( 2 ));
 | |
|         Line cut2(p->points.at( 1 ),
 | |
|                   p->points.at( 3 ));
 | |
|         return std::min(cut1.length, cut2.length);
 | |
|     }
 | |
| 
 | |
|     double triangulation = INFINITY;
 | |
|     double min_triangulation = INFINITY;
 | |
| 
 | |
|     for (size_t point_idx = 0; point_idx < poly_size; point_idx++){
 | |
|         Line cut(p->points.at( (point_idx - 1) % poly_size ),
 | |
|                  p->points.at( (point_idx + 1) % poly_size ));
 | |
| 
 | |
|         std::vector<LP_Point> smaller_poly;
 | |
|         for(size_t i = 0; i < poly_size; i++){
 | |
|             if(i != point_idx) smaller_poly.push_back(p->points.at(i));
 | |
|         }
 | |
| 
 | |
|         LP_Polygon s_p(std::move(smaller_poly));
 | |
|         triangulation = triangulate_basic(&s_p) + cut.length;
 | |
|         if(triangulation < min_triangulation) min_triangulation = triangulation;
 | |
|     }
 | |
| 
 | |
|     return min_triangulation;
 | |
| 
 | |
| }
 | |
| 
 | |
| //########################### attempt of thought
 | |
| 
 | |
| // build a list (array?) of all cut lengths ... n
 | |
| // build a list of "quatrogones"-> pentagones -> hexagones -> ....; each of them carries its min_triangulation
 | |
| // end up with our polygone already w min triang.
 | |
| // not really better i guess...
 | |
| 
 | |
| //########################### dynamic something
 | |
| 
 | |
| //use std::map to store triangulations of polygons
 | |
| 
 | |
| double Task::triangulate(){
 | |
|     std::map<int, double> m;
 | |
|     std::vector<bool> poly_key(task->p.points.size(), true);
 | |
|     return triangulate_subpolys(poly_key, &m); 
 | |
|     // 
 | |
|     // return triangulate_subpolys_but_better();
 | |
| }
 | |
| 
 | |
| int vec_to_int(std::vector<bool>* vec){
 | |
|     int res = 0;
 | |
|     for (size_t i = 0; i < vec->size(); i++){
 | |
|         res += vec->at(i) * 2^i;
 | |
|     }
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| std::vector<bool> Task::create_key(std::vector<int>* indices){
 | |
| 
 | |
|     size_t key_length = task->p.points.size();
 | |
|     std::vector<bool> key(key_length, false);
 | |
| 
 | |
|     for(size_t i = 0; i < indices->size(); i++){
 | |
|         key[indices->at(i)] = true;
 | |
|     }
 | |
|     return key;
 | |
| }
 | |
| 
 | |
| double Task::triangulate_subpolys(std::vector<bool> poly_key, std::map<int, double>* m){
 | |
|     // convert p to int
 | |
|     int key = vec_to_int(&poly_key);
 | |
| 
 | |
|     // try to find in map
 | |
|     //     success -> return mapped value
 | |
|     if (m->count(key)) return m->at(key); // ! contains() is c++20
 | |
| 
 | |
|     //     failure -> create poly from key
 | |
|     std::vector<LP_Point> curr_points;
 | |
|     std::vector<int> curr_indices;
 | |
|     for(size_t i = 0; i < task->p.points.size(); i++){
 | |
|         if(poly_key.at(i)){
 | |
|             curr_points.push_back(task->p.points.at(i));
 | |
|             curr_indices.push_back(i);
 | |
|         }
 | |
|     }
 | |
|     LP_Polygon poly(std::move(curr_points));
 | |
| 
 | |
|     //                use stupid triangulation but create poly_key instead of small_poly
 | |
|     //                save value in map before any return
 | |
| 
 | |
|     size_t poly_size = poly.points.size();
 | |
|     if(poly_size == 3){
 | |
|         (*m)[key] = 0.;
 | |
|         return 0.;
 | |
|     }
 | |
| 
 | |
|     double triangulation;
 | |
|     double min_triangulation = INFINITY;
 | |
| 
 | |
|     for (size_t point_idx = 0; point_idx < poly_size; point_idx++){
 | |
|         Line cut(poly.points.at( (point_idx - 1) % poly_size ),
 | |
|                  poly.points.at( (point_idx + 1) % poly_size ));
 | |
| 
 | |
|         std::vector<int> sub_indices = curr_indices;
 | |
|         sub_indices.erase(sub_indices.begin() + point_idx);
 | |
| 
 | |
|         triangulation = triangulate_subpolys( create_key( &sub_indices ), m )
 | |
|                         + cut.length;
 | |
| 
 | |
|         if(triangulation < min_triangulation) min_triangulation = triangulation;
 | |
|     }
 | |
| 
 | |
|     (*m)[key] = min_triangulation;
 | |
| 
 | |
|     //                return found value
 | |
|     return min_triangulation;
 | |
| }
 | |
| 
 | |
| //########################### dynamic something but better
 | |
| 
 | |
| 
 | |
| //############################################################ TRIANGULATION TEST
 | |
| 
 | |
| void task_test(){
 | |
|     std::vector< LP_Point > v1 = {{0,0}, {1,1}, {3,1}, {2,0}};
 | |
|     std::vector< LP_Point > v2 = {{0,0}, {0,1}, {1,2}, {2,1}, {2,0}};
 | |
|     std::vector< LP_Point > v3 = {{0,0}, {1,1}, {2,2}, {3,1}, {2,0}, {1,-1}};
 | |
| 
 | |
|     LP_Polygon p1(std::move(v1));
 | |
|     LP_Polygon p2(std::move(v2));
 | |
|     LP_Polygon p3(std::move(v3));
 | |
| 
 | |
|     Temp_Task_p tp1 = std::make_shared<Temp_Task>(std::move(p1));
 | |
|     Temp_Task_p tp2 = std::make_shared<Temp_Task>(std::move(p2));
 | |
|     Temp_Task_p tp3 = std::make_shared<Temp_Task>(std::move(p3));
 | |
| 
 | |
|     Task t1(std::move(tp1));
 | |
|     Task t2(std::move(tp2));
 | |
|     Task t3(std::move(tp3));
 | |
| 
 | |
|     t1.solve_stupid();
 | |
|     t2.solve_stupid();
 | |
|     t3.solve_stupid();
 | |
| 
 | |
|     std::cout << "4 vertices:\ncorrect:   calculated:\n" << "1.414      " << t1.solution() << std::endl;
 | |
|     std::cout << "5 vertices:\ncorrect:   calculated:\n" << "4.236      " << t2.solution() << std::endl;
 | |
|     std::cout << "6 vertices:\ncorrect:   calculated:\n" << "5.414      " << t1.solution() << std::endl << std::endl;
 | |
| 
 | |
|     t1.solve_less_stupid();
 | |
|     t2.solve_less_stupid();
 | |
|     t3.solve_less_stupid();
 | |
| 
 | |
|     std::cout << "SECOND VERSION:\n\n";
 | |
| 
 | |
|     std::cout << "4 vertices:\ncorrect:   calculated:\n" << "1.414      " << t1.solution() << std::endl;
 | |
|     std::cout << "5 vertices:\ncorrect:   calculated:\n" << "4.236      " << t2.solution() << std::endl;
 | |
|     std::cout << "6 vertices:\ncorrect:   calculated:\n" << "5.414      " << t1.solution() << std::endl << std::endl;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //############################################################ MAIN
 | |
| 
 | |
| int main(){
 | |
| 
 | |
|     //############################### MULTI THREAD
 | |
| 
 | |
|     // active_producents = active_consuments = 0;
 | |
| 
 | |
|     // task_queue_ptr queue_ptr = std::make_shared<Queue>();
 | |
|     // std::vector<std::thread> threads;
 | |
| 
 | |
|     // for(unsigned int i = 0; i < NUM_PRODUCENTS; i++){
 | |
|     //     threads.emplace_back(produce_thread, queue_ptr);
 | |
|     // }
 | |
| 
 | |
|     // for(unsigned int i = 0; i < NUM_WORKERS; i++){
 | |
|     //     threads.emplace_back(consume_thread, queue_ptr);
 | |
|     // }
 | |
| 
 | |
|     // for(auto& t : threads){
 | |
|     //     t.join();
 | |
|     //     os_l.lock();
 | |
|     //     os << "joined" << std::endl;
 | |
|     //     os_l.unlock();
 | |
|     // }
 | |
| 
 | |
|     //############################### SINGLE THREAD
 | |
| 
 | |
|     // while(1){
 | |
|     //     LP_Task_p tp = pickup_task();
 | |
|     //     if(!tp) break;
 | |
|     //     Task t(std::move(tp));
 | |
|     //     t.solve_stupid();
 | |
|     //     submit_task(std::move(t.unwrap()));
 | |
|     // }
 | |
| 
 | |
|     //############################### CONNECTION TEST
 | |
| 
 | |
|     // test();
 | |
| 
 | |
|     //############################### TRIANGULATION TEST
 | |
|     task_test();
 | |
| } |