@@ -2603,7 +2603,6 @@ schwartzSort(alias transform, alias less = "a < b",
26032603 foreach (ref p; probs)
26042604 {
26052605 if (! p) continue ;
2606- // enforce(p > 0 && p <= 1, "Wrong probability passed to entropy");
26072606 result -= p * log2(p);
26082607 }
26092608 return result;
@@ -2637,7 +2636,6 @@ schwartzSort(alias transform, alias less = "a < b",
26372636 foreach (ref p; probs)
26382637 {
26392638 if (! p) continue ;
2640- // enforce(p > 0 && p <= 1, "Wrong probability passed to entropy");
26412639 result -= p * log2(p);
26422640 }
26432641 return result;
@@ -3120,6 +3118,185 @@ unittest
31203118 }
31213119}
31223120
3121+ // medianOf
3122+ /*
3123+ Private for the time being.
3124+
3125+ Computes the median of 2 to 5 arbitrary indexes in random-access range `r`
3126+ using hand-written specialized algorithms. The indexes must be distinct (if not,
3127+ behavior is implementation-defined). The function also partitions the elements
3128+ involved around the median, e.g. $(D medianOf(r, a, b, c)) not only fills `r[b]`
3129+ with the median of `r[a]`, `r[b]`, and `r[c]`, but also puts the minimum in
3130+ `r[a]` and the maximum in `r[c]`.
3131+
3132+ Params:
3133+ less = The comparison predicate used, modeled as a $(LUCKY strict weak
3134+ ordering) (irreflexive, antisymmetric, transitive, and implying a transitive
3135+ equivalence).
3136+ flag = Used only for even values of `T.length`. If `No.leanRight`, the median
3137+ "leans left", meaning $(D medianOf(r, a, b, c, d)) puts the lower median of the
3138+ four in `r[b]`, the minimum in `r[a]`, and the two others in `r[c]` and `r[d]`.
3139+ Conversely, $(D median!("a < b", Yes.leanRight)(r, a, b, c, d)) puts the upper
3140+ median of the four in `r[c]`, the maximum in `r[d]`, and the two others in
3141+ `r[a]` and `r[b]`.
3142+ r = The range containing the indexes.
3143+ i = Two to five indexes inside `r`.
3144+ */
3145+ private void medianOf (
3146+ alias less = " a < b" ,
3147+ Flag! " leanRight" flag = No.leanRight,
3148+ Range ,
3149+ Indexes... )
3150+ (Range r, Indexes i)
3151+ if (isRandomAccessRange! Range && hasLength! Range &&
3152+ Indexes.length >= 2 && Indexes.length <= 5 &&
3153+ allSatisfy! (isUnsigned, Indexes))
3154+ {
3155+ assert (r.length >= Indexes.length);
3156+ import std.functional : binaryFun;
3157+ alias lt = binaryFun! less;
3158+ enum k = Indexes.length;
3159+ import std.algorithm.mutation : swapAt;
3160+
3161+ alias a = i[0 ];
3162+ static assert (is (typeof (a) == size_t ));
3163+ static if (k >= 2 )
3164+ {
3165+ alias b = i[1 ];
3166+ static assert (is (typeof (b) == size_t ));
3167+ assert (a != b);
3168+ }
3169+ static if (k >= 3 )
3170+ {
3171+ alias c = i[2 ];
3172+ static assert (is (typeof (c) == size_t ));
3173+ assert (a != c && b != c);
3174+ }
3175+ static if (k >= 4 )
3176+ {
3177+ alias d = i[3 ];
3178+ static assert (is (typeof (d) == size_t ));
3179+ assert (a != d && b != d && c != d);
3180+ }
3181+ static if (k >= 5 )
3182+ {
3183+ alias e = i[4 ];
3184+ static assert (is (typeof (e) == size_t ));
3185+ assert (a != e && b != e && c != e && d != e);
3186+ }
3187+
3188+ static if (k == 2 )
3189+ {
3190+ if (lt(r[b], r[a])) r.swapAt(a, b);
3191+ }
3192+ else static if (k == 3 )
3193+ {
3194+ if (lt(r[c], r[a])) // c < a
3195+ {
3196+ if (lt(r[a], r[b])) // c < a < b
3197+ {
3198+ r.swapAt(a, b);
3199+ r.swapAt(a, c);
3200+ }
3201+ else // c < a, b <= a
3202+ {
3203+ r.swapAt(a, c);
3204+ if (lt(r[b], r[a])) r.swapAt(a, b);
3205+ }
3206+ }
3207+ else // a <= c
3208+ {
3209+ if (lt(r[b], r[a])) // b < a <= c
3210+ {
3211+ r.swapAt(a, b);
3212+ }
3213+ else // a <= c, a <= b
3214+ {
3215+ if (lt(r[c], r[b])) r.swapAt(b, c);
3216+ }
3217+ }
3218+ assert (! lt(r[b], r[a]));
3219+ assert (! lt(r[c], r[b]));
3220+ }
3221+ else static if (k == 4 )
3222+ {
3223+ static if (flag == No.leanRight)
3224+ {
3225+ // Eliminate the rightmost from the competition
3226+ if (lt(r[d], r[c])) r.swapAt(c, d); // c<=d
3227+ if (lt(r[d], r[b])) r.swapAt(b, d); // b<=d
3228+ medianOf! lt(r, a, b, c);
3229+ }
3230+ else
3231+ {
3232+ // Eliminate the leftmost from the competition
3233+ if (lt(r[b], r[a])) r.swapAt(a, b); // a<=b
3234+ if (lt(r[c], r[a])) r.swapAt(a, c); // a<=c
3235+ medianOf! lt(r, b, c, d);
3236+ }
3237+ }
3238+ else static if (k == 5 )
3239+ {
3240+ // Credit: Teppo Niinimäki
3241+ version (unittest ) scope (success)
3242+ {
3243+ assert (! lt(r[c], r[a]));
3244+ assert (! lt(r[c], r[b]));
3245+ assert (! lt(r[d], r[c]));
3246+ assert (! lt(r[e], r[c]));
3247+ }
3248+
3249+ if (lt(r[c], r[a])) r.swapAt(a, c);
3250+ if (lt(r[d], r[b])) r.swapAt(b, d);
3251+ if (lt(r[d], r[c]))
3252+ {
3253+ r.swapAt(c, d);
3254+ r.swapAt(a, b);
3255+ }
3256+ if (lt(r[e], r[b])) r.swapAt(b, e);
3257+ if (lt(r[e], r[c]))
3258+ {
3259+ r.swapAt(c, e);
3260+ if (lt(r[c], r[a])) r.swapAt(a, c);
3261+ }
3262+ else
3263+ {
3264+ if (lt(r[c], r[b])) r.swapAt(b, c);
3265+ }
3266+ }
3267+ }
3268+
3269+ // /
3270+ unittest
3271+ {
3272+ // Verify medianOf for all permutations of [1, 2, 2, 3, 4].
3273+ int [5 ] data = [1 , 2 , 2 , 3 , 4 ];
3274+ do
3275+ {
3276+ int [5 ] a = data;
3277+ medianOf(a[], size_t (0 ), size_t (1 ));
3278+ assert (a[0 ] <= a[1 ]);
3279+
3280+ a[] = data[];
3281+ medianOf(a[], size_t (0 ), size_t (1 ), size_t (2 ));
3282+ assert (ordered(a[0 ], a[1 ], a[2 ]));
3283+
3284+ a[] = data[];
3285+ medianOf(a[], size_t (0 ), size_t (1 ), size_t (2 ), size_t (3 ));
3286+ assert (a[0 ] <= a[1 ] && a[1 ] <= a[2 ] && a[1 ] <= a[3 ]);
3287+
3288+ a[] = data[];
3289+ medianOf! (" a < b" , Yes.leanRight)(a[], size_t (0 ), size_t (1 ),
3290+ size_t (2 ), size_t (3 ));
3291+ assert (a[0 ] <= a[2 ] && a[1 ] <= a[2 ] && a[2 ] <= a[3 ]);
3292+
3293+ a[] = data[];
3294+ medianOf(a[], size_t (0 ), size_t (1 ), size_t (2 ), size_t (3 ), size_t (4 ));
3295+ assert (a[0 ] <= a[2 ] && a[1 ] <= a[2 ] && a[2 ] <= a[3 ] && a[2 ] <= a[4 ]);
3296+ }
3297+ while (nextPermutation(data[]));
3298+ }
3299+
31233300// nextPermutation
31243301/**
31253302 * Permutes $(D range) in-place to the next lexicographically greater
0 commit comments