cyqlone develop
Fast, parallel and vectorized solver for linear systems with optimal control structure.
Loading...
Searching...
No Matches
algorithms.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cyqlone/config.hpp>
4#include <batmat/assume.hpp>
5#include <guanaqo/trace.hpp>
6#include <algorithm>
7#include <iterator>
8#include <numeric>
9#include <ranges>
10#if CYQLONE_WITH_SKA_SORT
11#include <ska_sort.hpp>
12#endif
13
14namespace CYQLONE_NS(cyqlone::qpalm) {
15
16template <class R, class F>
17static void sort(R &&range, F key) {
18 GUANAQO_TRACE("sort", 0, std::ranges::ssize(range));
19#if CYQLONE_WITH_SKA_SORT
20 ska_sort(std::ranges::begin(range), std::ranges::end(range), key);
21#else
22 std::sort(std::ranges::begin(range), std::ranges::end(range),
23 [&](auto a, auto b) { return key(a) < key(b); });
24#endif
25}
26
27template <class R, class I, class F>
28static void nth_element(R &&range, I mid, F key) {
29 GUANAQO_TRACE("nth_element", 0, std::ranges::ssize(range));
30 std::nth_element(std::ranges::begin(range), mid, std::ranges::end(range),
31 [&](auto a, auto b) { return key(a) < key(b); });
32}
33
34/// A variant of std::ranges::partition where the first element of the return value is the smallest
35/// element of the "false" partition.
36template <std::ranges::bidirectional_range R, class F, class C>
37static std::ranges::subrange<std::ranges::iterator_t<R>> partition_min(R &&range, F pred, C cmp) {
38 GUANAQO_TRACE("partition_min", 0, std::ranges::ssize(range));
39 auto first = std::ranges::begin(range);
40 const auto last = std::ranges::end(range);
41 const auto lasti = std::ranges::next(first, last);
42 auto tail = lasti, min_it = lasti; // Track the minimum element of the "false" partition
43
44 // Return the "false" partition, but first make sure that the minimum element is ordered first
45 auto done = [&] {
46 BATMAT_ASSUME(first == tail);
47 if (min_it != first) {
48 BATMAT_ASSUME(first != lasti);
49 BATMAT_ASSUME(min_it != lasti);
50 std::ranges::iter_swap(min_it, first);
51 }
52 return std::ranges::subrange<std::ranges::iterator_t<R>>(first, lasti);
53 };
54
55 while (true) {
56 // Find the first element that violates the predicate
57 while (true) {
58 if (first == tail) {
59 return done();
60 } else if (pred(*first)) {
61 BATMAT_ASSUME(first != last);
62 ++first;
63 } else {
64 break;
65 }
66 }
67 BATMAT_ASSUME(tail != first);
68 --tail;
69 // Find the last element that satisfies the predicate
70 while (true) {
71 if (first == tail) {
72 if (min_it == last || cmp(*tail, *min_it))
73 min_it = tail;
74 return done();
75 } else if (pred(*tail)) {
76 break;
77 } else {
78 BATMAT_ASSUME(tail != first);
79 if (min_it == last || cmp(*tail, *min_it))
80 min_it = tail;
81 --tail;
82 }
83 }
84 std::ranges::iter_swap(first, tail);
85 if (min_it == last || cmp(*tail, *min_it))
86 min_it = tail;
87 BATMAT_ASSUME(first != last);
88 ++first;
89 }
90}
91
92template <std::ranges::forward_range R, class F>
93static decltype(auto) partition(R &&range, F key) {
94 GUANAQO_TRACE("partition", 0, std::ranges::ssize(range));
95 return std::ranges::partition(range, key);
96}
97template <std::permutable I, std::sentinel_for<I> S, class F>
98static decltype(auto) partition(I first, S last, F key) {
99 GUANAQO_TRACE("partition", 0, std::ranges::distance(first, last));
100 return std::ranges::partition(first, last, key);
101}
102
103template <class R, class F>
104static decltype(auto) min_element(R &&range, F key) {
105 GUANAQO_TRACE("min_element", 0, std::ranges::ssize(range));
106 return std::ranges::min_element(range, {}, key);
107}
108
109template <class I, class T, class BinOp, class UnOp>
110T transform_reduce(I first, I last, T init, BinOp binary_op, UnOp unary_op) {
111 GUANAQO_TRACE("transform_reduce", 0, std::ranges::distance(first, last));
112 return std::transform_reduce(first, last, init, binary_op, unary_op);
113}
114
115} // namespace CYQLONE_NS(cyqlone::qpalm)
#define BATMAT_ASSUME(x)
#define CYQLONE_NS(ns)
Definition config.hpp:10
#define GUANAQO_TRACE(name, instance,...)
static decltype(auto) partition(R &&range, F key)
T transform_reduce(I first, I last, T init, BinOp binary_op, UnOp unary_op)
static std::ranges::subrange< std::ranges::iterator_t< R > > partition_min(R &&range, F pred, C cmp)
A variant of std::ranges::partition where the first element of the return value is the smallest eleme...
static void sort(R &&range, F key)
static decltype(auto) min_element(R &&range, F key)
static void nth_element(R &&range, I mid, F key)