All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Pages
scheduling_jobs.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //=======================================================================
15 #ifndef PAAL_SCHEDULING_JOBS_HPP
16 #define PAAL_SCHEDULING_JOBS_HPP
17 
18 #define BOOST_RESULT_OF_USE_DECLTYPE
19 
21 #include "paal/utils/functors.hpp"
23 #include "paal/utils/irange.hpp"
25 
26 #include <boost/range/algorithm/copy.hpp>
27 #include <boost/range/algorithm/sort.hpp>
28 #include <boost/range/counting_range.hpp>
29 #include <boost/range/iterator_range.hpp>
30 #include <boost/range/numeric.hpp>
31 
32 #include <algorithm>
33 #include <cassert>
34 #include <iterator>
35 #include <numeric>
36 #include <random>
37 #include <utility>
38 #include <vector>
39 
40 namespace paal {
41 namespace greedy {
42 
43 namespace detail {
44 
45 template <class MachineIterator, class JobIterator, class GetSpeed,
46  class GetLoad>
47 struct sched_traits {
48  typedef typename std::iterator_traits<MachineIterator>::reference
49  machine_reference;
50  typedef typename std::iterator_traits<JobIterator>::reference job_reference;
54 };
55 
56 template <class MachineIterator, class JobIterator, class GetSpeed,
57  class GetLoad, class Traits = sched_traits<
58  MachineIterator, JobIterator, GetSpeed, GetLoad>>
59 typename Traits::frac_t calculate_bound(const MachineIterator mfirst,
60  const MachineIterator mlast,
61  const JobIterator jfirst,
62  const JobIterator jlast,
63  GetSpeed get_speed, GetLoad get_load) {
64  typedef typename Traits::speed_t Speed;
65  typedef typename Traits::load_t Load;
66  typedef typename Traits::frac_t Frac;
67 
68  auto jobs_num = jlast - jfirst;
69  auto machines_num = mlast - mfirst;
70 
71  std::vector<Speed> speed_sum(machines_num);
72  std::transform(mfirst, mlast, speed_sum.begin(), get_speed);
73  boost::partial_sum(speed_sum, speed_sum.begin());
74 
75  std::vector<Load> load_sum(jobs_num);
76  std::transform(jfirst, jlast, load_sum.begin(), get_load);
77  boost::partial_sum(load_sum, load_sum.begin());
78 
79  typedef decltype(machines_num) MachinesNumType;
80  assert(jobs_num > 0 && machines_num > 0);
81  Frac result(get_load(*jfirst), get_speed(*mfirst));
82  for (auto jobID : irange(jobs_num)) {
83  Load load = get_load(jfirst[jobID]);
84  auto get_single = [ = ](MachinesNumType i) {
85  return Frac(load, get_speed(mfirst[i]));
86  };
87  auto get_summed = [&](MachinesNumType i) {
88  return Frac(load_sum[jobID], speed_sum[i]);
89  };
90  auto condition = [ = ](MachinesNumType i) {
91  return get_summed(i) >= get_single(i);
92  };
93  auto machines_ids = boost::counting_range(
94  static_cast<MachinesNumType>(0), machines_num);
95  // current range based version in boost is broken
96  // should be replaced when released
97  // https://github.com/boostorg/algorithm/pull/4
98  auto it = std::partition_point(machines_ids.begin(), machines_ids.end(),
99  condition);
100  MachinesNumType machineID =
101  (it != machines_ids.end()) ? *it : machines_num - 1;
102  auto getMax = [ = ](MachinesNumType i) {
103  return std::max(get_single(i), get_summed(i));
104  };
105 
106  Frac candidate = getMax(machineID);
107  if (machineID != 0) {
108  assign_min(candidate, getMax(machineID - 1));
109  }
110  assign_max(result, candidate);
111  }
112  return result;
113 }
114 
115 template <class MachineIterator, class JobIterator, class OutputIterator,
116  class GetSpeed, class GetLoad, class RoundFun>
117 void schedule(MachineIterator mfirst, MachineIterator mlast, JobIterator jfirst,
118  JobIterator jlast, OutputIterator result, GetSpeed get_speed,
119  GetLoad get_load, RoundFun round) {
120  typedef sched_traits<MachineIterator, JobIterator, GetSpeed, GetLoad>
121  Traits;
122  typedef typename Traits::speed_t Speed;
123  typedef typename Traits::load_t Load;
124 
125  if (mfirst == mlast || jfirst == jlast) {
126  return;
127  }
128 
129  std::vector<MachineIterator> machines;
130  boost::copy(boost::counting_range(mfirst, mlast),
131  std::back_inserter(machines));
132  auto get_speed_from_iterator = utils::make_lift_iterator_functor(get_speed);
133  boost::sort(machines, utils::make_functor_to_comparator(
134  get_speed_from_iterator, utils::greater{}));
135 
136  std::vector<JobIterator> jobs;
137  boost::copy(boost::counting_range(jfirst, jlast), std::back_inserter(jobs));
138  auto get_load_from_iterator = utils::make_lift_iterator_functor(get_load);
139  boost::sort(jobs, utils::make_functor_to_comparator(get_load_from_iterator,
140  utils::greater{}));
141 
142  auto bound = detail::calculate_bound(
143  machines.begin(), machines.end(), jobs.begin(), jobs.end(),
144  get_speed_from_iterator, get_load_from_iterator);
145  Load bound_load = bound.num;
146  Speed bound_speed = bound.den;
147  Load current_load{};
148  auto emit = [&result](MachineIterator miter, JobIterator jiter) {
149  *result = std::make_pair(miter, jiter);
150  ++result;
151  };
152  auto job_iter = jobs.begin();
153  for (auto machine_iter = machines.begin(); machine_iter != machines.end();
154  ++machine_iter) {
155  auto &&machine = *(*machine_iter);
156  Speed speed = get_speed(machine);
157  while (job_iter != jobs.end()) {
158  auto &&job = *(*job_iter);
159  Load job_load = get_load(job) * bound_speed,
160  new_load = current_load + job_load;
161  assert(new_load <= bound_load * (2 * speed));
162  if (bound_load * speed < new_load) {
163  Load frac_load = bound_load * speed - current_load;
164  if (round(frac_load, job_load)) {
165  emit(*machine_iter, *job_iter);
166  } else {
167  auto next_machine_iter = std::next(machine_iter);
168  assert(next_machine_iter != machines.end());
169  emit(*next_machine_iter, *job_iter);
170  }
171  ++job_iter;
172  current_load = job_load - frac_load;
173  break;
174  }
175  emit(*machine_iter, *job_iter);
176  ++job_iter;
177  current_load = new_load;
178  }
179  }
180  assert(job_iter == jobs.end());
181 }
182 }
183 
184 /*
185  * @brief This is deterministic solve scheduling jobs on machines with different
186  * speeds problem and return schedule
187  *
188  * Example:
189  * \snippet scheduling_jobs_example.cpp Scheduling Jobs Example
190  *
191  * example file is scheduling_jobs_example.cpp
192  *
193  * @param mfirst
194  * @param mlast
195  * @param jfirst
196  * @param jlast
197  * @param result
198  * @param get_speed
199  * @param get_load
200  * @tparam MachineIterator
201  * @tparam JobIterator
202  * @tparam OutputIterator
203  * @tparam GetSpeed
204  * @tparam GetLoad
205  */
206 template <class MachineIterator, class JobIterator, class OutputIterator,
207  class GetSpeed, class GetLoad>
208 void schedule_deterministic(const MachineIterator mfirst,
209  const MachineIterator mlast,
210  const JobIterator jfirst, const JobIterator jlast,
211  OutputIterator result, GetSpeed get_speed,
212  GetLoad get_load) {
213  detail::schedule(mfirst, mlast, jfirst, jlast, result, get_speed, get_load,
215 }
216 
217 /*
218  * @brief This is randomized solve scheduling jobs on machines with different
219  * speeds problem and return schedule.
220  *
221  * Example:
222  * \snippet scheduling_jobs_example.cpp Scheduling Jobs Example
223  *
224  * example file is scheduling_jobs_example.cpp
225  *
226  * @param mfirst
227  * @param mlast
228  * @param jfirst
229  * @param jlast
230  * @param result
231  * @param get_speed
232  * @param get_load
233  * @param gen
234  * @tparam MachineIterator
235  * @tparam JobIterator
236  * @tparam OutputIterator
237  * @tparam GetSpeed
238  * @tparam GetLoad
239  * @tparam RandomNumberGenerator
240  */
241 template <class MachineIterator, class JobIterator, class OutputIterator,
242  class GetSpeed, class GetLoad,
243  class RandomNumberGenerator = std::default_random_engine>
244 void schedule_randomized(const MachineIterator mfirst,
245  const MachineIterator mlast, const JobIterator jfirst,
246  const JobIterator jlast, OutputIterator result,
247  GetSpeed get_speed, GetLoad get_load,
248  RandomNumberGenerator &&gen =
249  std::default_random_engine(97345631u)) {
250  typedef typename detail::sched_traits<MachineIterator, JobIterator,
251  GetSpeed, GetLoad> Traits;
252  double alpha = std::uniform_real_distribution<double>()(gen);
253  auto round = [alpha](typename Traits::load_t fractional_load,
254  typename Traits::load_t total_load) {
255  return total_load * alpha < fractional_load;
256  };
257  detail::schedule(mfirst, mlast, jfirst, jlast, result, get_speed, get_load,
258  round);
259 }
260 
261 }
262 }
263 
264 #endif // PAAL_SCHEDULING_JOBS_HPP
auto make_functor_to_comparator(Functor functor, Compare compare=Compare())
make for functor to comparator
Definition: functors.hpp:654
auto irange(T begin, T end)
irange
Definition: irange.hpp:22
This file contains set of simple useful functors or functor adapters.
void assign_max(T &t, const T &u)
void assign_min(T &t, const T &u)
greater functor
Definition: functors.hpp:478
auto make_lift_iterator_functor(Functor f)
make function for lift_iterator_functor
Definition: functors.hpp:467
Implementation of fractions, which are used only for comparison purposes, and thus they can be used w...
typename std::decay< typename std::result_of< F >::type >::type pure_result_of_t
return pure type of function (decays const and reference)
simple class to represent fraction
Definition: fraction.hpp:31
functor return true
Definition: functors.hpp:227
void schedule_deterministic(const MachineIterator mfirst, const MachineIterator mlast, const JobIterator jfirst, const JobIterator jlast, OutputIterator result, GetSpeed get_speed, GetLoad get_load)
detail