Turi Create  4.0
algorithm.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_UNITY_SITERABLE_ALGORITHMS_HPP
7 #define TURI_UNITY_SITERABLE_ALGORITHMS_HPP
8 #include <set>
9 #include <functional>
10 #include <algorithm>
11 #include <type_traits>
12 #include <iterator>
13 #include <core/parallel/lambda_omp.hpp>
14 #include <core/random/random.hpp>
15 #include <core/storage/sframe_data/siterable.hpp>
16 #include <core/storage/sframe_data/swriter_base.hpp>
17 #include <core/storage/sframe_data/sarray_reader.hpp>
18 #include <core/storage/sframe_data/is_sarray_like.hpp>
19 namespace turi {
20 /**
21  * \ingroup sframe_physical
22  * \addtogroup eager_algorithms Generic SFrame Eager Algorithms
23  * \{
24  */
25 /**************************************************************************/
26 /* */
27 /* Implementation of transform */
28 /* */
29 /**************************************************************************/
30 
31 /**
32  * Writes input to output calling the transformfn on each input emitting
33  * the result to output.
34  *
35  * This class accomplishes the abstract equivalent of
36  * \code
37  * for each x in input:
38  * write transformfn(x) to output
39  * \endcode
40  *
41  * The input object must be a descendent of \ref siterable, and the output
42  * object must be a descendent of \ref swriter_base. \ref sarray and
43  * \ref swriter are two common instances of either.
44  *
45  * The output object should be of the same number of segments as the input
46  * object. If they are of different number of segments, this function will
47  * attempt to change the number of segments of the output object. Changing the
48  * number of segments is generally a successful operation unless writes have
49  * already occured on the output. If the number of segments do not match,
50  * and if the number of output segments cannot be set, this function
51  * will throw a string exception and fail.
52  *
53  * \param input The input to read from. Must be a descendent of siterable
54  * \param output The output writer to write to. Must be a descendent of swriter_base
55  * \param transformfn The transform operation to perform on the input
56  * to generate the output
57  * \param constraint_segments The set of segments to operate on. If empty
58  * (default) will operate on all segments. Only valid
59  * segment numbers will be operated on.
60  */
61 template <typename S, typename T, typename TransformFn,
62 typename = typename std::enable_if<sframe_impl::is_sarray_like<S>::value>::type,
63 typename = typename std::enable_if<sframe_impl::is_sarray_like<T>::value>::type>
64 void transform(S&& input, T&& output,
65  TransformFn transformfn,
66  std::set<size_t> constraint_segments = std::set<size_t>()) {
67  log_func_entry();
68  ASSERT_TRUE(input.is_opened_for_read());
69  ASSERT_TRUE(output.is_opened_for_write());
70  auto input_reader = input.get_reader(output.num_segments());
71  // construct a vector containing a list of segments to operate on
72  std::vector<size_t> segments;
73  // if constraint segments is empty, we operate on all segments
74  if (constraint_segments.empty()) {
75  segments.resize(output.num_segments());
76  for (size_t i = 0; i < segments.size(); ++i) {
77  segments[i] = i;
78  }
79  } else {
80  std::copy(constraint_segments.begin(),
81  constraint_segments.end(),
82  std::inserter(segments, segments.end()));
83  }
84 
85  // perform a parallel for through the list of segments
86  parallel_for(0, segments.size(),
87  [&](size_t idx) {
88  size_t segid = segments[idx];
89  if (segid >= input_reader->num_segments()) return;
90  auto input_begin = input_reader->begin(segid);
91  auto input_end = input_reader->end(segid);
92  auto output_iter = output.get_output_iterator(segid);
93  std::transform(input_begin, input_end, output_iter, transformfn);
94  });
95 }
96 
97 
98 /**************************************************************************/
99 /* */
100 /* Implementation of copy_if */
101 /* */
102 /**************************************************************************/
103 
104 /**
105  * Filters input to output calling the filterfn on each input and emitting
106  * the input to output only if the filter function evaluates to true.
107  *
108  * This class accomplishes the abstract equivalent of
109  * \code
110  * for each x in input:
111  * if (filterfn(x)) write x to output
112  * \endcode
113  *
114  * The input object must be a descendent of \ref siterable, and the output
115  * object must be a descendent of \ref swriter_base. \ref sarray and
116  * \ref swriter are two common instances of either.
117  *
118  * The output object should be of the same number of segments as the input
119  * object. If they are of different number of segments, this function will
120  * attempt to change the number of segments of the output object. Changing the
121  * number of segments is generally a successful operation unless writes have
122  * already occured on the output. If the number of segments do not match,
123  * and if the number of output segments cannot be set, this function
124  * will throw a string exception and fail.
125  *
126  * \param input The input to read from. Must be a descendent of siterable
127  * \param output The output writer to write to. Must be a descendent of swriter_base
128  * \param filterfn The filter operation to perform on the input. If the filterfn
129  * evaluates to true, the input is copied to the output.
130  * \param constraint_segments The set of segments to operate on. If empty
131  * (default) will operate on all segments. Only valid
132  * segment numbers will be operated on.
133  */
134 template <typename S, typename T, typename FilterFn,
135 typename = typename std::enable_if<sframe_impl::is_sarray_like<S>::value>::type,
136 typename = typename std::enable_if<sframe_impl::is_sarray_like<T>::value>::type>
137 void copy_if(S&& input, T&& output,
138  FilterFn filterfn,
139  std::set<size_t> constraint_segments = std::set<size_t>(),
140  size_t random_seed=size_t(-1)) {
141  log_func_entry();
142  ASSERT_TRUE(input.is_opened_for_read());
143  ASSERT_TRUE(output.is_opened_for_write());
144  auto input_reader = input.get_reader(output.num_segments());
145  // construct a vector containing a list of segments to operate on
146  std::vector<size_t> segments;
147  // if constraint segments is empty, we operate on all segments
148  if (constraint_segments.empty()) {
149  segments.resize(input_reader->num_segments());
150  for (size_t i = 0; i < segments.size(); ++i) {
151  segments[i] = i;
152  }
153  } else {
154  std::copy(constraint_segments.begin(),
155  constraint_segments.end(),
156  std::inserter(segments, segments.end()));
157  }
158 
159  // perform a parallel for through the list of segments
160  parallel_for(0, segments.size(),
161  [&](size_t idx) {
162  if (random_seed != size_t(-1)){
163  random::get_source().seed(random_seed + idx);
164  }
165  size_t segid = segments[idx];
166  if (segid >= input_reader->num_segments()) return;
167  auto input_begin = input_reader->begin(segid);
168  auto input_end = input_reader->end(segid);
169  auto output_iter = output.get_output_iterator(segid);
170  std::copy_if(input_begin, input_end, output_iter, filterfn);
171  });
172 }
173 
174 /**
175  * Filters input to output calling the filterfn on each input and emitting
176  * the transformed input to output only if the filter function evaluates to true.
177  *
178  * This class accomplishes the abstract equivalent of
179  * \code
180  * for each x in input:
181  * if (filterfn(x)) write transform(x) to output
182  * \endcode
183  *
184  * The input object must be a descendent of \ref siterable, and the output
185  * object must be a descendent of \ref swriter_base. \ref sarray and
186  * \ref swriter are two common instances of either.
187  *
188  * The output object should be of the same number of segments as the input
189  * object. If they are of different number of segments, this function will
190  * attempt to change the number of segments of the output object. Changing the
191  * number of segments is generally a successful operation unless writes have
192  * already occured on the output. If the number of segments do not match,
193  * and if the number of output segments cannot be set, this function
194  * will throw a string exception and fail.
195  *
196  * The output object should be ready for write and the schema must match
197  * the output schema of the transform function.
198  *
199  * \param input The input to read from. Must be a descendent of siterable
200  * \param output The output writer to write to. Must be a descendent of swriter_base
201  * \param filterfn The filter operation to perform on the input. If the filterfn
202  * evaluates to true, the input is copied to the output.
203  * \param transformfn The transform operation to perform on the input.
204  * \param constraint_segments The set of segments to operate on. If empty
205  * (default) will operate on all segments. Only valid
206  * segment numbers will be operated on.
207  */
208 template <typename S, typename T, typename FilterFn, typename TransformFn,
209 typename = typename std::enable_if<sframe_impl::is_sarray_like<S>::value>::type,
210 typename = typename std::enable_if<sframe_impl::is_sarray_like<T>::value>::type>
211 void copy_transform_if(S&& input, T&& output,
212  FilterFn filterfn,
213  TransformFn transformfn,
214  std::set<size_t> constraint_segments = std::set<size_t>(),
215  size_t random_seed=size_t(-1)) {
216  log_func_entry();
217  ASSERT_TRUE(input.is_opened_for_read());
218  ASSERT_TRUE(output.is_opened_for_write());
219  auto input_reader = input.get_reader(output.num_segments());
220  // construct a vector containing a list of segments to operate on
221  std::vector<size_t> segments;
222  // if constraint segments is empty, we operate on all segments
223  if (constraint_segments.empty()) {
224  segments.resize(input_reader->num_segments());
225  for (size_t i = 0; i < segments.size(); ++i) {
226  segments[i] = i;
227  }
228  } else {
229  std::copy(constraint_segments.begin(),
230  constraint_segments.end(),
231  std::inserter(segments, segments.end()));
232  }
233 
234  // perform a parallel for through the list of segments
235  parallel_for(0, segments.size(),
236  [&](size_t idx) {
237  if (random_seed != size_t(-1)){
238  random::get_source().seed(random_seed + idx);
239  }
240  size_t segid = segments[idx];
241  if (segid >= input_reader->num_segments()) return;
242  auto input_begin = input_reader->begin(segid);
243  auto input_end = input_reader->end(segid);
244  auto output_iter = output.get_output_iterator(segid);
245 
246  while (input_begin != input_end) {
247  if (filterfn(*input_begin)) {
248  *output_iter = transformfn(*input_begin);
249  ++output_iter;
250  }
251  ++input_begin;
252  }
253  });
254 }
255 
256 /**************************************************************************/
257 /* */
258 /* Implementation of split */
259 /* */
260 /**************************************************************************/
261 /**
262  * Split input to output1 and output2 calling the filterfn on each input and emitting
263  * the input to output1 if the filter function evaluates to true, output2 otherwise.
264  *
265  * This class accomplishes the abstract equivalent of
266  * \code
267  * for each x in input:
268  * if (filterfn(x)) write x to output1
269  * else write x to output2
270  * \endcode
271  *
272  * The input object must be a descendent of \ref siterable, and the output
273  * object must be a descendent of \ref swriter_base. \ref sarray and
274  * \ref swriter are two common instances of either.
275  *
276  * The output object should be of the same number of segments as the input
277  * object. If they are of different number of segments, this function will
278  * attempt to change the number of segments of the output object. Changing the
279  * number of segments is generally a successful operation unless writes have
280  * already occured on the output. If the number of segments do not match,
281  * and if the number of output segments cannot be set, this function
282  * will throw a string exception and fail.
283  *
284  * \param input The input to read from. Must be a descendent of siterable
285  * \param output1 The output writer to write to. Must be a descendent of swriter_base
286  * \param output2 The output writer to write to. Must be a descendent of swriter_base
287  * \param filterfn The filter operation to perform on the input. If the filterfn
288  * evaluates to true, the input is copied to the output1, else output2.
289  */
290 template <typename S, typename T, typename FilterFn,
291 typename = typename std::enable_if<sframe_impl::is_sarray_like<S>::value>::type,
292 typename = typename std::enable_if<sframe_impl::is_sarray_like<T>::value>::type>
293 void split(S&& input, T&& output1, T&& output2,
294  FilterFn filterfn,
295  size_t random_seed=std::time(NULL)) {
296  log_func_entry();
297  ASSERT_TRUE(input.is_opened_for_read());
298  ASSERT_TRUE(output1.is_opened_for_write());
299  ASSERT_TRUE(output2.is_opened_for_write());
300  if (output1.set_num_segments(output2.num_segments()) == false) {
301  log_and_throw("Expects outputs to have the same number of segments");
302  }
303 
304  auto input_reader = input.get_reader(output1.num_segments());
305  // perform a parallel for through the list of segments
306  parallel_for(0, input_reader->num_segments(),
307  [&](size_t idx) {
308  if (random_seed != -1) {
309  random::get_source().seed(random_seed + idx);
310  }
311  auto input_begin = input_reader->begin(idx);
312  auto input_end = input_reader->end(idx);
313  auto output_iter1 = output1.get_output_iterator(idx);
314  auto output_iter2 = output2.get_output_iterator(idx);
315  auto iter = input_begin;
316  while(iter != input_end) {
317  auto& val = *iter;
318  if (filterfn(val)) {
319  *output_iter1 = val;
320  ++output_iter1;
321  } else {
322  *output_iter2 = val;
323  ++output_iter2;
324  }
325  ++iter;
326  }
327  });
328 }
329 
330 
331 /**************************************************************************/
332 /* */
333 /* Implementation of copy (from regular iterators to the swriter) */
334 /* */
335 /**************************************************************************/
336 
337 namespace sframe_impl {
338 
339 template <typename Iterator, typename SWriter>
340 void do_copy(Iterator begin, Iterator end, SWriter&& writer,
341  std::input_iterator_tag) {
342  using std::distance;
343  size_t length = distance(begin, end);
344  size_t items_written = 0;
345  // for each output array
346  for (size_t i = 0; i < writer.num_segments(); ++i) {
347  size_t remaining_length = length - items_written;
348  // items to output in this segment is
349  // remaining length / number of segments remaining
350  size_t items_to_output = remaining_length / (writer.num_segments() - i);
351  auto outputiter = writer.get_output_iterator(i);
352  for (size_t j = 0;j < items_to_output; ++j) {
353  *outputiter = *begin;
354  ++outputiter;
355  ++begin;
356  }
357  items_written += items_to_output;
358  }
359 }
360 
361 
362 
363 template <typename Iterator, typename SWriter>
364 void do_copy(Iterator begin, Iterator end, SWriter&& writer,
365  std::random_access_iterator_tag tag) {
366  size_t num_segments = writer.num_segments();
367  // get all the output iterators
368  size_t length = std::distance(begin, end);
369  // size of range each segment gets
370  double split_size = (double)length / num_segments;
371 
372  parallel_for(0, num_segments,
373  [&](size_t segment) {
374  // beginning of this worker's range
375  Iterator segment_begin = begin + split_size * segment;
376  // end of this worker's range
377  Iterator segment_end = begin + split_size * (segment + 1);
378  if (segment == num_segments - 1) segment_end = end;
379  auto outputiter = writer.get_output_iterator(segment);
380  while(segment_begin != segment_end) {
381  *outputiter = *segment_begin;
382  ++outputiter;
383  ++segment_begin;
384  }
385  });
386 }
387 
388 } // namespace sframe_impl
389 
390 
391 /**
392  * Writes to an SWriter from a standard input iterator sequence.
393  *
394  * This class accomplishes the abstract equivalent of
395  * \code
396  * for each x in range(begin, end) (regular iterator):
397  * write x to output (swriter)
398  * \endcode
399  *
400  * The input must be a pair of iterators, and the output
401  * object must be a descendent of \ref swriter_base.
402  *
403  * \note The precise arrangement of the data in the segment will depend
404  * on the iterator type. If the iterator range is at minimal a
405  * forward_iterator, The resultant data is blocked across the segments of the
406  * writer. i.e. if the writer has 4 segments, the first 1/4 of the data will go
407  * to segment 1, the next 1/4 will go to segment 2, etc. Otherwise, if the
408  * iterator range is an input iterator, it will be striped across the segments.
409  *
410  * \param begin The start of the forward iterator sequence to write to the writer.
411  * \param end The end of the forward iterator sequence to write to the writer.
412  * \param output The output writer to write to. Must be a descendent of swriter_base
413  */
414 template <typename Iterator, typename SWriter,
415 typename = typename std::enable_if<sframe_impl::is_sarray_like<SWriter>::value>::type>
416 void copy(Iterator begin, Iterator end, SWriter&& writer) {
417  ASSERT_TRUE(writer.is_opened_for_write());
418  sframe_impl::do_copy(begin, end, std::forward<SWriter>(writer),
419  typename std::iterator_traits<Iterator>::iterator_category());
420 }
421 
422 
423 
424 
425 /**
426  * Copies the contents of an SArray to regular output iterator.
427  *
428  * This class accomplishes the abstract equivalent of:
429  * \code
430  * for each x in sarray
431  * write x to output
432  * \endcode
433  *
434  * The input object must be a descendent of \ref swriter_base.
435  *
436  * \param array The SArray to read from
437  * \param output The output iterator to write to.
438  */
439 template <typename S, typename Iterator,
440 typename = typename std::enable_if<sframe_impl::is_sarray_like<S>::value>::type>
441 void copy(S&& array, Iterator output, size_t limit=(size_t)(-1)) {
442  log_func_entry();
443  ASSERT_TRUE(array.is_opened_for_read());
444  // for each segment
445  // copy into the output
446  auto reader = array.get_reader();
447  size_t ctr = 0;
448  for (size_t i = 0;i < reader->num_segments(); ++i) {
449  auto begin = reader->begin(i);
450  auto end = reader->end(i);
451  while(ctr < limit && begin != end) {
452  (*output) = std::move(*begin);
453  ++output;
454  ++begin;
455  ++ctr;
456  }
457  if (ctr >= limit) break;
458  }
459 }
460 
461 /**
462  * Performs a reduction on each segment of an Sarray returning the result of the
463  * reduction on each segment.
464  *
465  * This class accomplishes the abstract equivalent of:
466  * \code
467  * for each segment in sarray
468  * res = init
469  * for each x in segment:
470  * if (f(x, res) == false) break;
471  * returnval[segment] = res
472  * return returnval
473  * \endcode
474  *
475  * The input object must be a descendent of \ref siterable
476  *
477  * \param array The SArray to read from
478  * \param function The reduction function to use. This must be of the form
479  * bool f(const array_value_type&, reduction_type&).
480  * \param init The initial value to use in the reduction
481  *
482  * \tparam ResultType The result type of each reduction.
483  * \tparam S The type of the input array. Must be a descendent of siterable
484  * \tparam FunctionType The type of the function
485  *
486  * \note This function assumes that writes to std::vector<T> can be made in
487  * parallel. i.e. ResultType of bool should not be used.
488  */
489 template <typename ResultType, typename S, typename FunctionType,
490 typename = typename std::enable_if<sframe_impl::is_sarray_like<S>::value>::type>
491 std::vector<ResultType> reduce(S&& input, FunctionType f,
492  ResultType init = ResultType()) {
493  log_func_entry();
494  ASSERT_TRUE(input.is_opened_for_read());
495  std::vector<ResultType> ret;
496  size_t dop = thread::cpu_count();
497  ret.resize(dop, init);
498  auto input_reader = input.get_reader(dop);
499  // perform a parallel for through the list of segments
500  parallel_for(0, dop,
501  [&](size_t idx) {
502  auto input_begin = input_reader->begin(idx);
503  auto input_end = input_reader->end(idx);
504  ResultType reduce_result = init;
505  while(input_begin != input_end) {
506  if (f(*input_begin, reduce_result) == false) break;
507  ++input_begin;
508  }
509  ret[idx] = reduce_result;
510  });
511  return ret;
512 }
513 
514 
515 
516 
517 
518 /**
519  * Writes input to output calling the transformfn on each input pair emitting
520  * the result to output.
521  *
522  * This class accomplishes the abstract equivalent of
523  * \code
524  * for each x in input1:
525  * read next y in input2
526  * write transformfn(x, y) to output
527  * \endcode
528  *
529  * The input objects must be descendents of \ref siterable, and the output
530  * object must be a descendent of \ref swriter_base. \ref sarray and
531  * \ref swriter are two common instances of either.
532  *
533  * \param input1 The first input to read from. Must be a descendent of siterable
534  * \param input2 The second input to read from. Must be a descendent of siterable
535  * \param output The output writer to write to. Must be a descendent of swriter_base
536  * \param transformfn The transform operation to perform on the inputs
537  * to generate the output
538  */
539 template <typename S1, typename S2, typename T, typename TransformFn,
540 typename = typename std::enable_if<sframe_impl::is_sarray_like<S1>::value>::type,
541 typename = typename std::enable_if<sframe_impl::is_sarray_like<S2>::value>::type,
542 typename = typename std::enable_if<sframe_impl::is_sarray_like<T>::value>::type>
543 void binary_transform(S1&& input1, S2&& input2, T&& output,
544  TransformFn transformfn) {
545  log_func_entry();
546  ASSERT_TRUE(input1.is_opened_for_read());
547  ASSERT_TRUE(input2.is_opened_for_read());
548  ASSERT_TRUE(output.is_opened_for_write());
549 
550  auto input1_reader = input1.get_reader(output.num_segments());
551  auto input2_reader = input2.get_reader(output.num_segments());
552  // perform a parallel for through the list of segments
553  parallel_for(0, output.num_segments(),
554  [&](size_t idx) {
555  auto input1_begin = input1_reader->begin(idx);
556  auto input1_end = input1_reader->end(idx);
557  auto input2_begin = input2_reader->begin(idx);
558  auto input2_end = input2_reader->end(idx);
559  auto output_iter = output.get_output_iterator(idx);
560  while(input1_begin != input1_end) {
561  (*output_iter) = transformfn(*input1_begin, *input2_begin);
562  ++input1_begin;
563  ++input2_begin;
564  ++output_iter;
565  }
566  });
567 }
568 
569 
570 
571 /**************************************************************************/
572 /* */
573 /* Implementation of copy_range */
574 /* */
575 /**************************************************************************/
576 
577 /**
578  * Copies a range of elements to the output.
579  *
580  * This class accomplishes the abstract equivalent of
581  * \code
582  * for i = begin; i < end; i += step
583  * write row i in input to to output
584  * \endcode
585  *
586  * The input object must be a descendent of \ref siterable, and the output
587  * object must be a descendent of \ref swriter_base. \ref sarray and
588  * \ref swriter are two common instances of either.
589  *
590  * \param input The input to read from. Must be a descendent of siterable
591  * \param output The output writer to write to. Must be a descendent of swriter_base
592  * \param start The start row to begin reading
593  * \param step The row step
594  * \param end One past the last row to read
595  */
596 template <typename S, typename T,
597 typename = typename std::enable_if<sframe_impl::is_sarray_like<S>::value>::type,
598 typename = typename std::enable_if<sframe_impl::is_sarray_like<T>::value>::type>
599 void copy_range(S&& input, T&& output,
600  size_t start,
601  size_t step,
602  size_t end) {
603  log_func_entry();
604  ASSERT_TRUE(input.is_opened_for_read());
605  ASSERT_TRUE(output.is_opened_for_write());
606 
607  auto reader = input.get_reader();
608  end = std::min(end, reader->size());
609 
610  if (end < start) {
611  log_and_throw("End must be at least start");
612  }
613 
614  // this is the range of input elements
615  size_t element_range = end - start;
616  // there are this number of out elements
617  size_t num_out_elems = 1 + (element_range - 1) / step;
618 
619  parallel_for(0, output.num_segments(),
620  [&](size_t idx) {
621  auto writer = output.get_output_iterator(idx);
622  size_t start_idx = idx * num_out_elems / output.num_segments();
623  size_t end_idx = (idx + 1) * num_out_elems / output.num_segments();
624 
625  std::vector<typename std::decay<S>::type::value_type> buffer;
626  if (step == 1) {
627  // special case for step == 1
628  // read a block and write a block
629  for (size_t i = start_idx;
630  i < end_idx;
632  size_t block_read_range_start = start + i;
633  size_t block_read_range_end =
634  block_read_range_start + DEFAULT_SARRAY_READER_BUFFER_SIZE;
635  block_read_range_end = std::min(block_read_range_end, start + end_idx);
636  reader->read_rows(block_read_range_start,
637  block_read_range_end,
638  buffer);
639  for (auto& row: buffer) {
640  (*writer) = row;
641  ++writer;
642  }
643  }
644  } else {
645  // for step size > 1, read one element at a time
646  for (size_t i = start_idx; i < end_idx; ++i) {
647  reader->read_rows(start + i * step,
648  start + i * step + 1,
649  buffer);
650  if (buffer.size() == 0) break;
651  (*writer) = buffer[0];
652  ++writer;
653  }
654  }
655  });
656 }
657 
658 /// \}
659 } // namespace turi
660 #endif
void parallel_for(size_t begin, size_t end, const FunctionType &fn)
Definition: lambda_omp.hpp:93
void copy(S &&array, Iterator output, size_t limit=(size_t)(-1))
Definition: algorithm.hpp:441
void seed()
Seed the generator using the default seed.
Definition: random.hpp:101
std::vector< ResultType > reduce(S &&input, FunctionType f, ResultType init=ResultType())
Definition: algorithm.hpp:491
void copy_range(S &&input, T &&output, size_t start, size_t step, size_t end)
Definition: algorithm.hpp:599
static size_t cpu_count()
const size_t DEFAULT_SARRAY_READER_BUFFER_SIZE
void copy_transform_if(S &&input, T &&output, FilterFn filterfn, TransformFn transformfn, std::set< size_t > constraint_segments=std::set< size_t >(), size_t random_seed=size_t(-1))
Definition: algorithm.hpp:211
#define ASSERT_TRUE(cond)
Definition: assertions.hpp:309
generator & get_source()
void copy(Iterator begin, Iterator end, SWriter &&writer)
Definition: algorithm.hpp:416
void split(S &&input, T &&output1, T &&output2, FilterFn filterfn, size_t random_seed=std::time(NULL))
Definition: algorithm.hpp:293
void binary_transform(S1 &&input1, S2 &&input2, T &&output, TransformFn transformfn)
Definition: algorithm.hpp:543
void transform(S &&input, T &&output, TransformFn transformfn, std::set< size_t > constraint_segments=std::set< size_t >())
Definition: algorithm.hpp:64
void copy_if(S &&input, T &&output, FilterFn filterfn, std::set< size_t > constraint_segments=std::set< size_t >(), size_t random_seed=size_t(-1))
Definition: algorithm.hpp:137