Advertisement
Guest User

Untitled

a guest
May 23rd, 2019
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.30 KB | None | 0 0
  1. //
  2. // Created by Saxion on 10/12/2018.
  3. //
  4.  
  5. #ifndef ALGOS_ALGOS_H
  6. #define ALGOS_ALGOS_H
  7.  
  8. #include <algorithm>
  9. #include <numeric>
  10. #include <random>
  11. #include <vector>
  12. #include "task.h"
  13.  
  14. namespace saxion {
  15. struct algos {
  16.  
  17. template<typename _Iter>
  18. auto has_all_tasks_assigned(_Iter begin, _Iter end) const noexcept {
  19. return std::all_of(begin, end, [](const task &t) {
  20. return t.assignees.size();
  21. });
  22. // returns true if all the tasks in collection have a person assigned to them
  23. }
  24.  
  25. // 1 point
  26. template<typename _Iter>
  27. bool has_task_with_deadline_afer(_Iter begin, _Iter end, const task::time_type &deadline) const noexcept {
  28. // returns true if any of the tasks in collection have a deadline after <deadline>
  29. return std::any_of(begin, end, [deadline](task &t) {
  30. return deadline< t.deadline;
  31. }
  32. );
  33. }
  34.  
  35. // 3 points
  36. template<typename _Iter>
  37. auto remove_asignee_from_all(_Iter begin, _Iter end, const std::string &person) const noexcept {
  38.  
  39. std::for_each(begin, end, [person](task& t){
  40. t.assignees.erase(person);
  41. });
  42.  
  43. // transforms the tasks (in-place) by removing <person> from the assignees in all the tasks
  44. }
  45.  
  46. // 1 point
  47. template<typename _Iter>
  48. auto extend_deadlines(_Iter begin, _Iter end, int priority,const task::time_difference_type &extension) const noexcept {
  49.  
  50.  
  51. std::for_each(begin, end, [priority, extension](task& t){
  52. if(t.priority == priority){
  53. t.deadline += extension;
  54. }
  55. });
  56. // transforms the tasks with priority <prio> (in-place) by extending their deadlines with <extension>
  57. }
  58.  
  59. // 1 point
  60. template<typename _Iter>
  61. auto count_tasks_with_deadlines_before(_Iter begin, _Iter end, const task::time_type &deadline) const noexcept {
  62. return std::count_if(begin, end, [deadline](const task &t) {
  63. return t.deadline < deadline;
  64. });
  65. }
  66.  
  67. // 2 points
  68. template<typename _Iter>
  69. auto add_assignee_to_task(_Iter begin, _Iter end, int id, std::string person) const noexcept {
  70. return std::any_of(begin, end, [id, person](task &t) {
  71. if (t.id == id && !(t.assignees.find(person) != t.assignees.end())) {
  72. t.assignees.insert(person);
  73. return true;
  74. }
  75. return false;
  76. });
  77.  
  78. // adds <person> to assignees of the task with id <id>
  79. // returns false if such a task doesn't exist or if it already has <person> assigned to it
  80. // otherwise returns true
  81.  
  82. }
  83.  
  84. // 1 point
  85. template<typename _Iter>
  86. std::vector<task> get_tasks_with_priority(_Iter begin, _Iter end, int priority) const noexcept {
  87. std::vector<task> result;
  88. std::for_each(begin, end, [priority, &result](task &t) {
  89. if (t.priority == priority) {
  90. result.push_back(t);
  91. }
  92. });
  93. // returns a vector with copies of tasks with priority <priority>
  94. return result;
  95. }
  96.  
  97. // 2 points move_if ;)
  98. template<typename _Iter, typename _OutIter>
  99. _Iter extract_tasks_with_deadline_before(_Iter begin, _Iter end, _OutIter out, const task::time_type& deadline) const noexcept{
  100.  
  101. (void)begin; (void)end; (void)out; (void)deadline;
  102.  
  103. // moves the tasks with deadlines before <deadline> to the container "pointed by" the <out> iterator (see test code for what it is)
  104. // the tasks that are on or after the <deadline> should stay in the *beginning* of the original container
  105. // the returned iterator should point to the 'new end' of the range in the original container
  106.  
  107. /* Simplified example:
  108. * given an input container with integers: [6, 3, 7, 4, 5, 1]
  109. * move the numbers before number {5} to another container and return the new 'end' iterator to the original container.
  110. *
  111. * After moving numbers 'before {5}' the output container will have elements: [3, 4, 1],
  112. * while the original container will look like this: [6, 7, 5, _, _, _]
  113. * Notice that there are three empty slots at the end of the container and all the number >= 5 have been moved to the beginning.
  114. * The function should return the iterator to the 'new end' of the original container, which is the first empty slot.
  115. */
  116. return end;
  117. }
  118.  
  119. using id_prio = std::tuple<int, int>;
  120.  
  121. // 2 points
  122. template<typename _Iter>
  123. std::vector<id_prio> list_sorted_by_prio(_Iter begin, _Iter end) const noexcept {
  124. std::vector<id_prio> result;
  125.  
  126. std::for_each(begin, end, [&result](task& t){
  127. auto temp = std::tuple(t.id,t.priority);
  128. result.insert(result.begin(),temp);
  129. });
  130.  
  131. std::sort (result.begin(), result.end(), [](std::tuple<int, int> i, std::tuple<int, int> j){
  132. if(std::get<1>(i) == std::get<1>(j)){
  133. return std::get<0>(i) < std::get<0>(j);
  134. } else {
  135. return std::get<1>(i) < std::get<1>(j);
  136. }
  137. });
  138.  
  139. // returns a vector of pairs <id, priority> of all the tasks. The returned vector must be sorted by priority.
  140. // If two tasks have the same priority, they are sorted by id (lower id comes first)
  141. return result;
  142. }
  143.  
  144. // 1 point
  145. template<typename _Cont>
  146. auto remove_all_finished(_Cont &container) const noexcept {
  147.  
  148. auto now = std::chrono::system_clock::now();
  149.  
  150. return container.erase(std::remove_if(container.begin(),container.end(), [&now](task& t){
  151. return t.deadline < now;
  152. }), container.end());
  153.  
  154. // removes all the tasks with deadline before or on the time point now() obtained from the system_clock
  155. // notice that this function takes the whole container as an argument, that's because it's impossible to remove elements using just the iterators.
  156. }
  157.  
  158. // 1 point
  159. template<typename _Iter>
  160. task &get_nth_to_complete(_Iter begin, _Iter end, int n) const noexcept {
  161. std::nth_element(begin, begin + n, end, [](const task &low, const task &high) {
  162. if (low.deadline == high.deadline) {
  163. return low.priority < high.priority;
  164. } else return low.deadline < high.deadline;
  165. });
  166. return *(begin + n);
  167. // returns a reference to the n-th task to be completed in order of deadlines.
  168. // deadline ties are resolved by comparing priorities (lower priorities come first)
  169. }
  170.  
  171. // 1 point
  172. template<typename _Iter>
  173. std::vector<task> get_first_n_to_complete(_Iter begin, _Iter end, int n) const noexcept {
  174.  
  175. std::vector<task> result;
  176. std::sort(begin, end, [](task &t, task &r) {
  177. if (t.deadline == r.deadline) {
  178. return t.priority < r.priority;
  179. } else return t.deadline < r.deadline;
  180. });
  181. std::copy_n(begin, n, std::back_inserter(result));
  182. return result;
  183.  
  184. }
  185.  
  186. // 3 points
  187. template<typename _Iter, typename _OIter>
  188. void cost_burndown(_Iter begin, _Iter end, _OIter obegin) const noexcept {
  189. using time_type = std::chrono::time_point<std::chrono::system_clock>;
  190. std::map<time_type, double> deadlines;
  191. double cumulative(0.0);
  192.  
  193. std::for_each(begin, end, [&deadlines](const task &t) {
  194. deadlines[t.deadline] += t.cost;
  195. });
  196.  
  197. std::transform(deadlines.begin(), deadlines.end(), obegin,
  198. [&cumulative](std::pair<time_type, double> deadline) {
  199. cumulative = cumulative + deadline.second;
  200. return cumulative;
  201. });
  202. // you can assume that _OIter is a std::back_insert_iterator to a container of double
  203.  
  204. // calculates the cost burndown of the tasks and writes the output to the output iterator <obegin>
  205. // the cost burndown is defined as cumulative sum of the tasks' costs sorted by deadlines
  206. // tasks with the same deadline contribute one data point (sum of their costs) to the burndown
  207.  
  208. /* Simplified example
  209. * Assume that we have a container with 5 tasks, where each task has a deadline and a cost associated with it:
  210. * [ {4, 43.0}, {2, 11.0}, {3, 7.0}, {1, 23.0}, {3, 19.0} ], here the first number in a pair is the deadline and the second the cost
  211. * The first task to complete is the 4th task (deadline 1) with associated cost of 23.0
  212. * The 2nd task to complete is the 2nd task (deadline 2) with associated cost of 11.0
  213. * The 3rd tasks to complete are the 3rd and the 5th tasks (deadline 3) with associated costs of 7.0 + 19.0 = 26.0
  214. * The 4th and last task to complete is the 1st task (deadline 4) with associated cost of 43.0
  215. *
  216. * Therefore the cost burndown (cumulative cost) is: [23.0, 34.0, 60.0, 103.0].
  217. * Those numbers in this order must be outputted to the obegin iterator.
  218. */
  219. }
  220.  
  221.  
  222. // 1 point
  223. template<typename _Iter>
  224. std::pair<task, task> cheapest_and_most_expensive(_Iter begin, _Iter end) const noexcept {
  225.  
  226. std::pair<task, task> result;
  227. task max;
  228. task min;
  229.  
  230. max.cost = 0;
  231. min.cost = INT_MAX;
  232. std::for_each(begin, end, [&min, &max](task &t) {
  233. if (t.cost < min.cost) {
  234. min = t;
  235. }
  236. if (t.cost > max.cost) {
  237. max = t;
  238. }
  239. });
  240. return {min, max};
  241. // returns a pair consisting of the least and the most expensive tasks in the collection
  242. //return {task(), task()};
  243. }
  244.  
  245. // 1 point
  246. template<typename _Iter>
  247. auto total_cost(_Iter begin, _Iter end) const noexcept {
  248. double total = 0;
  249. std::for_each(begin, end, [&total](const task& t){
  250. total += t.cost;
  251. });
  252. // returns the total cost of all the tasks in the collection
  253. return total;
  254. }
  255.  
  256. // 2 points
  257. template<typename _Iter>
  258. double total_cost_of(_Iter begin, _Iter end, const std::string &assignee) const noexcept {
  259.  
  260. return std::accumulate(begin, end, 0.0, [assignee](double accumulator, task &t) {
  261. bool found = (std::find(t.assignees.begin(), t.assignees.end(), assignee) != t.assignees.end());
  262. if (found) {
  263. return accumulator + t.cost;
  264. } else {
  265. return accumulator;
  266. }
  267. });
  268. // returns the cost of all the tasks that have <assignee> assigned to them
  269. }
  270.  
  271. // 1 point
  272. template<typename _Iter>
  273. _Iter separate_by_deadline(_Iter begin, _Iter end, const task::time_type &deadline) const noexcept {
  274. auto place = std::count_if(begin, end, [deadline, begin, end](task &t) {
  275. std::sort(begin, end, [](task &t, task &r) {
  276. return t.deadline < r.deadline;
  277. });
  278. return t.deadline < deadline;
  279. });
  280. // reorders the tasks in such a way that all tasks with deadlines before <deadline> precede the tasks with deadline on or after <deadline>
  281. // returns the iterator to the last task in the first group (with deadlines before <deadline>)
  282. return (begin + (place - 1));
  283. }
  284.  
  285. // 3 points
  286. template<typename _Iter>
  287. double estimate_workload(_Iter begin, _Iter end, const std::string &person) const {
  288. std::vector<task> sample;
  289. std::sample(begin, end, std::back_inserter(sample), std::distance(begin, end) / 2,
  290. std::mt19937{std::random_device{}()});
  291. return std::count_if(sample.begin(), sample.end(), [person](const task &task1) {
  292. return task1.assignees.find(person) != task1.assignees.end();
  293. }) / sample.size();
  294. // estimates the workload of a <person>
  295. // the estimation is done as follows:
  296. // - out of all the tasks, half of them (n_s) are chosen at random (sampled)
  297. // - for the selected tasks a check is done, whether the <person> belongs to the task's assignees
  298. // based on the number of tasks that checked positive (count) and the total number of sampled tasks (n_s) the estimated workload is calculated as:
  299. // count / n_s
  300.  
  301. /* Simplified example:
  302. * There are 8 tasks and "zack" is assigned to tasks [2, 3, 6].
  303. * We can construct a truth table of all tasks like this: [0, 0, 1, 1, 0, 0, 1, 0]
  304. * The true workload of "zack" is 3/8=0.375
  305. *
  306. * Let's say for the estimate we sampled tasks: 0, 2, 4, 6. For those sampled tasks "zack" is assigned 2 two times,
  307. * consequently the estimated workload is 2/4 = 0.5
  308. *
  309. * Let's now say that we randomly sampled tasks 1, 4, 6, 7. For those tasks "zack" appears only once,
  310. * therefore the estimated workload is 1/4 = 0.25
  311. *
  312. * Notice that for our example it is possible to estimate a workload between 0.00 & 0.75
  313. */
  314.  
  315. //return -1.0;
  316. }
  317.  
  318.  
  319. struct averageaccumulator_t {
  320. double sum;
  321. size_t n;
  322.  
  323. double GetAverage() const { return ((double) sum) / n; }
  324. };
  325.  
  326. // 2 points
  327. template<typename _Iter>
  328. auto average_cost_of_prio(_Iter begin, _Iter end, int priority) const noexcept {
  329.  
  330.  
  331. auto func_acc_avg = [priority](averageaccumulator_t averageaccumulator, task &t) {
  332. if (t.priority == priority) {
  333. return averageaccumulator_t({
  334. averageaccumulator.sum + t.cost, averageaccumulator.n + 1});
  335. } else {
  336. return averageaccumulator_t({
  337. averageaccumulator.sum + 0.0, averageaccumulator.n + 0});
  338. }
  339. };
  340. averageaccumulator_t accumulated = std::accumulate(begin, end, averageaccumulator_t({0.0, 0}),
  341. func_acc_avg);
  342. // calculates and returns the average cost of tasks with priority <priority>
  343. return accumulated.GetAverage();
  344. }
  345. };
  346. }
  347. #endif //ALGOS_ALGOS_H
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement