Skip to content

Commit 4dec172

Browse files
committed
rework isSorted and friend
1 parent 817a711 commit 4dec172

File tree

1 file changed

+54
-32
lines changed

1 file changed

+54
-32
lines changed

source/mir/ndslice/sorting.d

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,46 +22,29 @@ With either function, the predicate must be a strict ordering just like with
2222
incorrect and will cause failed assertions.
2323
2424
Params:
25-
less = Predicate the range should be sorted by.
25+
less = Predicate the ndslice should be sorted by.
26+
Note:
27+
isSorted requires predicates for floating point types looks like `!(cmp_condition)`
28+
to return false if the ndslice contains NaNs.
2629
+/
27-
template isSorted(alias less = "a < b")
30+
template isSorted(alias less = "!(a >= b)")
2831
{
2932
import mir.functional: naryFun;
3033
static if (__traits(isSame, naryFun!less, less))
3134
/++
3235
slice = A slice to check for sortedness.
3336
Returns:
34-
`true` if the range is sorted, false otherwise. `isSorted` allows
37+
`true` if the ndslice is sorted, false otherwise. `isSorted` allows
3538
duplicates, $(LREF _isStrictlyMonotonic) not.
3639
+/
3740
@fastmath bool isSorted(SliceKind kind, size_t[] packs, Iterator)
3841
(Slice!(kind, packs, Iterator) slice)
3942
if (packs.length == 1)
4043
{
41-
if (slice.anyEmpty)
42-
return true;
43-
44-
auto ahead = slice;
45-
ahead.popFront();
46-
47-
static if (packs[0] == 1)
48-
{
49-
for (; !ahead.empty; ahead.popFront(), slice.popFront())
50-
{
51-
if (!less(ahead.front, slice.front)) continue;
52-
// Check for antisymmetric predicate
53-
assert(
54-
!less(slice.front, ahead.front),
55-
"Predicate for isSorted is not antisymmetric. Both" ~
56-
" pred(a, b) and pred(b, a) are true for certain values.");
57-
return false;
58-
}
59-
return true;
60-
}
61-
else
62-
{
63-
static assert("isSorted does not implemented for multidimensional slices.");
64-
}
44+
import mir.functional: reverseArgs;
45+
import mir.ndslice.algorithm: all;
46+
import mir.ndslice.topology: flattened, slide;
47+
return slice.flattened.slide!(2, reverseArgs!less).all!"!a";
6548
}
6649
else
6750
alias isSorted = .isSorted!(naryFun!less);
@@ -77,16 +60,55 @@ template isStrictlyMonotonic(alias less = "a < b")
7760
(Slice!(kind, packs, Iterator) slice)
7861
if (packs.length == 1)
7962
{
80-
static if (__traits(isSame, less, less))
81-
///
82-
import std.algorithm.searching : findAdjacent;
83-
import mir.functional: not;
84-
return findAdjacent!(not!less)(r).empty;
63+
import mir.ndslice.algorithm: all;
64+
import mir.ndslice.topology: flattened, slide;
65+
return slice.flattened.slide!(2, less).all!"a";
8566
}
8667
else
8768
alias isStrictlyMonotonic = .isStrictlyMonotonic!(naryFun!less);
8869
}
8970

71+
72+
///
73+
unittest
74+
{
75+
assert([1, 1, 2].sliced.isSorted);
76+
// strictly monotonic doesn't allow duplicates
77+
assert(![1, 1, 2].sliced.isStrictlyMonotonic);
78+
79+
auto arr = [4, 3, 2, 1].sliced;
80+
assert(!isSorted(arr));
81+
assert(!isStrictlyMonotonic(arr));
82+
83+
sort(arr);
84+
assert(isSorted(arr));
85+
assert(isStrictlyMonotonic(arr));
86+
}
87+
88+
unittest
89+
{
90+
auto a = [1, 2, 3].sliced;
91+
assert(isSorted(a[0 .. 0]));
92+
assert(isSorted(a[0 .. 1]));
93+
assert(isSorted(a));
94+
auto b = [1, 3, 2].sliced;
95+
assert(!isSorted(b));
96+
97+
// ignores duplicates
98+
auto c = [1, 1, 2].sliced;
99+
assert(isSorted(c));
100+
}
101+
102+
unittest
103+
{
104+
assert([1, 2, 3][0 .. 0].sliced.isStrictlyMonotonic);
105+
assert([1, 2, 3][0 .. 1].sliced.isStrictlyMonotonic);
106+
assert([1, 2, 3].sliced.isStrictlyMonotonic);
107+
assert(![1, 3, 2].sliced.isStrictlyMonotonic);
108+
assert(![1, 1, 2].sliced.isStrictlyMonotonic);
109+
}
110+
111+
90112
///
91113
template sort(alias less = "a < b")
92114
{

0 commit comments

Comments
 (0)