diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c23a76e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,46 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Docker C++ Debug", + "type": "cppdbg", + "request": "launch", + "program": "/app/a.out", + "args": [], + "stopAtEntry": true, + "cwd": "/app", + "environment": [], + "externalConsole": false, + "pipeTransport": { + "debuggerPath": "/usr/bin/gdb", + "pipeProgram": "ssh", + "pipeArgs": [ + "root@localhost", + "-p", "2222", + "-i", "${workspaceFolder}/key", + "-o", "StrictHostKeychecking=no", + "/usr/bin/gdb --interpreter=mi" + ] + }, + "sourceFileMap": { + "/app": "${workspaceFolder}" + }, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "skip libpoly", + "text": "skip -gfi libpoly.so", + "ignoreFailures": false + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a9e34ab --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,55 @@ +{ + "files.associations": { + "condition_variable": "cpp", + "thread": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp", + "map": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..4744023 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,32 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++ build active file", + "command": "/usr/bin/g++-14", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}", + "-Wall", + "-pedantic", + "-pthread", + "-std=c++20" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Task generated by Debugger." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a91a01e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM gcc:latest + +COPY ./ /app + +WORKDIR /app + +RUN apt update && apt install -y gdb gdbserver openssh-server && \ + apt clean + +RUN make a.out && echo 'yeey' + +RUN mv key.pub /root/.ssh/authorized_keys && \ + mkdir /var/run/sshd + +EXPOSE 22 + +CMD ["/usr/sbin/sshd", "-D"] + + +# CMD ["sleep", "infinity"] + +# CMD ["/app/a.out"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..583566c --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +a.out: triangulation.cpp + g++ -Wl,-rpath=. triangulation.cpp -g -Wall -pedantic -pthread -lpoly -L./ -std=c++20 \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..4625a5d --- /dev/null +++ b/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash +if [ ! -f key ] || [ ! -f key.pub ]; then + rm -f key key.pub && \ + ssh-keygen -t ed25519 -N "" -f key +fi +docker build -t cpp20 . \ No newline at end of file diff --git a/kill.sh b/kill.sh new file mode 100755 index 0000000..8300ff8 --- /dev/null +++ b/kill.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker ps --filter name=triangulation --format "{{.ID}}"| xargs -L1 docker kill \ No newline at end of file diff --git a/libpoly.h b/libpoly.h new file mode 100644 index 0000000..220cd7f --- /dev/null +++ b/libpoly.h @@ -0,0 +1,44 @@ +#ifndef libpoly092986127876186578684563243 +#define libpoly092986127876186578684563243 + +#include +#include +#include + +void test(); // prints to stdout to test linking + +struct LP_Point { + double x, y; + auto operator<=>(const LP_Point&) const = default; +}; + +struct LP_Polygon { + std::vector< LP_Point > points; + LP_Polygon(std::vector< LP_Point >&& p) : points(p) {} + LP_Polygon() {} +}; + +class LP_Task : public std::enable_shared_from_this< LP_Task > { +struct Private{ explicit Private() = default; }; + +public: + LP_Task(Private) {} + static std::shared_ptr create() { + return std::make_shared(Private()); + } + + std::shared_ptr getptr() { + return shared_from_this(); + } + LP_Task(LP_Polygon&& _p): p(_p), minimal_triangulation(MAXFLOAT){}; + + LP_Polygon p; + double minimal_triangulation; +}; + +using LP_Task_p = std::shared_ptr< LP_Task >; + +LP_Task_p pickup_task(); +bool submit_task(LP_Task_p&&); + +#endif // libpoly092986127876186578684563243 \ No newline at end of file diff --git a/libpoly.so b/libpoly.so new file mode 100644 index 0000000..610d8fc Binary files /dev/null and b/libpoly.so differ diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..7af3e8e --- /dev/null +++ b/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -d --name triangulation -p 2222:22 -p 7777:7777 cpp20 diff --git a/triangulation.cpp b/triangulation.cpp index ce62c73..0513059 100644 --- a/triangulation.cpp +++ b/triangulation.cpp @@ -21,21 +21,19 @@ std::condition_variable can_push; std::atomic_uint32_t active_producents; std::atomic_uint32_t active_consuments; -std::atomic_bool tasks_incoming; std::ostream& os = std::cout; std::mutex os_l; //############################# MODIFY HERE -constexpr unsigned NUM_PRODUCENTS = 1; -constexpr unsigned NUM_WORKERS = 3; +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){} }; @@ -45,9 +43,10 @@ class Task { private: Temp_Task_p task; - double triangulate(LP_Polygon* p); + double triangulate_basic(LP_Polygon* p); double triangulate(); double triangulate_subpolys(std::vector poly_key, std::map* m); + std::vector create_key(std::vector* indices); public: Task(): task(nullptr){}; @@ -56,13 +55,20 @@ public: t.task.reset(); } Task(Temp_Task_p&& tp): task(tp){} - void solve_stupid(){ - task->minimal_triangulation = triangulate(&(task->p)); + + 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); } - double const solution(){ return task->minimal_triangulation; } }; class Queue{ @@ -100,7 +106,7 @@ public: using task_queue_ptr = std::shared_ptr; //############################################################ PRODUCE THREAD - +/* class Producent{ private: task_queue_ptr task_queue; @@ -111,30 +117,41 @@ public: 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(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; + // std::vector< LP_Point > points; + // srand(static_cast(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(std::move( 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(std::move( p )); return Task(std::move(tp)); } void fill_queue(){ - while(tasks_incoming){ - //Task t = get_task(); - - task_queue->push(get_task()); + 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(); } }; @@ -154,6 +171,9 @@ public: ~Consument() { active_consuments--; } Task get_task(){ // might be redundant + os_l.lock(); + os << "processing" << std::endl; + os_l.unlock(); return task_queue->pop(); } @@ -161,11 +181,14 @@ public: while(active_producents || ! task_queue->is_empty()){ Task t = get_task(); t.solve_stupid(); - //submit_task(std::move(t.unwrap())); + 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(); } }; @@ -173,7 +196,7 @@ void consume_thread(task_queue_ptr task_queue){ Consument c(task_queue); c.work(); } - +*/ //############################################################ TRIANGULATION struct Line{ @@ -191,12 +214,19 @@ struct Line{ Line(Line& l): a(l.a), b(l.b), length(l.length){} }; -double Task::triangulate(LP_Polygon* p){ +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; + double triangulation = INFINITY; double min_triangulation = INFINITY; for (size_t point_idx = 0; point_idx < poly_size; point_idx++){ @@ -209,24 +239,31 @@ double Task::triangulate(LP_Polygon* p){ } LP_Polygon s_p(std::move(smaller_poly)); - triangulation = triangulate(&s_p) + cut.length; + triangulation = triangulate_basic(&s_p) + cut.length; if(triangulation < min_triangulation) min_triangulation = triangulation; } return min_triangulation; } -//############################### dynamic something + +//########################### 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 -//KEY CREATION: - // take relative positions of points in polygon, add them as vectors and do something with the amount of them - // maybe num * vx + num^2 * vy double Task::triangulate(){ std::map m; - std::vector poly_key; - return triangulate_subpolys(poly_key, &m); + std::vector poly_key(task->p.points.size(), true); + return triangulate_subpolys(poly_key, &m); + // + // return triangulate_subpolys_but_better(); } int vec_to_int(std::vector* vec){ @@ -237,46 +274,150 @@ int vec_to_int(std::vector* vec){ return res; } +std::vector Task::create_key(std::vector* indices){ + + size_t key_length = task->p.points.size(); + std::vector 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 poly_key, std::map* m){ // convert p to int + int key = vec_to_int(&poly_key); + // try to find in map // success -> return mapped value - // failure -> compute triangulation - // save value in map + if (m->count(key)) return m->at(key); // ! contains() is c++20 + + // failure -> create poly from key + std::vector curr_points; + std::vector 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 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 - // COMPUTE TRIANGULATION - // create polygon poly from p - // use stupid triangulation but create poly_key instead of small_poly - - return 0.; - - + 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(std::move(p1)); + Temp_Task_p tp2 = std::make_shared(std::move(p2)); + Temp_Task_p tp3 = std::make_shared(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(){ - active_producents = active_consuments = 0; - tasks_incoming = true; - task_queue_ptr queue_ptr = std::make_shared(); - std::vector threads; + //############################### MULTI THREAD - for(unsigned int i = 0; i < NUM_PRODUCENTS; i++){ - threads.emplace_back(produce_thread, queue_ptr); - } + // active_producents = active_consuments = 0; - for(unsigned int i = 0; i < NUM_WORKERS; i++){ - threads.emplace_back(consume_thread, queue_ptr); - } + // task_queue_ptr queue_ptr = std::make_shared(); + // std::vector threads; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - tasks_incoming = false; - for(auto& t : threads){ - t.join(); - os_l.lock(); - os << "joined" << std::endl; - os_l.unlock(); - } - //test(); + // 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(); } \ No newline at end of file