// tests.h // Copyright (c) 2009 Alexander Stepanov and Paul McJones // // Permission to use, copy, modify, distribute and sell this software // and its documentation for any purpose is hereby granted without // fee, provided that the above copyright notice appear in all copies // and that both that copyright notice and this permission notice // appear in supporting documentation. The authors make no // representations about the suitability of this software for any // purpose. It is provided "as is" without express or implied // warranty. // Regression tests for algorithms from // Elements of Programming // by Alexander Stepanov and Paul McJones // Addison-Wesley Professional, 2009 // To do: move rational, polynomial to eop.h ? #ifndef EOP_TESTS #define EOP_TESTS #include "intrinsics.h" #include "type_functions.h" #include "eop.h" #include "print.h" #include "assertions.h" // Naming conventions: // property_X checks that property X is satisfied for a given set of values // concept_X checks for minimal syntactic requirements of concept X; // it also performs nominal checks of the properties corresponding to the axioms // type_X checks that a that X satisfies the minimal syntactic requirements of the corresponding concept(s) // algorithm_X (or algorithms_X) checks that an algorithm or group of algorithms // satisfies postconditions // test_X performs checks on properties, concepts, types, and algorithms in area X, // e.g., a chapter bool verbose = false; void toggle_verbose() { verbose = !verbose; if (verbose) print("verbose now true"); else print("verbose now false"); print_eol(); } // Chapter 1. Foundations template void concept_Regular(T& x) { // Default constructor T y; // Equality Assert(x == x); // Assignment y = x; Assert(y == x); // Copy constructor T x_copy(x); Assert(x_copy == x); // Default total ordering less lt; Assert(!lt(x, x)); // Underlying type UnderlyingType(T) u; // Destructor } template requires(TotallyOrdered(T)) void concept_TotallyOrdered(T& x0, T& x1) { // Precondition: x0 < x1 Assert(x0 != x1); Assert(!(x0 == x1)); // Natural total ordering Assert(!(x0 < x0)); Assert(x0 < x1); Assert(x1 > x0); Assert(x0 <= x1); Assert(x1 >= x0); Assert(!(x1 < x0)); Assert(!(x0 > x1)); Assert(!(x1 <= x0)); Assert(!(x0 >= x1)); } template requires(Regular(T0) && Regular(T1)) void type_pair(const T0& x00, const T0& x01, const T1& x10, const T1& x11) { // Precondition: x00 < x01 || (x00 == x01 && x10 < x11) Assert(x00 < x01 || (x00 == x01 && x10 < x11)); typedef pair P01; // Pair constructor P01 p0(x00, x10); P01 p1(x01, x11); // Regular concept_Regular(p0); concept_TotallyOrdered(p0, p1); // Member selection Assert(p0.m0 == x00 && p0.m1 == x10); } template requires(Regular(T0) && Regular(T1) && Regular T2) void type_triple(const T0& x00, const T0& x01, const T1& x10, const T1& x11, const T2& x20, const T2& x21) { Assert(x00 < x01 || (x00 == x01 && (x10 < x11 || (x10 == x11 && x20 < x21)))); typedef triple T; // Triple constructor T t0(x00, x10, x20); // triple constructor T t1(x01, x11, x21); // Regular concept_Regular(t0); concept_TotallyOrdered(t0, t1); // Member selection Assert(t0.m0 == x00 && t0.m1 == x10 && t0.m2 == x20); } void test_tuples() { typedef pair P; print(" pair\n"); type_pair(0, 99, 'a', 'a'); type_pair(0, 0, 'a', 'z'); char a[] = {'a', 'Z'}; type_pair(P(0, 'a'), P(1, 'Z'), &(a[0]), &(a[1])); array a0; array a1(3, 3, 0); iota(3, begin(a1)); type_pair< array, char >(a0, a1, 'a', 'z'); slist l0; slist l1(a0); type_pair< slist, char >(l0, l1, 'a', 'z'); type_pair< array, slist >(a0, a1, l0, l1); print(" triple\n"); type_triple(0, 99, 'a', 'z', 1.0, 2.0); } template requires(MultiplicativeSemigroup(T)) struct times { T operator()(const T& a, const T& b) { return a * b; } }; template requires(MultiplicativeSemigroup(T)) struct input_type, 0> { typedef T type; }; void test_ch_1() { print(" Chapter 1\n"); int n0(0); int n1(1); concept_Regular(n0); concept_TotallyOrdered(n0, n1); // *****concept_Integer ????? // We check the most important fact in arithmetic Assert(plus_0(3 * 3, 4 * 4) == 5 * 5); Assert(plus_1(3 * 3, 4 * 4) == 5 * 5); int a = 3 * 3; int b = 4 * 4; int c; plus_2(&a, &b, &c); Assert(c == 5 * 5); Assert(square(3) == 9); Assert(square(3, times()) == 9); test_tuples(); } // Chapter 2. Transformations and their orbits template requires(Transformation(F)) void concept_Transformation(F f, Domain(F) x) { typedef Domain(F) X; typedef Codomain(F) Y; // X == Y Y y; y = x; Assert(x == y); y = f(x); typedef DistanceType(F) N; N n(1); } template requires(UnaryPredicate(P)) void concept_UnaryPredicate(P p, Domain(P) x) { typedef Domain(P) X; X x0; X x1; if (p(x)) x0 = x; else x1 = x; } template requires(MultiplicativeSemigroup(T)) struct sq { T operator()(const T& x) { return x * x; } }; template requires(MultiplicativeSemigroup(T)) struct input_type< sq, 0 > { typedef T type; }; template requires(MultiplicativeSemigroup(T)) struct codomain_type< sq > { typedef T type; }; template requires(MultiplicativeSemigroup(T)) struct distance_type< sq > { typedef T type; }; template requires(Integer(I) && Integer(N) && DistanceType(I) = N) struct gen_orbit_predicate // definition space predicate { I x_0; N h; N c; gen_orbit_predicate(I x_0, N h, N c) : x_0(x_0), h(h), c(c) { // Precondition: h < N(MaximumValue(I)) && c < N(MaximumValue(I)) // Precondition: !negative(h) && !negative(c) } bool operator()(const I& x) { return x_0 <= x && x < x_0 + I(h) + I(c); } }; template requires(Integer(I) && Integer(N) && DistanceType(I) = N) struct input_type, 0> { typedef I type; }; template requires(Integer(I) && Integer(N) && DistanceType(I) = N) struct gen_orbit // transformation { gen_orbit_predicate p; gen_orbit(I x_0, N h, N c) : p(x_0, h, c) { // Precondition: h < N(MaximumValue(I)) && c < N(MaximumValue(I)) // Precondition: !negative(h) && !negative(c) } I operator() (I x) { Assert(p(x)); x = successor(x); if (x == p.x_0 + I(p.h) + I(p.c)) x = p.x_0 + I(p.h); return x; } }; template requires(Integer(I) && Integer(N) && DistanceType(I) = N) struct input_type, 0> { typedef I type; }; template requires(Integer(I) && Integer(N) && DistanceType(I) = N) struct codomain_type< gen_orbit > { typedef I type; }; template requires(Integer(I) && Integer(N) && DistanceType(I) = N) struct distance_type< gen_orbit > { typedef N type; }; template requires(Transformation(F)) void algorithms_orbit(Domain(F) x, DistanceType(F) h, DistanceType(F) c) { typedef Domain(F) T; typedef DistanceType(F) N; F f(x, h, c); Assert(zero(c) == terminating(x, f, f.p)); if (zero(h) && !zero(c)) { Assert(circular(x, f, f.p)); Assert(circular_nonterminating_orbit(x, f)); } else if (!zero(h)) { Assert(!circular(x, f, f.p)); if (!zero(c)) Assert(!circular_nonterminating_orbit(x, f)); } T y = connection_point(x, f, f.p); Assert(power_unary(x, h, f) == y); if (!zero(c)) Assert(y == connection_point_nonterminating_orbit(x, f)); triple t = orbit_structure(x, f, f.p); if (zero(c)) { // terminating Assert(t.m0 == h); Assert(zero(t.m1)); Assert(t.m2 == collision_point(x, f, f.p)); } else if (zero(h)) { // circular Assert(zero(t.m0)); Assert(t.m1 == predecessor(c)); Assert(t.m2 == x); } else { // rho-shaped Assert(t.m0 == h); Assert(t.m1 == predecessor(c)); Assert(t.m2 == y); } if (!zero(c)) { triple t = orbit_structure_nonterminating_orbit(x, f); if (zero(h)) { // circular Assert(zero(t.m0)); Assert(t.m1 == predecessor(c)); Assert(t.m2 == x); } else { // rho-shaped Assert(t.m0 == h); Assert(t.m1 == predecessor(c)); Assert(t.m2 == y); } } } template requires(Integer(N)) struct hf { N operator()(const N& x) { return x / N(2); } }; template requires(Integer(N)) struct input_type< hf, 0 > { typedef N type; }; template requires(Integer(N)) struct codomain_type< hf > { typedef N type; }; template requires(Integer(N)) struct distance_type< hf > { typedef N type; }; void test_ch_2() { print(" Chapter 2\n"); for (int i = 1; i < 100000000; i = 10 * i) { Assert(abs(i) == i); Assert(abs(-i) == i); } Assert(euclidean_norm(3., 4.) == 5.); Assert(euclidean_norm(3., 4., 5.) == euclidean_norm(euclidean_norm(3., 4.), 5.)); concept_Transformation(sq(), 2); concept_Transformation(gen_orbit(0, 0u, 5u), 0); concept_Transformation(hf(), 16); concept_UnaryPredicate(gen_orbit(0, 0u, 5u).p, 0); for (int i = 2; i < 5; i = successor(i)) for (int j = 1; j < 5; j = successor(j)) { int tmp = power_unary(i, predecessor(j), sq()); Assert(power_unary(i, j, sq()) == tmp * tmp); } Assert(distance(2, 65536, sq()) == 4); // Cyclic algorithms_orbit< gen_orbit >(0, 0u, 5u); // Rho-shaped algorithms_orbit< gen_orbit >(0, 2u, 11u); algorithms_orbit< gen_orbit >(7, 97u, 17u); // Terminating algorithms_orbit< gen_orbit >(0, 101u, 0u); Assert(convergent_point_guarded(1024, 64, 1, hf()) == 64); Assert(convergent_point_guarded(1025, 65, 1, hf()) == 32); Assert(convergent_point_guarded(64, 1024, 1, hf()) == 64); Assert(convergent_point_guarded(65, 1025, 1, hf()) == 32); Assert(convergent_point_guarded(1024, 2047, 1, hf()) == 1); } // Chapter 3. Associative operations template requires(BinaryOperation(Op)) void concept_BinaryOperation(Op op, Domain(Op) x) { typedef Domain(Op) X; typedef Codomain(Op) Y; // X == Y Y y; y = x; Assert(x == y); y = op(x, x); } int minus_int(int a, int b) { return a - b; } int times_int(int a, int b) { return a * b; } void algorithm_power(int (*pow)(int, int, int (*)(int, int))) { Assert(pow(1, 1, times_int) == 1); Assert(pow(10, 1, times_int) == 10); Assert(pow(1, 10, times_int) == 1); Assert(pow(2, 2, times_int) == 4); Assert(pow(2, 10, times_int) == 1024); Assert(pow(10, 2, times_int) == 100); } void algorithm_power_accumulate(int (*pow)(int, int, int, int (*)(int, int))) { Assert(pow(99, 1, 1, times_int) == 99 * 1); Assert(pow(99, 10, 1, times_int) == 99 * 10); Assert(pow(99, 1, 10, times_int) == 99 * 1); Assert(pow(99, 2, 2, times_int) == 99 * 4); Assert(pow(99, 2, 10, times_int) == 99 * 1024); Assert(pow(99, 10, 2, times_int) == 99 * 100); Assert(pow(99, 1, 0, times_int) == 99); } void algorithm_power_accumulate_positive(int (*pow)(int, int, int, int (*)(int, int))) { Assert(pow(99, 1, 1, times_int) == 99 * 1); Assert(pow(99, 10, 1, times_int) == 99 * 10); Assert(pow(99, 1, 10, times_int) == 99 * 1); Assert(pow(99, 2, 2, times_int) == 99 * 4); Assert(pow(99, 2, 10, times_int) == 99 * 1024); Assert(pow(99, 10, 2, times_int) == 99 * 100); } void algorithm_power_with_identity(int (*pow)(int, int, int (*)(int, int), int)) { Assert(pow(1, 1, times_int, 1) == 1); Assert(pow(10, 1, times_int, 1) == 10); Assert(pow(1, 10, times_int, 1) == 1); Assert(pow(2, 2, times_int, 1) == 4); Assert(pow(2, 10, times_int, 1) == 1024); Assert(pow(10, 2, times_int, 1) == 100); Assert(pow(1, 0, times_int, 1) == 1); Assert(pow(1, 0, times_int, 99) == 99); } template requires(Integer(I)) void concept_Integer(I n) { I k(11); concept_Regular(n); I m; m = n + k; m = m - k; m = m * k; m = m / k; m = m % k; concept_TotallyOrdered(m, k); m = successor(n); m = predecessor(m); m = twice(m); m = half_nonnegative(m); m = binary_scale_down_nonnegative(m, I(1)); m = binary_scale_up_nonnegative(m, I(1)); bool bp = positive(m); bool bn = negative(m); Assert(!(bp && bn)); bool bz = zero(m); Assert(bz && !(bn || bp) || !bz && (bn || bp)); bool b1 = one(m); Assert(!(bz && b1)); Assert(!b1 || bp); bool be = even(m); bool bo = odd(m); Assert(be != bo); } void test_ch_3() { print(" Chapter 3\n"); concept_BinaryOperation(minus_int, 7); concept_BinaryOperation(times_int, 8); Assert(power_left_associated(-2, 3, minus_int) == 2); // (-2 - -2) - -2 = 2 Assert(power_left_associated(-2, 4, minus_int) == 4); // ((-2 - -2) - -2) - -2 = 4 algorithm_power(power_left_associated); Assert(power_right_associated(-2, 3, minus_int) == -2); // -2 - (-2 - -2) = -2 Assert(power_right_associated(-2, 4, minus_int) == 0); // -2 - (-2 - (-2 - -2) = 0 algorithm_power(power_right_associated); algorithm_power(power_0); algorithm_power(power_1); algorithm_power_accumulate(power_accumulate_0); algorithm_power_accumulate(power_accumulate_1); algorithm_power_accumulate(power_accumulate_2); algorithm_power_accumulate(power_accumulate_3); algorithm_power_accumulate(power_accumulate_4); algorithm_power_accumulate_positive( power_accumulate_positive_0); algorithm_power_accumulate(power_accumulate_5); algorithm_power(power_2); algorithm_power(power_3); algorithm_power_accumulate_positive( power_accumulate_positive); algorithm_power_accumulate(power_accumulate); algorithm_power(power); algorithm_power_with_identity(power); typedef long long N; typedef pair Fib; concept_Integer(N(7)); concept_BinaryOperation(fibonacci_matrix_multiply, Fib(N(1), N(0))); Fib f10(55, 34); Fib f11(89, 55); Fib f21 = fibonacci_matrix_multiply(f10, f11); Assert(f21.m0 == 10946 && f21.m1 == 6765); Assert(fibonacci(10) == N(55)); Assert(fibonacci(20) == N(6765)); }; // Chapter 4. Linear orderings template requires(Relation(R)) void concept_Relation(R r, Domain(R) x) { typedef Domain(R) X; X y; X z; if (r(x, x)) y = x; else z = x; } template requires(Relation(R)) void property_transitive(R r, Domain(R) x, Domain(R) y, Domain(R) z) { concept_Relation(r, x); Assert(!r(x, y) || !r(y, z) || r(x, z)); } template requires(Relation(R)) void property_total_ordering(R r, const Domain(R)& x0, const Domain(R)& x1, const Domain(R)& x2) { // Precondition: total_ordering(r) /\ r(x0, x1) /\ r(x1, x2) Assert(r(x0, x1) && r(x1, x2)); property_transitive(r, x0, x1, x2); Assert( r(x0, x1) && !(x0 == x1) && !r(x1, x0)); // trichotomy Assert(!r(x0, x0) ); // irreflexive } template requires(Relation(R)) void property_reflexive_total_ordering(R r, const Domain(R)& x0, const Domain(R)& x1, const Domain(R)& x2) { // Precondition: total_ordering(r) /\ r(x0, x1) /\ r(x1, x2) Assert(r(x0, x1) && r(x1, x2)); property_transitive(r, x0, x1, x2); property_transitive(r, x0, x0, x1); property_transitive(r, x0, x1, x1); property_transitive(r, x0, x0, x0); Assert(!r(x0, x1) || !r(x1, x0) || x0 == x1); // antisymmetric Assert(r(x0, x0) ); // reflexive } template requires(Regular(T) && Regular(U)) struct first { T operator()(const pair& x) { return x.m0; } }; template requires(Regular(T) && Regular(U)) struct input_type< first, 0 > { typedef pair type; }; template requires(TotallyOrdered(T0)) struct less_first { bool operator()(const pair& p0, const pair& p1) { return p0.m0 < p1.m0; } }; template requires(TotallyOrdered(T0)) struct input_type< less_first, 0 > { typedef pair type; }; template requires(TotallyOrdered(T0)) struct less_second { bool operator()(const pair& p0, const pair& p1) { return p0.m1 < p1.m1; } }; template requires(TotallyOrdered(T0)) struct input_type< less_second, 0 > { typedef pair type; }; template requires(Regular(T0)) struct eq_first { T0 x0; eq_first(T0 x0) : x0(x0) { } bool operator()(const pair& x) { return x.m0 == x0; } }; template requires(Regular(T0)) struct input_type< eq_first, 0 > { typedef pair type; }; template requires(Mutable(I) && BidirectionalIterator(I) && Relation(R)) bool next_permutation(I f, I l, R r) { // Precondition: weak_ordering(r) if (f == l || successor(f) == l) return false; I i = predecessor(l); while (true) { I ii = i; i = predecessor(i); if (r(source(i), source(ii))) { I j = l; do j = predecessor(j); while (!r(source(i), source(j))); exchange_values(i, j); reverse_bidirectional(ii, l); return true; } if (i == f) { reverse_bidirectional(f, l); return false; } } } template requires(UnaryFunction(F) && Relation(R) && Codomain(F) == Domain(R)) struct key_ordering { F f; R r; key_ordering(F f, R r) : f(f), r(r) { } bool operator()(const Domain(F)& x, const Domain(F)& y) { return r(f(x), f(y)); } }; template requires(Function(F) && Arity(F) == 1 && Relation(R) && Codomain(F) == Domain(R)) struct input_type< key_ordering, 0 > { typedef Domain(F) type; }; void algorithm_select_1_4() { print(" select_1_4\n"); typedef pair T; T t[] = {T(1, 1), T(2, 2), T(2, 3), T(3, 4)}; pointer(T) l = t + sizeof(t) / sizeof(T); do { if (verbose) { print(" 2nd of ("); print_range(t, l); print(") is "); } T r = select_1_4(t[0], t[1], t[2], t[3], key_ordering< first, less >(first(), less())); pointer(T) f = find_if(t, l, eq_first(2)); Assert(f != l && source(f) == r); if (verbose) { print(r); print_eol(); } } while (next_permutation(t, l, less_second())); } void algorithm_select_1_4_stability_indices() { print(" select_1_4 with stability indices\n"); typedef pair T; T t[] = {T(1, 1), T(2, 2), T(2, 3), T(3, 4)}; pointer(T) l = t + sizeof(t) / sizeof(T); do { if (verbose) { print(" 2nd of ("); print_range(t, l); print(") is "); } T r = select_1_4<0,1,2,3>(t[0], t[1], t[2], t[3], key_ordering< first, less >(first(), less())); pointer(T) f = find_if(t, l, eq_first(2)); Assert(f != l && source(f) == r); if (verbose) { print(r); print_eol(); } } while (next_permutation(t, l, less_second())); } void algorithm_select_2_5_stability_indices() { print(" select_2_5 with stability indices\n"); typedef pair P; typedef less_first R; P p0('x', 0); P p1('x', 1); P p2('x', 2); P p3('x', 3); P p4('x', 4); Assert(select_2_5<0,1,2,3,4>(p0,p1,p2,p3,p4,R()).m1 == p2.m1); Assert(select_2_5<0,1,2,4,3>(p0,p1,p2,p4,p3,R()).m1 == p2.m1); Assert(select_2_5<0,1,3,2,4>(p0,p1,p3,p2,p4,R()).m1 == p2.m1); Assert(select_2_5<0,1,3,4,2>(p0,p1,p3,p4,p2,R()).m1 == p2.m1); Assert(select_2_5<0,1,4,2,3>(p0,p1,p4,p2,p3,R()).m1 == p2.m1); Assert(select_2_5<0,1,4,3,2>(p0,p1,p4,p3,p2,R()).m1 == p2.m1); Assert(select_2_5<0,2,1,3,4>(p0,p2,p1,p3,p4,R()).m1 == p2.m1); Assert(select_2_5<0,2,1,4,3>(p0,p2,p1,p4,p3,R()).m1 == p2.m1); Assert(select_2_5<0,2,3,1,4>(p0,p2,p3,p1,p4,R()).m1 == p2.m1); Assert(select_2_5<0,2,3,4,1>(p0,p2,p3,p4,p1,R()).m1 == p2.m1); Assert(select_2_5<0,2,4,1,3>(p0,p2,p4,p1,p3,R()).m1 == p2.m1); Assert(select_2_5<0,2,4,3,1>(p0,p2,p4,p3,p1,R()).m1 == p2.m1); Assert(select_2_5<0,3,1,2,4>(p0,p3,p1,p2,p4,R()).m1 == p2.m1); Assert(select_2_5<0,3,1,4,2>(p0,p3,p1,p4,p2,R()).m1 == p2.m1); Assert(select_2_5<0,3,2,1,4>(p0,p3,p2,p1,p4,R()).m1 == p2.m1); Assert(select_2_5<0,3,2,4,1>(p0,p3,p2,p4,p1,R()).m1 == p2.m1); Assert(select_2_5<0,3,4,1,2>(p0,p3,p4,p1,p2,R()).m1 == p2.m1); Assert(select_2_5<0,3,4,2,1>(p0,p3,p4,p2,p1,R()).m1 == p2.m1); Assert(select_2_5<0,4,1,2,3>(p0,p4,p1,p2,p3,R()).m1 == p2.m1); Assert(select_2_5<0,4,1,3,2>(p0,p4,p1,p3,p2,R()).m1 == p2.m1); Assert(select_2_5<0,4,2,1,3>(p0,p4,p2,p1,p3,R()).m1 == p2.m1); Assert(select_2_5<0,4,2,3,1>(p0,p4,p2,p3,p1,R()).m1 == p2.m1); Assert(select_2_5<0,4,3,1,2>(p0,p4,p3,p1,p2,R()).m1 == p2.m1); Assert(select_2_5<0,4,3,2,1>(p0,p4,p3,p2,p1,R()).m1 == p2.m1); Assert(select_2_5<1,0,2,3,4>(p1,p0,p2,p3,p4,R()).m1 == p2.m1); Assert(select_2_5<1,0,2,4,3>(p1,p0,p2,p4,p3,R()).m1 == p2.m1); Assert(select_2_5<1,0,3,2,4>(p1,p0,p3,p2,p4,R()).m1 == p2.m1); Assert(select_2_5<1,0,3,4,2>(p1,p0,p3,p4,p2,R()).m1 == p2.m1); Assert(select_2_5<1,0,4,2,3>(p1,p0,p4,p2,p3,R()).m1 == p2.m1); Assert(select_2_5<1,0,4,3,2>(p1,p0,p4,p3,p2,R()).m1 == p2.m1); Assert(select_2_5<1,2,0,3,4>(p1,p2,p0,p3,p4,R()).m1 == p2.m1); Assert(select_2_5<1,2,0,4,3>(p1,p2,p0,p4,p3,R()).m1 == p2.m1); Assert(select_2_5<1,2,3,0,4>(p1,p2,p3,p0,p4,R()).m1 == p2.m1); Assert(select_2_5<1,2,3,4,0>(p1,p2,p3,p4,p0,R()).m1 == p2.m1); Assert(select_2_5<1,2,4,0,3>(p1,p2,p4,p0,p3,R()).m1 == p2.m1); Assert(select_2_5<1,2,4,3,0>(p1,p2,p4,p3,p0,R()).m1 == p2.m1); Assert(select_2_5<1,3,0,2,4>(p1,p3,p0,p2,p4,R()).m1 == p2.m1); Assert(select_2_5<1,3,0,4,2>(p1,p3,p0,p4,p2,R()).m1 == p2.m1); Assert(select_2_5<1,3,2,0,4>(p1,p3,p2,p0,p4,R()).m1 == p2.m1); Assert(select_2_5<1,3,2,4,0>(p1,p3,p2,p4,p0,R()).m1 == p2.m1); Assert(select_2_5<1,3,4,0,2>(p1,p3,p4,p0,p2,R()).m1 == p2.m1); Assert(select_2_5<1,3,4,2,0>(p1,p3,p4,p2,p0,R()).m1 == p2.m1); Assert(select_2_5<1,4,0,2,3>(p1,p4,p0,p2,p3,R()).m1 == p2.m1); Assert(select_2_5<1,4,0,3,2>(p1,p4,p0,p3,p2,R()).m1 == p2.m1); Assert(select_2_5<1,4,2,0,3>(p1,p4,p2,p0,p3,R()).m1 == p2.m1); Assert(select_2_5<1,4,2,3,0>(p1,p4,p2,p3,p0,R()).m1 == p2.m1); Assert(select_2_5<1,4,3,0,2>(p1,p4,p3,p0,p2,R()).m1 == p2.m1); Assert(select_2_5<1,4,3,2,0>(p1,p4,p3,p2,p0,R()).m1 == p2.m1); Assert(select_2_5<2,0,1,3,4>(p2,p0,p1,p3,p4,R()).m1 == p2.m1); Assert(select_2_5<2,0,1,4,3>(p2,p0,p1,p4,p3,R()).m1 == p2.m1); Assert(select_2_5<2,0,3,1,4>(p2,p0,p3,p1,p4,R()).m1 == p2.m1); Assert(select_2_5<2,0,3,4,1>(p2,p0,p3,p4,p1,R()).m1 == p2.m1); Assert(select_2_5<2,0,4,1,3>(p2,p0,p4,p1,p3,R()).m1 == p2.m1); Assert(select_2_5<2,0,4,3,1>(p2,p0,p4,p3,p1,R()).m1 == p2.m1); Assert(select_2_5<2,1,0,3,4>(p2,p1,p0,p3,p4,R()).m1 == p2.m1); Assert(select_2_5<2,1,0,4,3>(p2,p1,p0,p4,p3,R()).m1 == p2.m1); Assert(select_2_5<2,1,3,0,4>(p2,p1,p3,p0,p4,R()).m1 == p2.m1); Assert(select_2_5<2,1,3,4,0>(p2,p1,p3,p4,p0,R()).m1 == p2.m1); Assert(select_2_5<2,1,4,0,3>(p2,p1,p4,p0,p3,R()).m1 == p2.m1); Assert(select_2_5<2,1,4,3,0>(p2,p1,p4,p3,p0,R()).m1 == p2.m1); Assert(select_2_5<2,3,0,1,4>(p2,p3,p0,p1,p4,R()).m1 == p2.m1); Assert(select_2_5<2,3,0,4,1>(p2,p3,p0,p4,p1,R()).m1 == p2.m1); Assert(select_2_5<2,3,1,0,4>(p2,p3,p1,p0,p4,R()).m1 == p2.m1); Assert(select_2_5<2,3,1,4,0>(p2,p3,p1,p4,p0,R()).m1 == p2.m1); Assert(select_2_5<2,3,4,0,1>(p2,p3,p4,p0,p1,R()).m1 == p2.m1); Assert(select_2_5<2,3,4,1,0>(p2,p3,p4,p1,p0,R()).m1 == p2.m1); Assert(select_2_5<2,4,0,1,3>(p2,p4,p0,p1,p3,R()).m1 == p2.m1); Assert(select_2_5<2,4,0,3,1>(p2,p4,p0,p3,p1,R()).m1 == p2.m1); Assert(select_2_5<2,4,1,0,3>(p2,p4,p1,p0,p3,R()).m1 == p2.m1); Assert(select_2_5<2,4,1,3,0>(p2,p4,p1,p3,p0,R()).m1 == p2.m1); Assert(select_2_5<2,4,3,0,1>(p2,p4,p3,p0,p1,R()).m1 == p2.m1); Assert(select_2_5<2,4,3,1,0>(p2,p4,p3,p1,p0,R()).m1 == p2.m1); Assert(select_2_5<3,0,1,2,4>(p3,p0,p1,p2,p4,R()).m1 == p2.m1); Assert(select_2_5<3,0,1,4,2>(p3,p0,p1,p4,p2,R()).m1 == p2.m1); Assert(select_2_5<3,0,2,1,4>(p3,p0,p2,p1,p4,R()).m1 == p2.m1); Assert(select_2_5<3,0,2,4,1>(p3,p0,p2,p4,p1,R()).m1 == p2.m1); Assert(select_2_5<3,0,4,1,2>(p3,p0,p4,p1,p2,R()).m1 == p2.m1); Assert(select_2_5<3,0,4,2,1>(p3,p0,p4,p2,p1,R()).m1 == p2.m1); Assert(select_2_5<3,1,0,2,4>(p3,p1,p0,p2,p4,R()).m1 == p2.m1); Assert(select_2_5<3,1,0,4,2>(p3,p1,p0,p4,p2,R()).m1 == p2.m1); Assert(select_2_5<3,1,2,0,4>(p3,p1,p2,p0,p4,R()).m1 == p2.m1); Assert(select_2_5<3,1,2,4,0>(p3,p1,p2,p4,p0,R()).m1 == p2.m1); Assert(select_2_5<3,1,4,0,2>(p3,p1,p4,p0,p2,R()).m1 == p2.m1); Assert(select_2_5<3,1,4,2,0>(p3,p1,p4,p2,p0,R()).m1 == p2.m1); Assert(select_2_5<3,2,0,1,4>(p3,p2,p0,p1,p4,R()).m1 == p2.m1); Assert(select_2_5<3,2,0,4,1>(p3,p2,p0,p4,p1,R()).m1 == p2.m1); Assert(select_2_5<3,2,1,0,4>(p3,p2,p1,p0,p4,R()).m1 == p2.m1); Assert(select_2_5<3,2,1,4,0>(p3,p2,p1,p4,p0,R()).m1 == p2.m1); Assert(select_2_5<3,2,4,0,1>(p3,p2,p4,p0,p1,R()).m1 == p2.m1); Assert(select_2_5<3,2,4,1,0>(p3,p2,p4,p1,p0,R()).m1 == p2.m1); Assert(select_2_5<3,4,0,1,2>(p3,p4,p0,p1,p2,R()).m1 == p2.m1); Assert(select_2_5<3,4,0,2,1>(p3,p4,p0,p2,p1,R()).m1 == p2.m1); Assert(select_2_5<3,4,1,0,2>(p3,p4,p1,p0,p2,R()).m1 == p2.m1); Assert(select_2_5<3,4,1,2,0>(p3,p4,p1,p2,p0,R()).m1 == p2.m1); Assert(select_2_5<3,4,2,0,1>(p3,p4,p2,p0,p1,R()).m1 == p2.m1); Assert(select_2_5<3,4,2,1,0>(p3,p4,p2,p1,p0,R()).m1 == p2.m1); Assert(select_2_5<4,0,1,2,3>(p4,p0,p1,p2,p3,R()).m1 == p2.m1); Assert(select_2_5<4,0,1,3,2>(p4,p0,p1,p3,p2,R()).m1 == p2.m1); Assert(select_2_5<4,0,2,1,3>(p4,p0,p2,p1,p3,R()).m1 == p2.m1); Assert(select_2_5<4,0,2,3,1>(p4,p0,p2,p3,p1,R()).m1 == p2.m1); Assert(select_2_5<4,0,3,1,2>(p4,p0,p3,p1,p2,R()).m1 == p2.m1); Assert(select_2_5<4,0,3,2,1>(p4,p0,p3,p2,p1,R()).m1 == p2.m1); Assert(select_2_5<4,1,0,2,3>(p4,p1,p0,p2,p3,R()).m1 == p2.m1); Assert(select_2_5<4,1,0,3,2>(p4,p1,p0,p3,p2,R()).m1 == p2.m1); Assert(select_2_5<4,1,2,0,3>(p4,p1,p2,p0,p3,R()).m1 == p2.m1); Assert(select_2_5<4,1,2,3,0>(p4,p1,p2,p3,p0,R()).m1 == p2.m1); Assert(select_2_5<4,1,3,0,2>(p4,p1,p3,p0,p2,R()).m1 == p2.m1); Assert(select_2_5<4,1,3,2,0>(p4,p1,p3,p2,p0,R()).m1 == p2.m1); Assert(select_2_5<4,2,0,1,3>(p4,p2,p0,p1,p3,R()).m1 == p2.m1); Assert(select_2_5<4,2,0,3,1>(p4,p2,p0,p3,p1,R()).m1 == p2.m1); Assert(select_2_5<4,2,1,0,3>(p4,p2,p1,p0,p3,R()).m1 == p2.m1); Assert(select_2_5<4,2,1,3,0>(p4,p2,p1,p3,p0,R()).m1 == p2.m1); Assert(select_2_5<4,2,3,0,1>(p4,p2,p3,p0,p1,R()).m1 == p2.m1); Assert(select_2_5<4,2,3,1,0>(p4,p2,p3,p1,p0,R()).m1 == p2.m1); Assert(select_2_5<4,3,0,1,2>(p4,p3,p0,p1,p2,R()).m1 == p2.m1); Assert(select_2_5<4,3,0,2,1>(p4,p3,p0,p2,p1,R()).m1 == p2.m1); Assert(select_2_5<4,3,1,0,2>(p4,p3,p1,p0,p2,R()).m1 == p2.m1); Assert(select_2_5<4,3,1,2,0>(p4,p3,p1,p2,p0,R()).m1 == p2.m1); Assert(select_2_5<4,3,2,0,1>(p4,p3,p2,p0,p1,R()).m1 == p2.m1); Assert(select_2_5<4,3,2,1,0>(p4,p3,p2,p1,p0,R()).m1 == p2.m1); } void algorithm_median_5() { print(" median_5\n"); int i1 = 1; int i2 = 2; int i3 = 3; int i4 = 4; int i5 = 5; // ... Assert(&select_2_5_ab_cd<0, 1, 2, 3, 4, less >( i4, i5, i2, i3, i1, less()) == &i3); Assert(&select_2_5_ab<0, 1, 2, 3, 4, less >( i4, i5, i2, i3, i1, less()) == &i3); Assert(&select_2_5<0, 1, 2, 3, 4, less >( i4, i5, i2, i3, i1, less()) == &i3); // int p[5] = {1, 2, 3, 4, 5}; do { if (verbose) { print(" median of ("); print(p[0]); print(" "); print(p[1]); print(" "); print(p[2]); print(" "); print(p[3]); print(" "); print(p[4]); print(") is "); } int m = select_2_5<0, 1, 2, 3, 4,less >( p[0], p[1], p[2], p[3], p[4], less()); Assert(m == 3); if (verbose) { print(m); print_eol(); } } while (next_permutation(p, p + sizeof(p) / sizeof(int), less())); } typedef pair int_pair; void test_ch_4() { print(" Chapter 4\n"); // Test derived relations less lt; complement< less< int > > ge(lt); converse< less< int > > gt(lt); complement_of_converse< less< int > > le(lt); symmetric_complement< less< int> > eq(lt); complement< symmetric_complement< less< int> > > ne(eq); property_total_ordering(lt, 0, 1, 2); property_reflexive_total_ordering(ge, 2, 1, 0); property_total_ordering(gt, 2, 1, 0); property_reflexive_total_ordering(le, 0, 1, 2); property_transitive(eq, 0, 0, 0); Assert(ge(4, 3)); Assert(gt(4, 3)); Assert(le(3, 4)); Assert(le(4, 4)); Assert(eq(4, 4)); Assert(ne(3, 4)); // Test key_ordering typedef first F; F fst; typedef pair PID; key_ordering< F, less > ko(fst, less()); Assert(ko(PID(1, 2.0), PID(2, 1.0))); Assert(!ko(PID(1, 2.0), PID(1, 1.0))); Assert(!ko(PID(1, 1.0), PID(1, 2.0))); // clusters: != > <= >= -- see concept_TotallyOrdered // Test order selection int a = 3; int b = 3; int c = 4; int d = 4; Assert(&select_0_2(a, b, less()) == &a); Assert(&select_0_2(b, a, less()) == &b); Assert(&select_0_2(a, c, less()) == &a); Assert(&select_0_2(c, a, less()) == &a); Assert(select_0_2(a, c, less()) == a); Assert(select_0_2(c, a, less()) == a); Assert(&select_1_2(a, b, less()) == &b); Assert(&select_1_2(b, a, less()) == &a); Assert(&select_1_2(a, c, less()) == &c); Assert(&select_1_2(c, a, less()) == &c); Assert(select_1_2(a, c, less()) == c); Assert(select_1_2(c, a, less()) == c); int_pair p1(1, 1); int_pair p2(1, 2); typedef less_first R; Assert(select_0_2<1, 2, R>(p1, p2, R()) == p1); Assert(select_0_2<1, 2, R>(p2, p1, R()) == p2); Assert(select_1_2<1, 2, R>(p1, p2, R()) == p2); Assert(select_1_2<1, 2, R>(p2, p1, R()) == p1); Assert(&select_0_3(a, b, c, less()) == &a); Assert(&select_0_3(a, c, b, less()) == &a); Assert(&select_0_3(b, a, c, less()) == &b); Assert(&select_0_3(b, c, a, less()) == &b); Assert(&select_0_3(c, a, b, less()) == &a); Assert(&select_0_3(c, b, a, less()) == &b); Assert(select_0_3(a, c, d, less()) == a); Assert(select_0_3(c, a, d, less()) == a); Assert(select_0_3(d, c, a, less()) == a); Assert(&select_2_3(b, c, d, less()) == &d); Assert(&select_2_3(c, b, d, less()) == &d); Assert(&select_2_3(b, d, c, less()) == &c); Assert(&select_2_3(d, b, c, less()) == &c); Assert(&select_2_3(c, d, b, less()) == &d); Assert(&select_2_3(d, c, b, less()) == &c); Assert(select_2_3(a, c, d, less()) == d); Assert(select_2_3(c, a, d, less()) == c); Assert(select_2_3(d, c, a, less()) == c); // Test select_1_3_ab Assert(&select_1_3(a, b, c, less()) == &b); Assert(&select_1_3(a, c, b, less()) == &b); Assert(&select_1_3(b, a, c, less()) == &a); Assert(&select_1_3(b, c, a, less()) == &a); Assert(&select_1_3(c, a, b, less()) == &b); Assert(&select_1_3(c, b, a, less()) == &a); Assert(select_1_3(a, c, d, less()) == c); Assert(select_1_3(c, a, d, less()) == c); Assert(select_1_3(d, c, a, less()) == c); // Test select_1_4_ab_cd // Test select_1_4_ab algorithm_select_1_4(); algorithm_select_1_4_stability_indices(); algorithm_select_2_5_stability_indices(); { const int ca = 1, cb = 2, cc = 3, cd = 4, ce = 5; int b = 12, d = 14; Assert(median_5(1, cb, b, d, 15, less()) == 12); Assert(median_5(ca, cb, cc, cd, ce, less()) == 3); algorithm_median_5(); } { typedef pair P; Assert(min

(P('a', 3), P('a', 4)) == P('a', 3)); Assert(min

(P('a', 4), P('a', 3)) == P('a', 3)); Assert(max

(P('a', 3), P('a', 4)) == P('a', 4)); Assert(max

(P('a', 4), P('a', 3)) == P('a', 4)); } } // Chapter 5. Ordered algebraic structures template requires(OrderedAdditiveSemigroup(T)) void concept_OrderedAdditiveSemigroup(T& x, T& y, T& z) { // Precondition: x < y concept_Regular(x); // + : T x T -> T Assert((x + y) + z == x + (y + z)); Assert(x + y == y + x); concept_TotallyOrdered(x, y); Assert(x + z < y + z); } template requires(OrderedAdditiveMonoid(T)) void concept_OrderedAdditiveMonoid(T& x, T& y, T& z) { concept_OrderedAdditiveSemigroup(x, y, z); // 0 in T Assert(x + T(0) == x); } template requires(OrderedAdditiveGroup(T)) void concept_OrderedAdditiveGroup(T& x, T& y, T& z) { // Precondition: x < y concept_OrderedAdditiveMonoid(x, y, z); // - : T -> T Assert(x + (-x) == T(0)); } template requires(OrderedAdditiveGroup(T)) void algorithm_abs(const T& something) { // We need a nonzero number to test with; OrderedAdditiveGroup doesn't guarantee one T zero(0); Assert(something > zero); T x(something); T y(x + something); T z(y + something); concept_OrderedAdditiveGroup(x, y, z); // need x < y < z Assert(abs(zero) == zero); Assert(abs( something) == something); Assert(abs(-something) == something); } template requires(CancellableMonoid(T)) void concept_CancellableMonoid(T& x, T& y, T& z) { // Precondition: x < y concept_OrderedAdditiveMonoid(x, y, z); // - : T x T -> T if (x <= y) { T z = y - x; // defined Assert(z + x == y); } } template requires(ArchimedeanMonoid(T)) void concept_ArchimedeanMonoid(T& x, T& y, T& z, QuotientType(T) n) { // Precondition: x < y concept_CancellableMonoid(x, y, z); typedef QuotientType(T) N; concept_Integer(n); // slow_remainder terminates for all positive arguments } template requires(ArchimedeanGroup(T)) void concept_ArchimedeanGroup(T& x, T& y, T& z, QuotientType(T) n) { // Precondition: x < y concept_ArchimedeanMonoid(x, y, z, n); T tmp = x - y; Assert(tmp < 0); Assert(-tmp == y - x); } template requires(ArchimedeanMonoid(T)) // + numerals, successor void algorithms_slow_q_and_r() { typedef long Z; plus plus_T; typedef QuotientType(T) N; T max(1000); T a(0); while (a < max) { T b(1); while (b < max) { T r = slow_remainder(a, b); N q = slow_quotient(a, b); Assert(power(b, q, plus_T, T(0)) + r == a); b = successor(b); } a = successor(a); } } template requires(ArchimedeanMonoid(T)) // + numerals, successor void algorithms_q_and_r_nonnegative() { typedef long Z; plus plus_T; typedef QuotientType(T) N; T max(1000); T a(0); while (a < max) { T b(1); while (b < max) { T r = remainder_nonnegative(a, b); pair qr = quotient_remainder_nonnegative(a, b); Assert(qr.m1 == r); Assert(power(b, qr.m0, plus_T, T(0)) + r == a); b = successor(b); } a = successor(a); } } template requires(ArchimedeanMonoid(T)) // + numerals, successor void algorithms_q_and_r_nonnegative_fibonacci() { typedef long Z; plus plus_T; typedef QuotientType(T) N; T max(1000); T a(0); while (a < max) { T b(1); while (b < max) { T r = remainder_nonnegative_fibonacci(a, b); // pair qr = quotient_remainder_nonnegative_fibonacci(a, b); Assert(Z(r) == Z(a) % Z(b)); // Assert(qr.m1 == r); // Assert(Z(qr.m0) == Z(a) / Z(b)); // Assert(power(b, qr.m0, plus_T, T(0)) + r == a); b = successor(b); } a = successor(a); } } template requires(ArchimedeanMonoid(T)) // + numerals, successor void algorithms_q_and_r_nonnegative_iterative() { typedef long Z; plus plus_T; typedef QuotientType(T) N; T max(1000); T a(0); while (a < max) { T b(1); while (b < max) { T r = remainder_nonnegative_iterative(a, b); pair qr = quotient_remainder_nonnegative_iterative(a, b); Assert(Z(r) == Z(a) % Z(b)); Assert(qr.m1 == r); Assert(Z(qr.m0) == Z(a) / Z(b)); Assert(power(b, qr.m0, plus_T, T(0)) + r == a); b = successor(b); } a = successor(a); } } template requires(ArchimedeanMonoid(T)) T largest_power_of_two(T a) { // Precondition: $a > 0$ T b(1); while (b <= a - b) b = b + b; return b; // Postcondition: $(\exists i \geq 0)\,b = 2^i \wedge b \leq a < b+b } template requires(ArchimedeanMonoid(T)) // + numerals, successor void algorithm_largest_doubling() { typedef long Z; T max(1000); T a(1); while (a < max) { T b(1); while (b <= a) { T d = largest_doubling(a, b); // Assert(Z(d) % Z(b) == 0); // it is an integral multiple of b // Z n = Z(d) / Z(b); // n = the integral multiple // Assert(largest_power_of_two(n) == n); // n is a power of 2; it is a doubling Assert(d <= a && d > a - d); // it is the largest b = successor(b); } a = successor(a); } } // remainder for double as EuclideanSemimodule double remainder(double x, double y) { return remainder_nonnegative(x, y); } // concept IntegralDomain(T) means // CommutativeSemiring(T) // /\ (all a,b in T) a*b = T(0) => (a = T(0) \/ b = T(0)) // We vary from the usual definition by allowing a semiring rather than a ring. // The second condition means there are no zero divisors. // See van der Waerden, Modern Algebra, volume 1, chapter 3, section 13, // for the construction of a field of quotients from an integral domain. template requires(IntegralDomain(N)) struct rational { typedef rational T; N p; // numerator N q; // denominator rational() { } rational(const N& p, const N& q) : p(p), q(q) { Assert(q != N(0)); } rational(const N& x) : p(x), q(N(1)) { } }; template requires(IntegralDomain(N)) struct quotient_type< rational > { typedef N type; }; template requires(IntegralDomain(N)) rational operator+(const rational& x, const rational& y) { return rational(y.q * x.p + x.q * y.p, x.q * y.q); } template requires(IntegralDomain(N)) rational operator-(const rational& x) { return rational(-x.p, x.q); } template requires(IntegralDomain(N)) rational operator-(const rational& x, const rational& y) { return x + (-y); } template requires(IntegralDomain(N)) rational operator*(const rational& x, const rational& y) { return rational(x.p * y.p, x.q * y.q); } template requires(IntegralDomain(N)) rational multiplicative_inverse(const rational& x) { // Precondition: $x.p \neq 0$ return rational(x.q, x.p); } template requires(IntegralDomain(N)) rational operator/(const rational& x, const rational& y) { return rational(x.p * y.q, x.q * y.p); // Postcondition: x * multiplicative_inverse(y) } // Multiplication for rational as a semimodule over integers template requires(IntegralDomain(N)) rational operator*(const N& n, const rational& x) { return rational(n * x.p, x.q); } template requires(IntegralDomain(N)) rational remainder(const rational& x, const rational& y) { return remainder_nonnegative(x, y); } template requires(IntegralDomain(N)) bool operator==(const rational& x, const rational& y) { return x.p * y.q == y.p * x.q; } template requires(IntegralDomain(N)) bool operator<(const rational& x, const rational& y) { return x.p * y.q < y.p * x.q; } template requires(IntegralDomain(N)) void print(const rational& x) { if (zero(x.p)) print("0"); else if (one(x.q)) print(x.p); else { print(x.p); print("/"); print(x.q); } } template requires(ArchimedeanGroup(T)) struct ag_quotient_remainder { pair operator()(T a, T b) { Assert(a >= T(0) && b > T(0)); return quotient_remainder_nonnegative(a, b); } }; template requires(ArchimedeanGroup(T)) struct input_type< ag_quotient_remainder, 0 > { typedef T type; }; template requires(ArchimedeanGroup(T)) // + numerals, successor void algorithms_signed_q_and_r() { typedef long Z; typedef QuotientType(T) N; T min(-10); T max(10); T a(min); while (a <= max) { T b(a); while (b <= max) { if (b != T(0)) { T r = remainder(a, b, remainder_nonnegative); Assert(abs(r) < abs(b)); pair qr = quotient_remainder(a, b, ag_quotient_remainder()); Assert(qr.m1 == r); Assert(qr.m0 * b + r == a); } b = successor(b); } a = successor(a); } } typedef rational Q; bool operator<(const Q& x, const Q& y) { return x.p * y.q < y.p * x.q; } template<> struct quotient_type { typedef long type; // ***** what should this be ????? }; // polynomial is a type constructor; it models the following concept // There could be other models, such as sparse representations. // PolynomialRing(T) equals by definition // ValueType : Polynomial -> CommutativeSemiring // IndexType : Polynomial -> Integer // /\ degree : T -> IndexType(T) // /\ coefficient : T x IndexType(T) -> ValueType(T) // /\ lc : T –> ValueType(T) // a \mapsto coefficient(a, degree(a)) // /\ tc : T –> ValueType(T) // a \mapsto coefficient(a, 0) // /\ indeterminate : -> T // /\ evaluate : T x ValueType(T) -> ValueType(T) // /\ · : ValueType(T) x T -> T // /\ + : T x T -> T // /\ · : T x T -> T // /\ shift_left : T x Integer -> T // (a, n) \mapsto power(indeterminate(), n, ·) · a // /\ ... template requires(Ring(T)) struct polynomial { typedef int IndexType; array coeff; // Invariant: degree(f) = size(f.coeff) - 1 /\ // coefficient(f, i) = f.coeff[degree(f) - i] polynomial() : coeff(IndexType(1), IndexType(1), T(0)) { } // f(x) = 0 polynomial(T x_0) : coeff(IndexType(1), IndexType(1), x_0) { } // f(x) = x_0 }; template requires(Ring(T)) struct value_type< polynomial > { typedef T type; }; template requires(Ring(T)) struct index_type; #define IndexType(T) typename index_type< T >::type template requires(Ring(T)) struct index_type< polynomial > { typedef typename polynomial::IndexType type; }; template requires(Ring(T)) IndexType(polynomial) operator==(const polynomial& f, const polynomial& g) { return f.coeff == g.coeff; } template requires(Ring(T)) IndexType(polynomial) operator<(const polynomial& f, const polynomial& g) { return degree(f) < degree(g) || degree(g) == degree(f) && f.coeff < g.coeff; } template requires(Ring(T)) IndexType(polynomial) degree(const polynomial& f) { // ***** Should degree(polynomial(0)) = -infinity ????? return predecessor(size(f.coeff)); } template requires(Ring(T)) void shift_add_in_place(polynomial& f, const T& x_0) { insert(back< array >(f.coeff), x_0); // Postcondition: f'(x) = x * f(x) + x_0 } template requires(Ring(T)) void shift_left_in_place(polynomial& f, IndexType(polynomial) n) { // Precondition: n >= 0 while (count_down(n)) shift_add_in_place(f, T(0)); // Postcondition: f'(x) = x^n * f(x) } template requires(Ring(T)) T coefficient(const polynomial& f, IndexType(polynomial) i) { // Precondition: $0 \leq i \leq \func{degree}(f)$ return f.coeff[degree(f) - i]; // not a reference, to guarantee the invariant holds } template requires(Ring(T)) T lc(const polynomial& f) // leading coefficient { return f.coeff[0]; // Poscondition: returns coefficient(f, degree(f)) } template requires(Ring(T)) T tc(const polynomial& f) // trailing coefficient { return f.coeff[size(f.coeff) - 1]; // Poscondition: returns coefficient(f, 0) } template requires(Ring(T)) bool monic(const polynomial& f) { return lc(f) == T(1); } template requires(Ring(T)) polynomial indeterminate() { polynomial f(T(1)); // f(x) = 1 shift_add_in_place(f, T(0)); // f'(x) = f(x) * x + 0 = 1 * x = x return f; // could be a static const member // Postcondition: returns f(x) = x } template requires(Ring(T)) polynomial evaluate(const polynomial& f, const T& x_0) { typedef IndexType(polynomial) I; I n(degree(f)); // Horner's scheme T r = coefficient(f, n); while (!negative(n)) { n = predecessor(n); r = (r * x_0) + coefficient(f, n); } return r; // Postcondition: r = f(x_0) } template requires(Ring(T)) polynomial add(const polynomial& f, const polynomial& g, IndexType(polynomial) d, IndexType(polynomial) n_g) { // Precondition: $0 < d = degree(f) - degree(g) \wedge n_g = degree(g)$ typedef IndexType(polynomial) I; polynomial h(lc(f)); I i(1); while (i != d) { shift_add_in_place(h, f.coeff[i]); i = successor(i); } I j(0); while (j <= n_g) { shift_add_in_place(h, f.coeff[i] + g.coeff[j]); i = successor(i); j = successor(j); } return h; // Postcondition: h(x) = f(x) + g(x) } template requires(Ring(T)) polynomial operator+(const polynomial& f, const polynomial& g) { typedef IndexType(polynomial) I; I n_f = degree(f); I n_g = degree(g); if (n_f > n_g) return add(f, g, n_f - n_g, n_g); else if (n_g > n_f) return add(g, f, n_g - n_f, n_f); I i(0); T x; while (i <= n_f) { x = f.coeff[i] + g.coeff[i]; if (x != T(0)) break; i = successor(i); } polynomial h(x); while (i < n_f) { i = successor(i); shift_add_in_place(h, f.coeff[i] + g.coeff[i]); }; return h; // Postcondition: h(x) = f(x) + g(x) } template requires(Ring(T) && Transformation(F) && T == Domain(F)) void transform_coefficients_in_place(polynomial& f, F trans) { typedef IndexType(polynomial) I; I i(0); I n = degree(f); while (i <= n) { f.coeff[i] = trans(f.coeff[i]); i = successor(i); } } template requires(Ring(T)) polynomial operator-(polynomial f) // f is a copy { transform_coefficients_in_place(f, negate()); return f; // Postcondition: f'(x) = -f(x) } template requires(Ring(T)) polynomial operator-(const polynomial& f, const polynomial& g) { return f + (-g); // Postcondition: returns h(x) = f(x) - g(x) } template requires(Ring(T)) polynomial product(const polynomial& f, const polynomial& g) { // Precondition: degree(f) <= degree(g) typedef IndexType(polynomial) I; I n_f = degree(f); I n = n_f + degree(g); polynomial h(lc(f) * lc(g)); n = predecessor(n); // Invariant: shift_left(r, n) is the // (deg(f)+deg(g)-n) highest-order coefficients of the result while (!negative(n)) { T sum(0); I i_f(0); while (i_f <= min(n_f, n)) { sum = sum + coefficient(f, i_f) * coefficient(g, n - i_f); i_f = successor(i_f); } shift_add_in_place(h, sum); n = predecessor(n); } return h; // Postcondition: h(x) = f(x) * g(x) } template requires(Ring(T)) polynomial operator*(const polynomial& f, const polynomial& g) { if (degree(f) <= degree(g)) return product(f, g); else return product(g, f); } template requires(Ring(T)) polynomial operator*(T x_0, const polynomial& f) { polynomial h(f); transform_coefficients_in_place( h, multiplies_transformation< multiplies >(x_0, multiplies())); return h; // Postcondition: h(x) = x_0 * f(x) } template requires(Ring(T)) polynomial shift_left(const polynomial& f, IndexType(polynomial) n) { polynomial h(f); shift_left_in_place(h, n); return h; // Postcondition: h(x) = x^n * f(x) } template requires(Ring(T)) pair< polynomial, polynomial > quotient_remainder(const polynomial& f, const polynomial&g) { // Precondition: unit(lc(g)) T u = multiplicative_inverse(lc(g)); polynomial q(0); polynomial r = f; while (degree(r) >= degree(g)) { // Invariant: f = q * g + r polynomial q_i = shift_left(polynomial(lc(r) * u), degree(r) - degree(g)); q = q + q_i; r = r - q_i * g; } return pair< polynomial, polynomial >(q, r); // Postcondition: f = q * g + r /\ degree(r) < degree(g) } template requires(Ring(T)) polynomial remainder(const polynomial& f, const polynomial&g) { // Precondition: unit(lc(g)) return quotient_remainder(f, g).m1; } template requires(Ring(T)) void print_coefficient(T c, IndexType(polynomial) i) { if (!one(c) || zero(i)) { print(c); if (positive(i)) print("*"); } if (positive(i)) { print("x"); if (i > IndexType(polynomial)(1)) { print("^"); print(i); } } } template requires(Ring(T)) void print(const polynomial& f) { typedef IndexType(polynomial) I; print("polynomial("); I i = degree(f); T c = coefficient(f, i); print_coefficient(c, i); i = predecessor(i); while (!negative(i)) { c = coefficient(f, i); if (!zero(c)) { if (negative(c)) { print(" - "); c = -c; } else print(" + "); print_coefficient(c, i); } i = predecessor(i); } print(")"); } void test_ch_5() { print(" Chapter 5\n"); algorithm_abs(1); algorithm_abs(1l); algorithm_abs(1.0); algorithm_abs(1.0l); algorithm_abs< rational >(rational(1, 2)); // type_functions.h defines QuotientType for several built-in integral types { typedef int T; T x(0); T y(1); T z(2); quotient_type::type n(3); concept_ArchimedeanGroup(x, y, z, n); } { typedef long int T; T x(0); T y(1); T z(2); quotient_type::type n(3); concept_ArchimedeanGroup(x, y, z, n); } { typedef Q T; T x(0); T y(1); T z(2); quotient_type::type n(3); concept_ArchimedeanGroup(x, y, z, n); } { typedef double T; T x(0.0); T y(1.0); T z(2.0); quotient_type::type n(3); concept_ArchimedeanGroup(x, y, z, n); } algorithms_slow_q_and_r(); algorithms_slow_q_and_r(); algorithms_slow_q_and_r(); algorithms_q_and_r_nonnegative(); algorithms_q_and_r_nonnegative(); algorithms_q_and_r_nonnegative(); algorithms_q_and_r_nonnegative_fibonacci(); algorithms_q_and_r_nonnegative_fibonacci(); // algorithms_q_and_r_nonnegative_fibonacci(); algorithms_q_and_r_nonnegative_iterative(); algorithms_q_and_r_nonnegative_iterative(); // algorithms_q_and_r_nonnegative_iterative(); algorithm_largest_doubling(); algorithm_largest_doubling(); algorithm_largest_doubling(); algorithm_largest_doubling(); Assert(subtractive_gcd_nonzero(1000, 990) == 10); Assert(subtractive_gcd_nonzero(1000u, 990u) == 10u); Assert(subtractive_gcd_nonzero(0.75, 0.5) == 0.25); Assert(subtractive_gcd_nonzero(Q(3, 4), Q(1, 2)) == Q(1, 4)); Assert(subtractive_gcd(1000, 990) == 10); Assert(subtractive_gcd(1000, 0) == 1000); Assert(subtractive_gcd(0, 990) == 990); Assert(subtractive_gcd(1000u, 990u) == 10u); Assert(subtractive_gcd(1000u, 0u) == 1000u); Assert(subtractive_gcd(0u, 990u) == 990u); Assert(subtractive_gcd(0.75, 0.5) == 0.25); Assert(subtractive_gcd(0.75, 0.0) == 0.75); Assert(subtractive_gcd(0.0, 0.5) == 0.5); Assert(subtractive_gcd(Q(3, 4), Q(1, 2)) == Q(1, 4)); Assert(subtractive_gcd(Q(3, 4), Q(0, 2)) == Q(3, 4)); Assert(subtractive_gcd(Q(0, 4), Q(1, 2)) == Q(1, 2)); Assert(fast_subtractive_gcd(1000, 990) == 10); Assert(fast_subtractive_gcd(1000, 0) == 1000); Assert(fast_subtractive_gcd(0, 990) == 990); Assert(fast_subtractive_gcd(1000u, 990u) == 10u); Assert(fast_subtractive_gcd(1000u, 0u) == 1000u); Assert(fast_subtractive_gcd(0u, 990u) == 990u); Assert(fast_subtractive_gcd(0.75, 0.5) == 0.25); Assert(fast_subtractive_gcd(0.75, 0.0) == 0.75); Assert(fast_subtractive_gcd(0.0, 0.5) == 0.5); Assert(fast_subtractive_gcd(Q(3, 4), Q(1, 2)) == Q(1, 4)); Assert(fast_subtractive_gcd(Q(3, 4), Q(0, 2)) == Q(3, 4)); Assert(fast_subtractive_gcd(Q(0, 4), Q(1, 2)) == Q(1, 2)); // gcd for EuclideanSemiring Assert(gcd(1000, 990) == 10); Assert(gcd(1000, 0) == 1000); Assert(gcd(0, 990) == 990); Assert(gcd(1000u, 990u) == 10u); Assert(gcd(1000u, 0u) == 1000u); Assert(gcd(0u, 990u) == 990u); { typedef polynomial< rational > Q_X; Q_X a = shift_left(Q_X(1), 2) - Q_X(1); // x^2 - 1 Q_X b = shift_left(Q_X(1), 1) + Q_X(1); // x + 1 if (verbose) { print(" poly 1 = "); print(Q_X(1)); print_eol(); print(" poly a = "); print(a); print_eol(); print(" poly 2*a = "); print(Q_X(2) * a); print_eol(); print(" poly b = "); print(b); print_eol(); print(" poly a * b = "); print(a * b); print_eol(); pair p = quotient_remainder(a, b); print(" poly a / b = "); print(p.m0); print(" remainder "); print(p.m1); print_eol(); } Assert(gcd(a, b) == b); } // gcd for EuclideanSemimodule Assert(gcd(1000, 990) == 10); Assert(gcd(1000, 0) == 1000); Assert(gcd(0, 990) == 990); Assert(gcd(1000u, 990u) == 10u); Assert(gcd(1000u, 0u) == 1000u); Assert(gcd(0u, 990u) == 990u); Assert(gcd(0.75, 0.5) == 0.25); Assert(gcd(0.75, 0.0) == 0.75); Assert(gcd(0.0, 0.5) == 0.5); Assert(gcd(Q(3, 4), Q(1, 2)) == Q(1, 4)); Assert(gcd(Q(3, 4), Q(0, 2)) == Q(3, 4)); Assert(gcd(Q(0, 4), Q(1, 2)) == Q(1, 2)); algorithms_signed_q_and_r(); algorithms_signed_q_and_r(); algorithms_signed_q_and_r(); } // Chapter 6. Iterators // "Thunk"-style iterator template requires(Semiring(T)) struct square_of_i { T i; square_of_i(T i) : i(i) { } }; template requires(Semiring(T)) struct value_type< square_of_i > { typedef T type; }; template requires(Semiring(T)) square_of_i successor(const square_of_i& x) { return square_of_i(x.i + T(1)); } template requires(Semiring(T)) T source(const square_of_i& x) { return x.i * x.i; } template requires(Semiring(T)) bool operator==(const square_of_i& x, const square_of_i& y) { return x.i == y.i; } template requires(BinaryOperation(Op)) struct accumulate { typedef Domain(Op) T; Op op; T sum; accumulate(Op op, const T& x) : op(op), sum(x) { } void operator()(const T& x) { sum = op(sum, x); } }; template requires(BinaryOperation) struct input_type< accumulate, 0 > { typedef Domain(Op) type; }; template requires(Regular(T)) struct identity { T operator()(const T& x) { return x; } }; template requires(Regular(T)) struct input_type, 0> { typedef T type; }; void test_ch_6() { print(" Chapter 6\n"); { int i; i = int(0); increment(i); Assert(i == int(1)); i = int(99); increment(i); Assert(i == int(100)); double x[100]; pointer(double) fx; fx = x; increment(fx); Assert(fx == x + 1); fx = &x[99]; increment(fx); Assert(fx == x + 100); } { typedef int Z; // Integer(Z) Z a[] = {0, 1, 2, 3, 4, 5}; slist l(counted_range(a, sizeof(a)/sizeof(Z))); typedef iterator_type< slist >::type I; typedef distance_type< I >::type N; // Integer(N) slist_iterator f = begin(l) + N(3); Assert(source(f) == Z(3)); Assert(f - begin(l) == N(3)); Assert(begin(l) - begin(l) == N(0)); Assert(for_each(begin(l), end(l), accumulate< plus >(plus(), Z(0))).sum == 15); Assert(find(begin(l), end(l), Z(-1)) == end(l)); Assert(find(begin(l), end(l), Z(5)) == begin(l) + N(5)); Z b[] = {1, 1, 1}; slist lb(counted_range(b, sizeof(b)/sizeof(Z))); Assert(find_not(begin(lb), end(lb), Z(1)) == end(lb)); Assert(find_not(begin(lb), end(lb), Z(0)) == begin(lb)); Assert(find_if(begin(l), end(l), negative) == end(l)); Assert(find_if(begin(l), end(l), lower_bound_predicate< less >(3, less())) == begin(l) + N(3)); Assert(find_if_not(begin(lb), end(lb), positive) == end(lb)); Assert(find_if_not(begin(l), end(l), positive) == begin(l)); Assert(all(begin(lb), end(lb), positive)); Assert(none(begin(l), end(l), negative)); Assert(some(begin(l), end(l), positive)); Assert(not_all(begin(l), end(l), positive)); Assert(all(Z(1), Z(100), positive)); Assert(none(Z(1), Z(100), negative)); Assert(some(Z(0), Z(100), odd)); Assert(not_all(Z(0), Z(100), odd)); Assert(count_if(begin(l), end(l), even, Z(100)) == Z(100) + Z(3)); Assert(count_if(begin(l), end(l), even) == Z(3)); Assert(count_if_not(begin(l), end(l), positive, Z(-1)) == Z(-1) + Z(1)); Assert(count_if_not(begin(l), end(l), positive) == Z(1)); Assert(count(begin(l), end(l), Z(2), Z(100)) == Z(100) + Z(1)); Assert(count(begin(l), end(l), Z(2)) == Z(1)); Assert(count_not(begin(l), end(l), Z(2), Z(100)) == Z(100) + Z(5)); Assert(count_not(begin(l), end(l), Z(2)) == Z(5)); Assert(reduce_nonempty(0, 50, plus(), identity()) == Z(49*50/2)); Assert(reduce_nonempty(0, 1, plus(), identity()) == Z(0)); Assert(reduce_nonempty(begin(l), end(l), plus()) == Z(15)); Assert(reduce_nonempty(begin(l), successor(begin(l)), plus()) == Z(0)); Assert(reduce(0, 0, plus(), identity(), Z(0)) == Z(0)); Assert(reduce(0, 50, plus(), identity(), Z(0)) == Z(49*50/2)); Assert(reduce(0, 1, plus(), identity(), Z(0)) == Z(0)); Assert(reduce(begin(l), begin(l), plus(), Z(0)) == Z(0)); Assert(reduce(begin(l), end(l), plus(), Z(0)) == Z(15)); Assert(reduce(begin(l), successor(begin(l)), plus(), Z(0)) == Z(0)); Z c[] = {0, 1, 0, 2, 0, 3, 0, 4, 0, 5}; slist lc(counted_range(c, sizeof(c)/sizeof(Z))); Assert(reduce_nonzeroes(0, 0, plus(), identity(), Z(0)) == Z(0)); Assert(reduce_nonzeroes(0, 50, plus(), identity(), Z(0)) == Z(49*50/2)); Assert(reduce_nonzeroes(0, 1, plus(), identity(), Z(0)) == Z(0)); Assert(reduce_nonzeroes(begin(lc), begin(lc), plus(), Z(0)) == Z(0)); Assert(reduce_nonzeroes(begin(lc), end(lc), plus(), Z(0)) == Z(15)); Assert(reduce_nonzeroes( begin(lc), successor(begin(lc)), plus(), Z(0)) == Z(0)); Assert(reduce(begin(l), end(l)) == Z(15)); Assert(reduce(begin(lb), end(lb)) == Z(3)); Assert(reduce(begin(lc), end(lc)) == Z(15)); { pair >, iterator_type< slist >::type> p = for_each_n(begin(l), size(l), accumulate< plus >(plus(), Z(0))); Assert(p.m0.sum == 15 && p.m1 == end(l)); } { pair >::type, N> p = find_n(begin(l), size(l), Z(-1)); Assert(p.m0 == end(l) && p.m1 == 0); p = find_n(begin(l), size(l), Z(5)); Assert(p.m0 == begin(l) + N(5) && p.m1 == N(1)); } Assert(find_if( begin(l), end(l), lower_bound_predicate< less >(3, less())) != end(l)); Assert(find_if_unguarded( begin(l), lower_bound_predicate< less >(3, less())) == begin(l) + N(3)); Assert(find_if_not(begin(l), end(l), positive) != end(l)); Assert(find_if_not_unguarded(begin(l), positive) == begin(l)); { pair p0 = find_mismatch(begin(l), end(l), Z(0), Z(6), equal()); Assert(p0.m0 == end(l) && p0.m1 == Z(6)); p0 = find_mismatch(begin(l), end(l), Z(0), Z(7), equal()); Assert(p0.m0 == end(l) && p0.m1 == Z(6)); p0 = find_mismatch(begin(l), end(l), Z(0), Z(4), equal()); Assert(p0.m0 == begin(l) + N(4) && p0.m1 == Z(4)); Z d[] = {0, 1, 2, 3, -4, 5}; slist ld(counted_range(d, sizeof(d)/sizeof(Z))); pair p1 = find_mismatch( begin(l), end(l), begin(ld), end(ld), equal()); Assert(p1.m0 == begin(l) + N(4) && p1.m1 == begin(ld) + N(4)); } { Assert(find_adjacent_mismatch(begin(lb), end(lb), equal()) == end(lb)); Z e[] = {0, 0, 0, 1, 0, 0}; slist le(counted_range(e, sizeof(e)/sizeof(Z))); Assert(find_adjacent_mismatch(begin(le), end(le), equal()) == begin(le) + N(3)); Assert(find_adjacent_mismatch_forward( begin(lb), end(lb), equal()) == end(lb)); Assert(find_adjacent_mismatch_forward( begin(le), end(le), equal()) == begin(le) + N(3)); } Assert(relation_preserving(begin(l), begin(l), less())); Assert(relation_preserving(begin(l), end(l), less())); Assert(strictly_increasing_range(begin(l), begin(l), less())); Assert(strictly_increasing_range(begin(l), end(l), less())); Assert(!strictly_increasing_range(begin(lb), end(lb), less())); Assert(!strictly_increasing_range(begin(lc), end(lc), less())); Assert(relation_preserving( begin(l), end(l), complement_of_converse< less >(less()))); { less lt; complement_of_converse< less > leq(lt); Assert(leq(Z(0), Z(0))); Assert(leq(Z(0), Z(1))); Assert(!leq(Z(1), Z(0))); } Assert(increasing_range(begin(l), begin(l), less())); Assert(increasing_range(begin(l), end(l), less())); Assert(increasing_range(begin(lb), end(lb), less())); Assert(!increasing_range(begin(lc), end(lc), less())); { Z f[] = {0, 0, 1, 1, 2, 3, 5, 5}; slist lf(counted_range(f, sizeof(f)/sizeof(Z))); Assert(!strictly_increasing_range(begin(lf), end(lf), less())); Assert(increasing_range(begin(lf), end(lf), less())); } Assert(partitioned(begin(l), begin(l), negative)); Assert(partitioned(begin(l), end(l), negative)); Assert(!partitioned(begin(l), end(l), zero)); Assert(partitioned(begin(lb), end(lb), even)); Assert(partitioned(begin(lb), end(lb), odd)); Assert(partitioned( begin(l), end(l), lower_bound_predicate< less >(3, less()))); Assert(partitioned( begin(l), end(l), upper_bound_predicate< less >(3, less()))); { Z g[] = {0, 2, 4, 1, 3, 5}; slist lg(counted_range(g, sizeof(g)/sizeof(Z))); Assert(partitioned(begin(lg), end(lg), odd)); Assert(!partitioned(begin(lg), end(lg), even)); } Assert(partition_point_n(begin(lb), size(lb), zero) == end(lb)); Assert(partition_point_n(begin(lb), size(lb), odd) == begin(lb)); Assert(partition_point_n( begin(l), size(l), lower_bound_predicate< less >(3, less())) == begin(l) + N(3)); Assert(partition_point(begin(lb), end(lb), zero) == end(lb)); Assert(partition_point(begin(lb), end(lb), odd) == begin(lb)); Assert(partition_point( begin(l), end(l), lower_bound_predicate< less >(3, less())) == begin(l) + N(3)); { // bidirectional iterators Z h[] = {0, 1, 2, 3, 4, 5}; list ah(counted_range(h, sizeof(h)/sizeof(Z))); Assert(end(ah) - 1 == begin(ah) + (size(ah) - 1)); Assert(find_backward_if(begin(ah), end(ah), zero) == successor(begin(ah))); Assert(find_backward_if(begin(ah), end(ah), negative) == begin(ah)); Assert(find_backward_if_unguarded(end(ah), zero) == begin(ah)); Assert(find_backward_if_not(begin(ah), end(ah), zero) == end(ah)); Assert(find_backward_if_not(begin(ah), end(ah), positive) == successor(begin(ah))); Assert(find_backward_if_not_unguarded(end(ah), positive) == begin(ah)); } { // random access iterators Z h[] = {0, 1, 2, 3, 4, 5}; array ah(counted_range(h, sizeof(h)/sizeof(Z))); Assert(end(ah) - 1 == begin(ah) + (size(ah) - 1)); Assert(find_backward_if(begin(ah), end(ah), zero) == successor(begin(ah))); Assert(find_backward_if(begin(ah), end(ah), negative) == begin(ah)); Assert(find_backward_if_not(begin(ah), end(ah), zero) == end(ah)); Assert(find_backward_if_not(begin(ah), end(ah), positive) == successor(begin(ah))); } } int a[] = {0, 1, 2, 2, 4, 4, 5}; pointer(int) f = a; pointer(int) l = a + sizeof(a) / sizeof(int); distance_type::type n = l - f; pointer(int) m; m = lower_bound_n(f, n, 2, less()); Assert(m == a + 2); m = upper_bound_n(f, n, 2, less()); Assert(m == a + 4); m = lower_bound_n(f, n, 3, less()); Assert(m == a + 4); m = upper_bound_n(f, n, 3, less()); Assert(m == a + 4); { const int N = 9; int s0 = reduce(square_of_i(0), square_of_i(N + 1), plus(), 0); int s1 = reduce_balanced( square_of_i(0), square_of_i(N + 1), plus(), 0); if (verbose) { print(" reduction of thunk iterator\n"); print(" reduce(square(i), 0<=i<10, +) = "); print(s0); print_eol(); print(" reduce(square(i), 0<=i<10, +) = "); print(s1); print_eol(); } Assert(s0 == s1); Assert(s0 == (2 * N * N * N + 3 * N * N + N) / 6); } } // Chapter 7. Coordinate structures template requires(BifurcateCoordinate(C)) struct count_visits { int n_pre, n_in, n_post; count_visits() : n_pre(0), n_in(0), n_post(0) { } void operator()(visit v, C) { switch (v) { case pre: n_pre = successor(n_pre); break; case in: n_in = successor(n_in); break; case post: n_post = successor(n_post); break; } } }; template void algorithms_lexicographical() { print(" lexicographical\n"); print(" ***** to do: parameterize by range type\n"); verify_conservation v(slist_node_count); Z a[] = {0, 1, 2, 3, 4, 5}; typedef pointer(Z) I; I f_a = a; I l_a = f_a + (sizeof(a) / sizeof(Z)); slist la(counted_range(a, sizeof(a) / sizeof(Z))); Z b[] = {0, 1, 2, 3, 4, -5}; I f_b = b; I l_b = f_b + (sizeof(b) / sizeof(Z)); Assert(lexicographical_equivalent(f_a, l_a, begin(la), end(la), equal())); Assert(lexicographical_equal(f_a, l_a, begin(la), end(la))); Assert(!lexicographical_equal(f_b, l_b, begin(la), end(la))); Assert(size(la) == 6 && lexicographical_equal_k<6, I, IteratorType(slist)>()(f_a, begin(la))); typedef DistanceType(I) NP; Assert( lexicographical_compare(f_a, f_a, f_a, l_a, less())); Assert( lexicographical_compare(f_a, f_a + NP(4), f_a, l_a, less())); Assert( lexicographical_compare(f_a, f_a + NP(5), f_a, l_a, less())); Assert(!lexicographical_compare(f_a, f_a + NP(6), f_a, l_a, less())); Assert(!lexicographical_compare(f_a, l_a, f_a, f_a + NP(4), less())); less lt; comparator_3_way< less > comp(lt); Assert(lexicographical_compare_3way(f_a, l_a, f_b, l_b, comp) == -1); Assert(lexicographical_compare_3way(f_a, l_a, f_a, l_a, comp) == 0); Assert(lexicographical_compare_3way(f_b, l_b, f_a, l_a, comp) == 1); Assert( lexicographical_less(f_a, f_a, f_a, l_a)); Assert( lexicographical_less(f_a, f_a + NP(4), f_a, l_a)); Assert( lexicographical_less(f_a, f_a + NP(5), f_a, l_a)); Assert(!lexicographical_less(f_a, f_a + NP(6), f_a, l_a)); Assert(!lexicographical_less(f_a, l_a, f_a, f_a + NP(4))); Assert(!lexicographical_less_k<6, I, I>()(f_a, f_b)); Assert(lexicographical_less_k<6, I, I>()(f_b, f_a)); } template requires(Tree(T) && Tree(T_X)) void algorithms_bifurcate_coordinates() { print(" bifurcate coordinates\n"); typedef CoordinateType(T) C; typedef WeightType(T) N; typedef CoordinateType(T_X) C_X; T t0; T t4(4); T t3_45(3, t4, T(5)); T t2_345_678(2, t3_45, T(6, T(7), T(8))); T t(1, t2_345_678, T(9, T(10, T(11), T(12)), T(13, T(14), T(15)))); if (verbose) { print("t4: "); print(t4); print_eol(); print("t3_45: "); print(t3_45); print_eol(); print("t2_345_678: "); print(t2_345_678); print_eol(); print("t: "); print(t); print_eol(); } C r = begin(t); Assert(!empty(r)); Assert(has_left_successor(r)); C r_l = left_successor(r); Assert(!empty(r_l)); Assert(has_left_successor(r_l)); C r_l_l = left_successor(r_l); Assert(empty(begin(t0))); Assert(weight_recursive(begin(t0)) == N(0)); Assert(weight_recursive(begin(t4)) == N(1)); Assert(weight_recursive(begin(t3_45)) == N(3)); Assert(weight_recursive(begin(t2_345_678)) == N(7)); Assert(weight_recursive(begin(t)) == N(15)); Assert(height_recursive(begin(t0)) == N(0)); Assert(height_recursive(begin(t4)) == N(1)); Assert(height_recursive(begin(t3_45)) == N(2)); Assert(height_recursive(begin(t2_345_678)) == N(3)); Assert(height_recursive(begin(t)) == N(4)); count_visits proc; proc = traverse_nonempty(begin(t), proc); Assert(proc.n_pre == N(15) && proc.n_in == N(15) && proc.n_post == N(15)); C c_r = begin(t3_45); T s4(-4); T s3_45(-3, t4, T(-5)); T s2_345_678(-2, t3_45, T(-6, T(-7), T(-8))); T s(-1, t2_345_678, T(-9, T(-10, T(-11), T(-12)), T(-13, T(-14), T(-15)))); T_X x4('d'); T_X x3_45('c', x4, T_X('e')); T_X x2_345_678('b', x3_45, T_X('f', T_X('g'), T_X('h'))); T_X x('a', x2_345_678, T_X('i', T_X('j', T_X('k'), T_X('l')), T_X('m', T_X('n'), T_X('o')))); Assert(bifurcate_isomorphic_nonempty(begin(t), begin(t))); Assert(bifurcate_isomorphic_nonempty(begin(t), begin(s))); Assert(!bifurcate_isomorphic_nonempty(begin(t), begin(t2_345_678))); Assert(bifurcate_isomorphic_nonempty(begin(t), begin(x))); Assert(bifurcate_isomorphic_nonempty( left_successor(begin(t)), right_successor(begin(x)))); T u(t); if (verbose) { print("u(t): "); print(u); print_eol(); } Assert(t == u); Assert(bifurcate_equivalent_nonempty( begin(t), begin(u), equal())); Assert(!bifurcate_equivalent_nonempty( begin(t), begin(t2_345_678), equal())); // These exercise bifurcate_compare_nonempty Assert(!(t < u) && !(u < t)); Assert(T() < T(0)); Assert(!(T(0) < T())); Assert(T(0) < T(1)); Assert(!(T(1) < T(0))); Assert(T(0, T(1, T(), T()), T()) < T(1, T(), T())); Assert(!(T(1, T(), T()) < T(0, T(1, T(), T()), T()))); Assert(T(0, T(), T()) < T(0, T(0), T())); Assert(!(T(0, T(0), T()) < T(0, T(), T()))); Assert(T(0, T(), T()) < T(0, T(), T(0))); Assert(!(T(0, T(), T(0)) < T(0, T(), T()))); Assert(T(0, T(0), T()) < T(0, T(0), T(0))); Assert(!(T(0, T(0), T(0)) < T(0, T(0), T()))); } template requires(Tree(T) && Tree(T_X) && Integer(ValueType(T)) && Character(ValueType(T_X))) void algorithms_bidirectional_bifurcate_coordinates() { print(" bidirectional bifurcate coordinates\n"); typedef ValueType(T) Z; typedef CoordinateType(T) C; typedef WeightType(T) N; typedef CoordinateType(T_X) C_X; T t0; T t4(4); T t3_45(3, t4, T(5)); T t2_345_678(2, t3_45, T(6, T(7), T(8))); T t(1, t2_345_678, T(9, T(10, T(11), T(12)), T(13, T(14), T(15)))); if (verbose) { print("t4: "); print(t4); print_eol(); print("t3_45: "); print(t3_45); print_eol(); print("t2_345_678: "); print(t2_345_678); print_eol(); print("t: "); print(t); print_eol(); } C root = begin(t); Assert(has_left_successor(root)); C root_l = left_successor(root); Assert(is_left_successor(root_l)); Assert(!is_right_successor(root_l)); Assert(has_right_successor(root)); C root_r = right_successor(root); Assert(is_right_successor(root_r)); Assert(!is_left_successor(root_r)); Assert(has_left_successor(root_l)); C root_l_l = left_successor(root_l); count_visits proc; proc = traverse(begin(t), proc); Assert(proc.n_pre == N(15) && proc.n_in == N(15) && proc.n_post == N(15)); C c_r = begin(t3_45); C c = c_r; visit v(pre); int dh; dh = traverse_step(v, c); Assert(dh == 1 && c == left_successor(c_r) && v == pre); dh = traverse_step(v, c); Assert(dh == 0 && c == left_successor(c_r) && v == in); dh = traverse_step(v, c); Assert(dh == 0 && c == left_successor(c_r) && v == post); dh = traverse_step(v, c); Assert(dh == -1 && c == c_r && v == in); dh = traverse_step(v, c); Assert(dh == 1 && c == right_successor(c_r) && v == pre); dh = traverse_step(v, c); Assert(dh == 0 && c == right_successor(c_r) && v == in); dh = traverse_step(v, c); Assert(dh == 0 && c == right_successor(c_r) && v == post); dh = traverse_step(v, c); Assert(dh == -1 && c == c_r && v == post); Assert(reachable(root, root_l_l)); Assert(!reachable(root_l_l, root)); Assert(weight(begin(t0)) == N(0)); Assert(weight(begin(t4)) == N(1)); Assert(weight(begin(t3_45)) == N(3)); Assert(weight(begin(t2_345_678)) == N(7)); Assert(weight(begin(t)) == N(15)); Assert(height(begin(t0)) == N(0)); Assert(height(begin(t4)) == N(1)); Assert(height(begin(t3_45)) == N(2)); Assert(height(begin(t2_345_678)) == N(3)); Assert(height(begin(t)) == N(4)); proc.n_pre = 0; proc.n_in = 0; proc.n_post = 0; proc = traverse(begin(t0), proc); Assert(proc.n_pre == N(0) && proc.n_in == N(0) && proc.n_post == N(0)); proc = traverse(begin(t), proc); Assert(proc.n_pre == N(15) && proc.n_in == N(15) && proc.n_post == N(15)); T s4(-4); T s3_45(-3, t4, T(-5)); T s2_345_678(-2, t3_45, T(-6, T(-7), T(-8))); T s(-1, t2_345_678, T(-9, T(-10, T(-11), T(-12)), T(-13, T(-14), T(-15)))); T_X x4('d'); T_X x3_45('c', x4, T_X('e')); T_X x2_345_678('b', x3_45, T_X('f', T_X('g'), T_X('h'))); T_X x('a', x2_345_678, T_X('i', T_X('j', T_X('k'), T_X('l')), T_X('m', T_X('n'), T_X('o')))); Assert(bifurcate_isomorphic_nonempty(begin(t), begin(t))); Assert(bifurcate_isomorphic_nonempty(begin(t), begin(s))); Assert(!bifurcate_isomorphic_nonempty(begin(t), begin(t2_345_678))); Assert(bifurcate_isomorphic_nonempty(begin(t), begin(x))); Assert(bifurcate_isomorphic_nonempty( left_successor(begin(t)), right_successor(begin(x)))); Assert(bifurcate_isomorphic(begin(t0), begin(t0))); Assert(!bifurcate_isomorphic(begin(t), begin(t0))); Assert(!bifurcate_isomorphic(begin(t0), begin(t))); Assert(bifurcate_isomorphic(begin(t), begin(t))); Assert(bifurcate_isomorphic(begin(t), begin(s))); Assert(!bifurcate_isomorphic(begin(t), begin(t2_345_678))); Assert(bifurcate_isomorphic(begin(t), begin(x))); Assert(bifurcate_isomorphic( left_successor(begin(t)), right_successor(begin(x)))); T tt(t); Assert(t == tt); Assert(bifurcate_equivalent_nonempty(begin(t), begin(tt), equal())); Assert(!bifurcate_equivalent_nonempty(begin(t), begin(t2_345_678), equal())); Assert(bifurcate_equivalent(begin(t0), begin(t0), equal())); Assert(!bifurcate_equivalent(begin(t), begin(t0), equal())); Assert(!bifurcate_equivalent(begin(t0), begin(t), equal())); Assert(bifurcate_equivalent(begin(t), begin(tt), equal())); Assert(!bifurcate_equivalent(begin(t), begin(t2_345_678), equal())); // Test equivalence for two coordinate types typedef stree U; U u0; U u4(4); U u3_45(3, u4, U(5)); U u2_345_678(2, u3_45, U(6, U(7), U(8))); U u(1, u2_345_678, U(9, U(10, U(11), U(12)), U(13, U(14), U(15)))); Assert( bifurcate_equivalent_nonempty(begin(t), begin(u), equal())); Assert( bifurcate_equivalent_nonempty(begin(t), begin(u), equal())); Assert(!bifurcate_equivalent_nonempty( left_successor(begin(t)), begin(u), equal())); // These exercise bifurcate_less and bifurcate_compare Assert(!(t < tt) && !(tt < t)); Assert(T() < T(0)); Assert(!(T(0) < T())); Assert(T(0) < T(1)); Assert(!(T(1) < T(0))); Assert(T(0, T(1, T(), T()), T()) < T(1, T(), T())); Assert(!(T(1, T(), T()) < T(0, T(1, T(), T()), T()))); Assert(T(0, T(), T()) < T(0, T(0), T())); Assert(!(T(0, T(0), T()) < T(0, T(), T()))); Assert(T(0, T(), T()) < T(0, T(), T(0))); Assert(!(T(0, T(), T(0)) < T(0, T(), T()))); Assert(T(0, T(0), T()) < T(0, T(0), T(0))); Assert(!(T(0, T(0), T(0)) < T(0, T(0), T()))); Assert( bifurcate_shape_compare(begin(t0), begin(t4))); Assert(!bifurcate_shape_compare(begin(t4), begin(t0))); Assert(!bifurcate_shape_compare(left_successor(begin(t)), right_successor(begin(t)))); Assert(!bifurcate_shape_compare(right_successor(begin(t)), left_successor(begin(t)))); Assert( bifurcate_shape_compare(begin(t2_345_678), begin(t))); Assert(!bifurcate_shape_compare(begin(t), begin(t2_345_678))); } template requires(Integer(Z) && Regular(X)) void test_ch_7() { print(" Chapter 7\n"); algorithms_lexicographical(); verify_conservation vs(stree_node_count); verify_conservation v(tree_node_count); algorithms_bifurcate_coordinates< stree, stree >(); algorithms_bifurcate_coordinates< tree, tree >(); algorithms_bidirectional_bifurcate_coordinates< tree, tree >(); } // Chapter 8. Coordinates with mutable successors template requires(List(L)) void algorithms_linked() { typedef ValueType(L) Z; typedef IteratorType(L) I; typedef DistanceType(I) N; const int n = 500; array a(n, n, Z(0)); typedef IteratorType(array) Ia; Ia f = begin(a); iota(n, f); Ia t; advance_tail(t, f); Assert(t == begin(a) && f == successor(t)); // ***** to do: linker_to_tail L la(a); L lb; Assert(size(lb) == 0); I last = find_last(begin(la), end(la)); Assert(source(last) == predecessor(n) && successor(last) == end(la)); // ***** to do: split_linked, combine_linked_nonempty // ***** to do: linker_to_head // ***** rewrite these tests in terms of procedures on raw coordinates ????? reverse(la); Assert(size(la) == n); equal_iota_reverse(begin(la), end(la)); reverse(la); Assert(size(la) == n); Assert(equal_iota(begin(la), end(la))); partition(la, lb, even); Assert(size(la) + size(lb) == n); Assert(all(begin(la), end(la), odd)); Assert(all(begin(lb), end(lb), even)); merge(la, lb, less()); Assert(size(la) == n && empty(lb)); Assert(equal_iota(begin(la), end(la))); reverse(la); sort(la, less()); Assert(size(la) == n); Assert(equal_iota(begin(la), end(la))); } template requires(Integer(Z)) void algorithms_linked_iterators() { print(" linked iterators\n"); verify_conservation vs(slist_node_count); verify_conservation v(list_node_count); algorithms_linked< slist >(); algorithms_linked< list >(); } template requires(Readable(C) && AdditiveMonoid(ValueType(C))) struct sum_source { typedef ValueType(C) T; T sum; sum_source() : sum(T(0)) { } void operator()(C c) { sum = sum + source(c); } }; template requires(Readable(C) && AdditiveMonoid(ValueType(C))) struct input_type< sum_source, 0 > { typedef C type; }; template requires(Integer(Z)) void algorithms_linked_bifurcate_coordinates() { print(" linked bifurcate coordinates\n"); verify_conservation v(stree_node_count); typedef stree T; typedef CoordinateType(T) C; typedef WeightType(C) N; // ***** to do: test tree_rotate on single-node tree { T t0_12(0, T(1), T(2)); C root = begin(t0_12); N n = weight_recursive(root); Assert(n == 3); C null = C(); // empty(null) C l = left_successor(root); C r = right_successor(root); C curr = root; C prev = null; tree_rotate(curr, prev); Assert(left_successor(root) == r && right_successor(root) == null && curr == l && prev == root); tree_rotate(curr, prev); tree_rotate(curr, prev); tree_rotate(curr, prev); tree_rotate(curr, prev); tree_rotate(curr, prev); tree_rotate(curr, prev); tree_rotate(curr, prev); tree_rotate(curr, prev); Assert(curr == root && prev == null); Assert(weight_recursive(root) == n && source(root) == Z(0) && source(left_successor(root)) == Z(1) && source(right_successor(root)) == Z(2)); // ***** to do: more verification of individual tree_rotate steps } T t4(4); T t3_45(3, t4, T(5)); T t2_345_678(2, t3_45, T(6, T(7), T(8))); T t1__15(1, t2_345_678, T(9, T(10, T(11), T(12)), T(13, T(14), T(15)))); // weight_rotating exercises counter Assert(weight_rotating(begin(t3_45)) == N(3)); Assert(weight_rotating(begin(t1__15)) == N(15)); // traverse_phased_rotating exercises phased_applicator Assert(traverse_phased_rotating( begin(t1__15), 0, sum_source() ).sum == N(120)); } template requires(Integer(Z)) void test_ch_8() { print(" Chapter 8\n"); // ***** to do: predicate_source // ***** to do: relation_source algorithms_linked_iterators(); algorithms_linked_bifurcate_coordinates(); } // Chapter 9. Copying template requires(DynamicSequence(S)) void extend_sequence_n(S& s, DistanceType(IteratorType(S)) n, const ValueType(S)& x) { typedef after AP; while (count_down(n)) AP ap = insert(AP(s, begin(s)), x); } template requires(Readable(I) && Iterator(I) && Integer(ValueType(I))) bool equal_iota_reverse(I f, I l) { ValueType(I) n(l - f); while (f != l) { n = predecessor(n); if (source(f) != n) return false; f = successor(f); } return true; } template requires(Regular(T)) struct equal_to_x { T x; equal_to_x(const T& x) : x(x) { } bool operator()(const T& y) { return x == y; } }; template requires(Regular(T)) struct input_type< equal_to_x, 0 > { typedef T type; }; template requires(Mutable(I0) && ForwardIterator(I0) && Mutable(I1) && ForwardIterator(I1) && ValueType(I0) == ValueType(I1) && Integer(ValueType(I0))) void algorithms_copy_forward(I0 f0, I0 l0, I1 f1, I1 l1) { // Precondition: $l0 - f0 <= l1 - f1$ typedef ValueType(I0) T; typedef DistanceType(I0) N0; typedef DistanceType(I1) N1; N0 n = l0 - f0; N0 n_over_2(half_nonnegative(n)); Assert(n <= N0(l1 - f1)); // test fill_step (used for other tests) { { I1 f = f1; while (f != l1) { sink(f) = 0; f = successor(f); } } I1 f_o = f1; fill_step(f_o, -1); Assert(f_o == successor(f1)); Assert(source(f1) == -1); } // test fill { { I1 f = f1; while (f != l1) { sink(f) = T(-1); f = successor(f); } } I1 l_o = f1 + N1(n - N0(2)); I1 m1 = fill(successor(f1), l_o, T(0)); Assert(m1 == l_o); Assert(all(successor(f1), m1, equal_to_x(T(0)))); Assert(source(f1) == -1 && source(f1 + N1(n - N0(1))) == T(-1)); } // test fill_n { { I1 f = f1; while (f != l1) { sink(f) = T(-1); f = successor(f); } } N1 n1 = N1(n - N0(2)); I1 m1 = fill_n(successor(f1), n1, T(0)); Assert(m1 == successor(f1) + n1); Assert(all(successor(f1), m1, equal_to_x(T(0)))); Assert(source(f1) == -1 && source(f1 + N1(n - N0(1))) == T(-1)); } // test copy_step { I0 f_i = f0; iota(n, f0); I1 f_o = f1; fill_n(f1, l1 - f1, -1); copy_step(f_i, f_o); Assert(f_i == successor(f0)); Assert(f_o == successor(f1)); Assert(source(f1) == source(f0)); } // test copy, not aliased { iota(n, f0); I0 m0 = f0 + (n - N0(2)); fill_n(f1, n, -1); I1 m1 = copy(f0, m0, successor(f1)); Assert(m1 == f1 + N1(n - N0(1))); Assert(lexicographical_equal(f0, m0, successor(f1), m1)); Assert(source(f1) == -1 && source(f1 + (n - N0(1))) == -1); } // test copy, aliased backward { iota(n, f0); I1 m1 = copy(f0 + N0(2), l0, f1); // save original values I0 m0 = copy(f0 + N0(2), l0, f0); Assert(m0 == f0 + (n - N0(2))); Assert(lexicographical_equal(f0, m0, f1, m1)); Assert(source(m0) == m0 - f0 && source(successor(m0)) == successor(m0 - f0)); } // test copy_bounded { iota(n, f0); fill_n(f1, n, -1); pair pio = copy_bounded(f0, l0, f1, f1 + N1(n_over_2)); Assert(pio.m0 == f0 + n_over_2 && pio.m1 == f1 + N1(n_over_2)); Assert(lexicographical_equal(f0, pio.m0, f1, pio.m1)); Assert(source(f1 + N1(successor(n_over_2))) == -1); } // test count_down { N0 i; N0 n; n = N0(5); i = N0(0); while (count_down(n)) i = successor(i); Assert(i == N0(5)); n = N0(0); i = N0(0); while (count_down(n)) i = successor(i); Assert(i == N0(0)); } // test copy_n { N0 n0 = (n - N0(2)); fill_n(f1, n, -1); pair pio = copy_n(f0, n0, successor(f1)); Assert(pio.m0 == f0 + n0); Assert(pio.m1 == f1 + N1(n - N0(1))); Assert(lexicographical_equal(f0, f0 + n0, successor(f1), pio.m1)); Assert(source(f1) == -1 && source(f1 + (n - N0(1))) == -1); } // test copy_select { iota(n, f0); predicate_source< I0, bool (*)(const T&) > es(even); I1 m1 = copy_select(f0, l0, f1, es); Assert(m1 - f1 == count_if(f0, l0, even)); Assert(all(f1, m1, even)); } // test copy_if { iota(n, f0); I1 m1 = copy_if(f0, l0, f1, odd); Assert(m1 - f1 == count_if(f0, l0, odd)); Assert(all(f1, m1, odd)); } // test split_copy { iota(n, f0); I0 f_f = f0; I1 f_t = f1; predicate_source< I0, bool (*)(const T&) > es(even); N0 n_f = count_if(f0, l0, odd); N1 n_t = count_if(f0, l0, even); pair pft = split_copy(f0, l0, f_f, f_t, es); Assert(pft.m0 - f_f == n_f); Assert(pft.m1 - f_t == n_t); Assert(all(f_f, pft.m0, odd)); Assert(all(f_t, pft.m1, even)); } // test split_copy_n { iota(n, f0); I0 f_f = f0; I1 f_t = f1; predicate_source< I0, bool (*)(const T&) > es(even); N0 n_f = count_if(f0, l0, odd); N1 n_t = count_if(f0, l0, even); pair pft = split_copy_n(f0, n, f_f, f_t, es); Assert(pft.m0 - f_f == n_f); Assert(pft.m1 - f_t == n_t); Assert(all(f_f, pft.m0, odd)); Assert(all(f_t, pft.m1, even)); } // test partition_copy { iota(n, f0); I0 f_f = f0; I1 f_t = f1; N0 n_f = count_if(f0, l0, even); N1 n_t = count_if(f0, l0, odd); pair pft = partition_copy(f0, l0, f_f, f_t, odd); Assert(pft.m0 - f_f == n_f); Assert(pft.m1 - f_t == n_t); Assert(all(f_f, pft.m0, even)); Assert(all(f_t, pft.m1, odd)); } // test partition_copy_n { iota(n, f0); I0 f_f = f0; I1 f_t = f1; N0 n_f = count_if(f0, l0, even); N1 n_t = count_if(f0, l0, odd); pair pft = partition_copy_n(f0, n, f_f, f_t, odd); Assert(pft.m0 - f_f == n_f); Assert(pft.m1 - f_t == n_t); Assert(all(f_f, pft.m0, even)); Assert(all(f_t, pft.m1, odd)); } // test combine_copy { I0 m0 = iota(n_over_2, f0); iota(n - n_over_2, m0); less lt; relation_source< I0, I0, less > lts(lt); I1 m1 = combine_copy(f0, m0, m0, l0, f1, lts); Assert(m1 - f1 == n); Assert(increasing_range(f1, m1, less())); } // test combine_copy_n { I0 m0 = iota(n_over_2, f0); iota(n - n_over_2, m0); less lt; relation_source< I0, I0, less > lts(lt); triple t = combine_copy_n(f0, m0 - f0, m0, l0 - m0, f1, lts); Assert(t.m0 == m0 && t.m1 == l0 && t.m2 - f1 == n); Assert(increasing_range(f1, t.m2, less())); } // test merge_copy { I0 m0 = iota(n_over_2, f0); iota(n - n_over_2, m0); less lt; I1 m1 = merge_copy(f0, m0, m0, l0, f1, lt); Assert(m1 - f1 == n); Assert(increasing_range(f1, m1, less())); } // test exchange_values, swap_step { I0 f_0 = f0; I1 f_1 = f1; sink(f_0) = 137; sink(f_1) = -99; exchange_values(f0, f1); Assert(f_0 == f0 && f_1 == f1); Assert(source(f0) == -99 && source(f1) == 137); swap_step(f_0, f_1); Assert(f_0 == successor(f0) && f_1 == successor(f1)); Assert(source(f0) == 137 && source(f1) == -99); } // test swap_ranges { iota(n, f0); fill_n(f1, n, T(-1)); I1 m1 = swap_ranges(f0, l0, f1); Assert(m1 == f1 + N1(n)); Assert(equal_iota(f1, m1)); Assert(all(f0, l0, equal_to_x(-1))); } // test swap_ranges_ bounded { iota(n, f0); N1 n1(n_over_2); fill_n(f1, n1, T(-1)); pair p01 = swap_ranges_bounded(f0, l0, f1, f1 + n1); Assert(p01.m0 == f0 + N0(n1)); Assert(p01.m1 == f1 + n1); Assert(equal_iota(f1, p01.m1)); Assert(all(f0, p01.m0, equal_to_x(-1))); } // test swap_ranges_n { iota(n, f0); fill_n(f1, n, T(-1)); pair p01 = swap_ranges_n(f0, f1, n); Assert(p01.m0 == f0 + n); Assert(p01.m1 == f1 + N1(n)); Assert(equal_iota(f1, p01.m1)); Assert(all(f0, l0, equal_to_x(-1))); } } template requires(Readable(I0) && BidirectionalIterator(I0) && Writable(I1) && BidirectionalIterator(I1) && ValueType(I0) == ValueType(I1)) void algorithms_copy_backward(I0 f0, I0 l0, I1 f1, I1 l1) { // Precondition: $l0 - f0 <= l1 - f1$ typedef ValueType(I0) T; typedef DistanceType(I0) N0; typedef DistanceType(I1) N1; N0 n = l0 - f0; N0 n_over_2(half_nonnegative(n)); Assert(n <= N0(l1 - f1)); // test copy_backward_step { I0 l_i = l0; iota(n, f0); I1 l_o = l1; fill_n(f1, l1 - f1, -1); copy_backward_step(l_i, l_o); Assert(l_i == predecessor(l0)); Assert(l_o == predecessor(l1)); Assert(source(predecessor(l1)) == source(predecessor(l0))); } // test copy_backward { I0 m0 = l0 - (n - N0(2)); fill_n(f1, n, -1); I1 m1 = copy_backward(m0, l0, predecessor(l1)); Assert(m1 == l1 - N1(n - N0(1))); Assert(lexicographical_equal(m0, l0, m1, predecessor(l1))); Assert(source(predecessor(m1)) == -1 && source(predecessor(l1)) == -1); } // test copy_backward_n { const N0 n_minus_2 = n - N0(2); I0 m0 = l0 - n_minus_2; fill_n(f1, n, -1); pair p = copy_backward_n(l0, n_minus_2, predecessor(l1)); Assert(p.m1 == l1 - N1(n - N0(1))); Assert(lexicographical_equal(m0, l0, p.m1, predecessor(l1))); Assert(source(predecessor(p.m1)) == -1 && source(predecessor(l1)) == -1); } // test combine_copy_backward { I0 m0 = iota(n_over_2, f0); iota(n - n_over_2, m0); less lt; relation_source< I0, I0, less > lts(lt); I1 m1 = combine_copy_backward(f0, m0, m0, l0, l1, lts); Assert(l1 - m1 == n); Assert(increasing_range(m1, l1, less())); } // test combine_copy_backward_n { I0 m0 = iota(n_over_2, f0); iota(n - n_over_2, m0); less lt; relation_source< I0, I0, less > lts(lt); triple t = combine_copy_backward_n(m0, m0 - f0, l0, l0 - m0, l1, lts); Assert(t.m0 == f0 && t.m1 == m0 && l1 - t.m2 == n); Assert(increasing_range(t.m2, l1, less())); } // test merge_copy_backward { I0 m0 = iota(n_over_2, f0); iota(n - n_over_2, m0); less lt; I1 m1 = merge_copy_backward(f0, m0, m0, l0, l1, lt); Assert(l1 - m1 == n); Assert(increasing_range(m1, l1, less())); } // test merge_copy_backward_n { I0 m0 = iota(n_over_2, f0); iota(n - n_over_2, m0); less lt; triple t = merge_copy_backward_n(m0, m0 - f0, l0, l0 - m0, l1, lt); Assert(t.m0 == f0 && t.m1 == m0 && l1 - t.m2 == n); Assert(increasing_range(t.m2, l1, less())); } } template requires(Mutable(I0) && BidirectionalIterator(I0) && Mutable(I1) && BidirectionalIterator(I1) && ValueType(I0) == ValueType(I1)) void algorithms_copy_reverse(I0 f0, I0 l0, I1 f1, I1 l1) { // Precondition: $l0 - f0 == l1 - f1$ typedef ValueType(I0) T; typedef DistanceType(I0) N0; typedef DistanceType(I1) N1; N0 n = l0 - f0; N0 n_over_2(half_nonnegative(n)); Assert(n == N0(l1 - f1)); // test reverse_copy_step { if (verbose) print(" reverse_copy_step\n"); I0 l_i = l0; iota(n, f0); I1 f_o = f1; fill_n(f1, l1 - f1, -1); reverse_copy_step(l_i, f_o); Assert(l_i == predecessor(l0)); Assert(f_o == successor(f1)); Assert(source(f1) == source(predecessor(l0))); } // test reverse_copy_backward_step { if (verbose) print(" reverse_copy_backward_step\n"); I0 f_i = f0; iota(n, f0); I1 l_o = l1; fill_n(f1, l1 - f1, -1); reverse_copy_backward_step(f_i, l_o); Assert(f_i == successor(f0)); Assert(l_o == predecessor(l1)); Assert(source(predecessor(l1)) == source(f0)); } // test reverse_copy { if (verbose) print(" reverse_copy\n"); iota(n, f0); fill_n(f1, l1 - f1, -1); I1 f_o = successor(f1); I1 l_o = reverse_copy(f0, l0 - N0(2), f_o); Assert(l_o == predecessor(l1)); N1 n_o(n - N0(2)); while (count_down(n_o)) { Assert(source(f_o) == n_o); f_o = successor(f_o); } Assert(source(f1) == -1 && source(predecessor(l1)) == -1); } // test reverse_copy_backward { if (verbose) print(" reverse_copy_backward\n"); iota(n, f0); fill_n(f1, n, -1); I1 l_o = predecessor(l1); I1 f_o = reverse_copy_backward(f0, l0 - N0(2), l_o); Assert(f_o == successor(f1)); N1 n_o(n - N0(2)); while (count_down(n_o)) { Assert(source(f_o) == n_o); f_o = successor(f_o); } Assert(source(f1) == -1 && source(predecessor(l1)) == -1); } // test reverse_swap_step { if (verbose) print(" reverse_swap_step\n"); I0 l_0 = l0; I1 f_1 = f1; sink(predecessor(l_0)) = 137; sink(f_1) = -99; reverse_swap_step(l_0, f_1); Assert(l_0 == predecessor(l0) && f_1 == successor(f1)); Assert(source(predecessor(l0)) == -99 && source(f1) == 137); } // test reverse_swap_ranges { if (verbose) print(" reverse_swap_ranges\n"); iota(n, f0); fill_n(f1, n, T(-1)); I1 m1 = reverse_swap_ranges(f0, l0, f1); Assert(m1 == f1 + N1(n)); Assert(equal_iota_reverse(f1, m1)); Assert(all(f0, l0, equal_to_x(-1))); } // test reverse_swap_ranges_bounded { if (verbose) print(" reverse_swap_ranges_bounded\n"); I0 m0 = f0 + n_over_2; iota(n_over_2, f0); fill(f1, l1, T(-1)); pair p01 = reverse_swap_ranges_bounded(f0, m0, f1, l1); Assert(p01.m0 == f0); Assert(p01.m1 == f1 + N1(n_over_2)); Assert(equal_iota_reverse(f1, p01.m1)); Assert(all(f0, m0, equal_to_x(-1))); } // test reverse_swap_ranges_n { if (verbose) print(" reverse_swap_ranges_n\n"); iota(n, f0); fill_n(f1, n, T(-1)); pair p01 = reverse_swap_ranges_n(l0, f1, n); Assert(p01.m0 == f0); Assert(p01.m1 == f1 + N1(n)); Assert(equal_iota_reverse(f1, p01.m1)); Assert(all(f0, l0, equal_to_x(-1))); } } template requires(Regular(T)) void test_ch_9() { print(" Chapter 9\n"); print(" copy/split/combine/swap\n"); const int k = 50; array_k ca; array da(k, k, T()); slist l; print(" ***** replace list with slist and list ?????\n"); int n = k; extend_sequence_n(l, n, T(-1)); Assert(size(ca) == k && size(da) == k && size(l) == k); print(" forward"); print_eol(); print(" ***** to do: split into iterator and forward iterator\n"); print(" ***** to do: split into readable/writable/mutable ?????\n"); algorithms_copy_forward(begin(ca), end(ca), begin(da), end(da)); algorithms_copy_forward(begin(ca), end(ca), begin(l), end(l)); algorithms_copy_forward(begin(da), end(da), begin(ca), end(ca)); algorithms_copy_forward(begin(da), end(da), begin(l), end(l)); algorithms_copy_forward(begin(l), end(l), begin(ca), end(ca)); algorithms_copy_forward(begin(l), end(l), begin(da), end(da)); print(" ***** to do: various iterator types for split/combine/partition/merge\n"); print(" ***** to do: copy_bounded/copy_n backward overlapped\n"); print(" backward"); print_eol(); algorithms_copy_backward(begin(ca), end(ca), begin(da), end(da)); algorithms_copy_backward(begin(da), end(da), begin(ca), end(ca)); print(" ***** to do: copy_backward forward overlapped\n"); print(" reverse\n"); print(" ***** to do: split into finer iterator concept combinations\n"); print(" ***** to do: split into readable/writable/mutable ?????\n"); algorithms_copy_reverse(begin(ca), end(ca), begin(da), end(da)); algorithms_copy_reverse(begin(da), end(da), begin(ca), end(ca)); } // Chapter 10. Rearrangements template requires(RandomAccessIterator(I)) struct successor_cyclic { I f; I l; successor_cyclic(I f, I l) : f(f), l(l) { } I operator()(I i) { i = successor(i); if (i == l) i = f; return i; } }; void algorithm_cycle_to() { typedef int N; const int k = 17; array_k a; typedef iterator_type< array_k >::type I; I f = begin(a); I l = end(a); iota(k, f); cycle_to(f, successor_cyclic(f, l)); Assert(source(f) == predecessor(k)); Assert(equal_iota(successor(f), l)); } template requires(Regular(T) && Integer(N)) void type_temporary_buffer(N n) { { temporary_buffer b(n); DistanceType(pointer(T)) m = size(b); Assert(0 < m && m <= n); if (verbose) { print("size(temporary_buffer("); print(n); print(") = "); print(m); print(" where sizeof(T) = "); print(sizeof(T)); print_eol(); } } } void algorithms_reverse() { typedef int T; const int k = 50; array_k ca; // typedef DistanceType(IteratorType(array)) N; typedef ptrdiff_t N; array da(N(k), N(k), T(0)); slist l; extend_sequence_n(l, k, T(-1)); iota(k, begin(ca)); iota(k, begin(ca)); reverse_n_indexed(begin(ca), size(ca)); equal_iota_reverse(begin(ca), end(ca)); iota(k, begin(ca)); reverse_bidirectional(begin(ca), end(ca)); equal_iota_reverse(begin(ca), end(ca)); iota(k, begin(ca)); reverse_n_bidirectional(begin(ca), end(ca), size(ca)); equal_iota_reverse(begin(ca), end(ca)); iota(k, begin(l)); reverse_n_with_buffer(begin(l), k, begin(ca)); equal_iota_reverse(begin(l), end(l)); iota(k, begin(l)); reverse_n_forward(begin(l), k); equal_iota_reverse(begin(l), end(l)); iota(k, begin(l)); reverse_n_adaptive(begin(l), k, begin(ca), half_nonnegative(k)); equal_iota_reverse(begin(l), end(l)); iota(k, begin(l)); reverse_n_adaptive(begin(l), k, begin(ca), half_nonnegative(k)); equal_iota_reverse(begin(l), end(l)); iota(k, begin(da)); reverse_indexed(begin(da), end(da)); equal_iota_reverse(begin(da), end(da)); iota(k, begin(l)); reverse_n_with_temporary_buffer(begin(l), k); equal_iota_reverse(begin(l), end(l)); } typedef pointer(int) int_pointer; template requires(IteratorConcept(C)) void algorithms_rotate_Concept(int_pointer a, int n) { Assert(n != 0); fill_n(a, n, int(7)); int_pointer f = a; int_pointer l = f + n; iota(n, f); if (verbose) { print(" Initial a: "); print_range(a, a+n); print_eol(); } int_pointer c = successor(f); while (c != l) { Assert(f != c && c != l); // guard required since we're invoking "inner" versions rotate_nontrivial(f, c, l, C()); c = successor(c); } if (verbose) { print(" After rotating a: "); print_range(a, a+n); print_eol(); } if (even(n)) for (int i = 0; i < n; ++i) Assert(source(f + i) == (i + n / 2) % n); else for (int i = 0; i < n; ++i) Assert(source(f + i) == i); } void algorithm_rotate_forward_annotated(int_pointer a, int n) { Assert(n != 0); fill_n(a, n, int(7)); int_pointer f = a; int_pointer l = f + n; iota(n, f); if (verbose) { print(" Initial a: "); print_range(a, a+n); print_eol(); } int_pointer c = successor(f); while (c != l) { Assert(f != c && c != l); // guard required since we're invoking "inner" versions rotate_forward_annotated(f, c, l); c = successor(c); } if (verbose) { print(" After rotating a: "); print_range(a, a+n); print_eol(); } if (even(n)) for (int i = 0; i < n; ++i) Assert(source(f + i) == (i + n / 2) % n); else for (int i = 0; i < n; ++i) Assert(source(f + i) == i); } template requires(ForwardIterator(I) && ForwardIterator(B)) void algorithms_rotate_Concept_with_buffer(I f, DistanceType(I) n, B f_b, I (*algo)(I, I, I, B)) { Assert(n != 0); fill_n(f, n, int(7)); I l = f + n; iota(n, f); if (verbose) { print(" Initial range: "); print_range(f, l); print_eol(); } int_pointer c = successor(f); while (c != l) { Assert(f != c && c != l); // guard required since we're invoking "inner" versions algo(f, c, l, f_b); c = successor(c); } if (verbose) { print(" After rotating range: "); print_range(f, l); print_eol(); } if (even(n)) for (int i = 0; i < n; ++i) Assert(source(f + i) == (i + half_nonnegative(n)) % n); else for (int i = 0; i < n; ++i) Assert(source(f + i) == i); } template requires(Integer(N)) void algorithm_rotate_partial(N n) { Assert(n > N(1)); array a(twice(n), twice(n), N(-1)); typedef IteratorType(array) I; I f = begin(a) + n / N(4); I l = f + n; I m = f + 1; while (m != l) { iota(n, f); I m_prime = rotate_partial_nontrivial(f, m, l); Assert(source(predecessor(f)) == N(-1) && source(l) == N(-1)); Assert(m_prime + (m - f) == l); Assert(equal_iota(f, m_prime, m - f)); DistanceType(I) k = (l - f) % (m - f); rotate(m_prime, l - k, l); Assert(equal_iota(m_prime, l)); m = successor(m); } } void algorithms_rotate() { print(" rotate\n"); // Directly or indirectly tests these algorithms: // cycle_from // k_rotate_from_permutation_random_access // k_rotate_from_permutation_indexed // rotate_cycles // rotate_indexed_nontrivial // rotate_random_access_nontrivial // rotate_bidirectional_nontrivial // rotate_forward_annotated // rotate_forward_step // rotate_forward_nontrivial // rotate_with_buffer_nontrivial // rotate_with_buffer_backward_nontrivial typedef pointer(int) I; int a[8]; int b[8]; for (int n = 6; n < 8; ++n) { algorithm_rotate_forward_annotated(a, n); algorithms_rotate_Concept(a, n); algorithms_rotate_Concept(a, n); algorithms_rotate_Concept(a, n); algorithms_rotate_Concept(a, n); algorithms_rotate_Concept_with_buffer( a, n, b, rotate_with_buffer_nontrivial); algorithms_rotate_Concept_with_buffer( a, n, b, rotate_with_buffer_backward_nontrivial); } int n = 41; while (n < 50) { algorithm_rotate_partial(n); n = n + 2; } } void test_ch_10() { print(" Chapter 10\n"); algorithm_cycle_to(); type_temporary_buffer< char >(1000); type_temporary_buffer< char >(100000); type_temporary_buffer< array_k<10,char> >(1000); type_temporary_buffer< array_k<10,char> >(100000); algorithms_reverse(); algorithms_rotate(); } // Chapter 11. Partition and merging void algorithms_reduce_balanced() { // tests counter_machine, add_to_counter, transpose_operation, reduce_nonzeroes typedef int Z; // Integer(Z) Z a[] = {0, 1, 2, 3, 4, 5}; slist l(counted_range(a, sizeof(a)/sizeof(Z))); Assert(reduce_balanced(0, 0, plus(), identity(), Z(0)) == Z(0)); Assert(reduce_balanced(0, 50, plus(), identity(), Z(0)) == Z(49*50/2)); Assert(reduce_balanced(0, 1, plus(), identity(), Z(0)) == Z(0)); Assert(reduce_balanced(begin(l), begin(l), plus(), Z(0)) == Z(0)); Assert(reduce_balanced(begin(l), end(l), plus(), Z(0)) == Z(15)); Assert(reduce_balanced(begin(l), successor(begin(l)), plus(), Z(0)) == Z(0)); } bool even_int(int x) { return even(x); } bool odd_int(int x) { return odd(x); } typedef bool (*int_pred_type)(int); struct partition_algorithm_tester { typedef pointer(int) I; typedef distance_type::type N; const pointer(char) name; array_k<6, int> a; I f; I l; N n; bool (*p)(int); slist b; I m_potential; partition_algorithm_tester(const pointer(char) name) : name(name), a(), f(begin(a)), l(end(a)), n(l - f), p(even_int), b(a) { Assert(size(b) == n); iota(int(n), f); m_potential = potential_partition_point(f, l, even); if (verbose) { print(" Before "); print(name); print(" partition with even: "); print_range(f, l); print_eol(); } } void validate(I m) { if (verbose) { print(" After "); print(name); print(" partition with even: "); print_range(f, l); print_eol(); } Assert(m_potential == m); Assert(partitioned(f, l, even)); Assert(partitioned_at_point(f, m, l, even)); Assert(m == partition_point(f, l, even)); } void validate_false(I m) { if (verbose) { print(" After "); print(name); print(" partition with even: "); print_range(f, l); print_eol(); } Assert(m_potential == m); Assert(none(f, m, p)); } }; void algorithms_partition() { { int a[] = {0, 2, 4, 1, 3, 5}; pointer(int) f = a; pointer(int) l = a + sizeof(a) / sizeof(int); // exercise pointer(int) m = potential_partition_point(f, l, odd); // exercise Assert(partitioned_at_point(f, m, l, odd)); } { // book partition_algorithm_tester t("semistable"); t.validate(partition_semistable(t.f, t.l, t.p)); } { // exercise partition_algorithm_tester t("remove_if"); t.validate_false(remove_if(t.f, t.l, t.p)); } { // book partition_algorithm_tester t("bidirectional"); t.validate(partition_bidirectional(t.f, t.l, t.p)); } { // could have been exercise partition_algorithm_tester t("indexed"); t.validate(partition_indexed(t.f, t.l, t.p)); } { // exercise partition_algorithm_tester t("forward"); t.validate(partition_forward(t.f, t.l, t.p)); } { // exercise partition_algorithm_tester t("single_cycle"); t.validate(partition_single_cycle(t.f, t.l, t.p)); } { // exercise partition_algorithm_tester t("sentinel"); t.validate(partition_sentinel(t.f, t.l, t.p)); } // ***** to do: exercise - single_cycle_sentinel { // book partition_algorithm_tester t("stable_with_buffer"); t.validate(partition_stable_with_buffer(t.f, t.l, begin(t.b), t.p)); } { // book // uses partition_stable_singleton, partition_stable_combine partition_algorithm_tester t("stable_n_nonempty"); typedef partition_algorithm_tester::I I; pair p = partition_stable_n_nonempty(t.f, t.l - t.f, t.p); Assert(p.m1 == t.l); t.validate(p.m0); } { // book partition_algorithm_tester t("stable_n"); typedef partition_algorithm_tester::I I; pair p; p = partition_stable_n(t.f, 0, t.p); Assert(p.m0 == t.f && p.m1 == t.f); p = partition_stable_n(t.f, t.n, t.p); Assert(p.m1 == t.l); t.validate(p.m0); } { // additional partition_algorithm_tester t("advanced stable_n"); typedef partition_algorithm_tester::I I; pair p; p = advanced_partition_stable_n(t.f, 0, t.p); Assert(p.m0 == t.f && p.m1 == t.f); p = advanced_partition_stable_n(t.f, t.n, t.p); Assert(p.m1 == t.l); t.validate(p.m0); } { // for completeness partition_algorithm_tester t("stable"); t.validate(partition_stable(t.f, t.l, t.p)); } { // book partition_algorithm_tester t("stable iterative"); t.validate(partition_stable_iterative(t.f, t.l, t.p)); } } char force_lower(char a) { if ('A' <= a && a <= 'Z') return 'a' + (a - 'A'); return a; } struct less_ignoring_case { bool operator()(char a, char b) const { return force_lower(a) < force_lower(b); } }; template<> struct input_type { typedef char type; }; struct equal_ignoring_case { bool operator()(char a, char b) const { return force_lower(a) == force_lower(b); } }; template<> struct input_type { typedef char type; }; int size_unguarded(const pointer(char) a) { int n(0); while (source(a) != char(0)) { n = successor(n); a = successor(a); } return n; } const pointer(char) begin(const pointer(char) a) { return a; } const pointer(char) end(const pointer(char) a) { return begin(a) + size_unguarded(a); } template requires(WrappedMerger(M) && Relation(R) && Domain(R) == char && Relation(E) && Domain(E) == char) struct merge_case { M merger; R r; E e; bool commutative; merge_case(M merger, R r, E e, bool commutative) : merger(merger), r(r), e(e), commutative(commutative) { // Precondition: $\property{weak\_ordering}(r) // Precondition: $\property{equivalence}(e) } void subcase( const pointer(char) a, int n_a, const pointer(char) b, int n_b, const pointer(char) c, int n_c) { array tmp(n_c, n_c, char(0)); pointer(char) f_ab = begin(tmp); pointer(char) m_ab = copy_n(begin(a), n_a, f_ab).m1; pointer(char) l_ab = copy_n(begin(b), n_b, m_ab).m1; Assert(l_ab == end(tmp)); merger(f_ab, n_a, m_ab, n_b, r); Assert(lexicographical_equivalent(f_ab, l_ab, begin(c), end(c), e)); if (verbose) { print(" "); print(a); print(" merge "); print(b); print(" equiv "); print(c); print_eol(); } } void operator()(const pointer(char) a, const pointer(char) b, const pointer(char) c) { int n_a = size_unguarded(a) ; int n_b = size_unguarded(b); int n_c = size_unguarded(c); Assert(n_a + n_b == n_c); subcase(a, n_a, b, n_b, c, n_c); if (commutative) subcase(b, n_b, a, n_a, c, n_c); } }; template requires(Merger(M)) void merge_cases(M m) { merge_case c(m, less_ignoring_case(), equal_ignoring_case(), true); merge_case > n(m, less_ignoring_case(), equal(), false); n("", "", ""); c("a", "", "a"); n("a", "A", "aA"); n("a", "a", "aa"); c("a", "b", "ab"); c("a", "bc", "abc"); c("b", "ac", "abc"); c("c", "ab", "abc"); n("ab", "AB", "aAbB"); c("ab", "cd", "abcd"); c("ac", "bd", "abcd"); c("ad", "bc", "abcd"); n("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"); // And so on. } template requires(Mutable(I) && ForwardIterator(I) && Relation(R) && ValueType(I) == Domain(R)) I wrapped_merge_n_with_buffer(I f0, DistanceType(I) n0, I f1, DistanceType(I) n1, R r) { array b(n0, n0, ValueType(I)()); return merge_n_with_buffer(f0, n0, f1, n1, begin(b), r); } template requires(Mutable(I) && ForwardIterator(I) && Relation(R) && ValueType(I) == Domain(R)) I wrapped_merge_n_adaptive(I f0, DistanceType(I) n0, I f1, DistanceType(I) n1, R r) { const DistanceType(I) n = half_nonnegative(n0); array b(n, n, ValueType(I)()); return merge_n_adaptive(f0, n0, f1, n1, begin(b), size(b), r); } void algorithms_merge() { typedef pointer(char) I; merge_cases(wrapped_merge_n_with_buffer); merge_cases(wrapped_merge_n_adaptive); } template requires(Sequence(S) && Integer(ValueType(S))) void algorithms_sort(S& s) { typedef IteratorType(S) I; typedef DistanceType(I) N; typedef ValueType(I) T; I f = begin(s); I l = end(s); N n = size(s); Assert(n == l - f); I m; less ls; converse< less > greater(ls); { iota(n, f); int n_b = half_nonnegative(n); array buffer(n_b, n_b, 0); m = sort_n_with_buffer(f, n, begin(buffer), greater); Assert(m == l && equal_iota_reverse(f, l)); } { iota(n, f); array buffer(50, 50, 0); pointer(int) f_b = begin(buffer); int n_b = size(buffer); m = sort_n_adaptive(f, n, f_b, n_b, greater); Assert(m == l && equal_iota_reverse(f, l)); } { iota(n, f); m = sort_n(f, n, greater); Assert(m == l && equal_iota_reverse(f, l)); } { iota(n, f); m = advanced_sort_n(f, n, greater); Assert(m == l && equal_iota_reverse(f, l)); } } void test_ch_11() { print(" Chapter 11\n"); print(" reduce_balanced\n"); algorithms_reduce_balanced(); print(" partition\n"); algorithms_partition(); print(" merge\n"); algorithms_merge(); const int n = 500; typedef int T; array_k ca; array a(n, n, T()); slist sl(a); list l(a); print(" sort\n"); algorithms_sort(ca); algorithms_sort(a); algorithms_sort(sl); algorithms_sort(l); } // Chapter 12. Composite objects template requires(Regular(T)) void nothing(const T&) { } template requires(Linearizable(W)) void concept_Linearizable(W& w) { // Regular concept_Regular(w); // Type functions typedef IteratorType(W) I; typedef ValueType(W) T; typedef SizeType(W) N; // Procedures and operators I f = begin(w); I l = end(w); N n = size(w); bool e = empty(w); Assert(n == (l - f)); Assert(e == (n == 0)); for_each(f, l, nothing); N i(0); while (f != l) { Assert(addressof(w[i]) == addressof(source(f))); i = successor(i); f = successor(f); } } template requires(Sequence(S)) void concept_Sequence(S& s0, S& s1, ValueType(S)& x) { // Precondition: s0 < s1 /\ !empty(s1) /\ x != s1[0] Assert(begin(s1) != end(s1)); Assert(x != s1[0]); concept_Linearizable(s1); concept_TotallyOrdered(s0, s1); // (all s in S)(all i in [begin(s), end(s)) deref(i) is a part of s S s11(s1); Assert(s11 == s1); s11[0] = x; // change the copy Assert(s11 != s1); // Equality and total ordering are lexicographical } template requires(ConstantSizeSequence(T0) && ConstantSizeSequence(T1) && ValueType(T0) == ValueType(T1)) void concept_ConstantSizeSequence(T0& a0, T1& a1, ValueType(T1)& x) { // Precondition: a0 < a1 /\ x != a1[0] if (verbose) { print(" "); print(a1); print_eol(); } concept_Sequence(a0, a1, x); // size is fixed, and agrees with Size type attribute Assert(size(a0) == Size(T0)); Assert(size(a1) == Size(T1)); // size is positive, at least for array_k Assert(!empty(a0)); Assert(!empty(a1)); // Iterator is pointer(T) Assert(begin(a0) == addressof(a0[0])); // Equality behavior Assert(a0 != a1); // Total ordering behavior // ***** to do: move this to concept_Sequence ????? Assert(a0 < a1); Assert(!(a1 < a0)); } void type_array_k() { { array_k<10, int> a0; array_k<10, int> a1; a0[0] = -39; a1[0] = 17; // establish a0 < a1 int x(99); concept_ConstantSizeSequence(a0, a1, x); } { typedef pair P; array_k<3, P> a0; array_k<3, P> a1; a0[0] = P(0, 'a'); a1[0] = P(1, 'Z'); // establish a0 < a1 P x(2, '0'); concept_ConstantSizeSequence(a0, a1, x); } { typedef array DA; DA da0; DA da1(3, 3, 0); iota(3, begin(da1)); typedef array_k< 4, DA > A_DA; A_DA a0; A_DA a1; if (verbose) { print(" da0:"); print(da0); print_eol(); print(" da1:"); print(da1); print_eol(); } a0[0] = da0; a1[0] = da1; // establish a0 < a1 if (verbose) { print(" a0:"); print(a0); print_eol(); print(" a1:"); print(a1); print_eol(); } Assert(a0 != a1); concept_ConstantSizeSequence(a0, a1, da0); { typedef slist SL; SL sl0; SL sl1; extend_sequence_n(sl0, 3, 3); extend_sequence_n(sl1, 4, 4); typedef array_k< 5, SL > A_SL; A_SL a0; A_SL a1; a0[0] = sl0; a1[0] = sl1; // establish a0 < a1 concept_ConstantSizeSequence(a0, a1, sl0); } typedef slist< DA > SL; SL sl0; SL sl1; extend_sequence_n(sl0, 3, da0); extend_sequence_n(sl1, 4, da1); typedef array_k< 3, SL > A_SL; A_SL a_sl0; A_SL a_sl1; a_sl0[0] = sl0; a_sl1[0] = sl1; // establish a0 < a1 concept_ConstantSizeSequence(a_sl0, a_sl1, sl0); } } template requires(Readable(I) && Iterator(I)) void type_bounded_range(I f, I l) { typedef bounded_range T; T r(f, l); concept_Linearizable(r); // but not totally ordered } template requires(Readable(I) && Iterator(I)) void type_counted_range(I f, DistanceType(I) n) { typedef counted_range T; T r(f, n); concept_Linearizable(r); // but not totally ordered } template requires(Position(P)) void concept_Position(P p, BaseType(P)& s, IteratorType(P) i) { typedef BaseType(P) B; typedef IteratorType(P) I; typedef ValueType(P) T; typedef SizeType(P) N; // Not regular: lacks default constructor, copy constructor, assignment B& b = base(p); Assert(addressof(b) == addressof(s)); I cur = current(p); Assert(cur - begin(s) >= N(0) && end(s) - cur >= N(0)); // i.e., cur \in [begin(s), end(s)) Assert(begin(p) == begin(s)); Assert(end(p) == end(s)); } template requires(DynamicSequence(S)) void test_Position(S& s, IteratorType(S) i) { before bef(s, i); concept_Position(bef, s, i); Assert(current(bef) == i); after aft(s, i); concept_Position(aft, s, i); Assert(current(bef) == i); front fr(s); concept_Position(fr, s, i); Assert(current(fr) == begin(s)); back bk(s); concept_Position(bk, s, i); Assert(current(bk) == end(s)); at a(s, i); concept_Position(a, s, i); Assert(current(bef) == i); } template requires(DynamicSequence(S)) void concept_DynamicSequence(S& s0, S& s1, ValueType(S)& x) { // Precondition: s0 < s1 /\ x != s1[0] typedef IteratorType(S) I; concept_Sequence(s0, s1, x); // construct from linearizable bounded_range br(begin(s1), end(s1)); S s11(br); Assert(s11 == s1); // insert // insert_range // erase // erase_range } template requires(List(L) && ValueType(L) == int) void type_list() { const SizeType(L) k0 = 10; { const SizeType(L) k1 = 15; L l0; L l1; extend_sequence_n(l0, k0, 0); extend_sequence_n(l1, k1, 1); int i(2); concept_DynamicSequence(l0, l1, i); } L l0; L l1; extend_sequence_n(l0, k0, 0); // algorithms: reverse, partition, merge, sort iota(k0, begin(l0)); reverse(l0); Assert(equal_iota_reverse(begin(l0), end(l0))); reverse(l0); Assert(equal_iota(begin(l0), end(l0))); Assert(size(l0) == k0); if (verbose) { print(" l0 before partition: "); print(l0); print_eol(); } partition(l0, l1, even); if (verbose) { print(" l0 after: "); print(l0); print_eol(); } if (verbose) { print(" l1 after: "); print(l1); print_eol(); } Assert(all(begin(l0), end(l0), odd)); Assert(all(begin(l1), end(l1), even)); L l2; L l3; partition(l2, l3, even); Assert(empty(l2) && empty(l3)); merge(l0, l1, less()); Assert(equal_iota(begin(l0), end(l0)) && size(l0) == k0 && empty(l1)); reverse(l0); sort(l0, less()); Assert(equal_iota(begin(l0), end(l0)) && size(l0) == k0); print(" ***** to do: slist, list"); print(" (including erase, erase_first, erase_after, set_link_backward\n"); } template requires(SingleExtentArray(S)) void type_single_extent_array(S& s0, S& s1, ValueType(S)& x) { // Precondition: s0 < s1 /\ x != s1[0] concept_DynamicSequence(s0, s1, x); // construct from capacity // construct from size, capacity, and value // construct from counted_range // end_of_storage // capacity // full // reserve_basic/reserve array a; typedef SizeType(array) N; Assert(empty(a)); Assert(full(a)); Assert(capacity(a) == N(0)); Assert(end(a) == end_of_storage(a)); reserve(a, N(1)); Assert(empty(a)); Assert(!full(a)); Assert(capacity(a) == N(1)); Assert(end(a) + N(1) == end_of_storage(a)); insert(back< array >(a), 1); Assert(size(a) == N(1)); Assert(end(a) == end_of_storage(a)); Assert(full(a)); erase(back< array >(a)); Assert(empty(a)); Assert(full(a)); } void type_array() { { array a0(10, 10, -39); array a1(10, 10, 17); // establish a0 < a1 int x(99); type_single_extent_array(a0, a1, x); } { typedef pair P; array

a0(3, 3, P()); array

a1(3, 3, P()); a0[0] = P(0, 'a'); a1[0] = P(1, 'Z'); // establish a0 < a1 P x(2, '0'); type_single_extent_array(a0, a1, x); } { typedef array_k<4, int> CA; CA ca0; CA ca1; fill_n(begin(ca0), size(ca0), 0); iota(4, begin(ca1)); // establish ca0 < ca1 typedef array A_CA; A_CA a0(3, 3, ca0); A_CA a1(3, 3, ca1); // establish a0 < a1 if (verbose) { print(" a0:"); print(a0); print_eol(); print(" a1:"); print(a1); print_eol(); } if (verbose) { print(" a0:"); print(a0); print_eol(); print(" a1:"); print(a1); print_eol(); } Assert(a0 != a1); type_single_extent_array(a0, a1, ca0); { typedef slist SL; SL sl0; SL sl1; extend_sequence_n(sl0, 3, 3); extend_sequence_n(sl1, 4, 4); typedef array< SL > A_SL; A_SL a0(2, 2, sl0); A_SL a1(2, 2, sl1); // establish a0 < a1 type_single_extent_array(a0, a1, sl0); } typedef slist< CA > SL; SL sl0; SL sl1; extend_sequence_n(sl0, 3, ca0); extend_sequence_n(sl1, 4, ca1); typedef array< SL > A_SL; A_SL a_sl0(4, 4, sl0); A_SL a_sl1(4, 4, sl1); // establish a0 < a1 type_single_extent_array(a_sl0, a_sl1, sl0); } } template requires(T == array) void algorithm_underlying_ref_array(T0& x) { typedef UnderlyingType(T) U; T t(2, 2, x); U u = underlying_ref(t); Assert(u.p == t.p); } template requires(T == array) void type_underlying_iterator_array(T0& x) { typedef IteratorType(T) I; typedef underlying_iterator UI; T t(2, 2, x); I f(begin(t)); I l(end(t)); UI uf(f); UI ul(l); Assert(uf != ul); Assert(predecessor(successor(uf)) == uf); Assert(ul - uf == l - f); Assert((uf + 1) - 1 == uf); Assert(uf < ul); Assert(addressof(sink(uf)) == addressof(source(uf)) && addressof(sink(uf)) == addressof(deref(uf))); Assert(original(uf) == f); while (uf != ul) { Assert(source(uf).p == source(f).p); f = successor(f); uf = successor(uf); } Assert(f == l); } template requires(T == array) void algorithm_original_ref_array(T0& x) { typedef UnderlyingType(T) U; T t0(2, 2, x); T t1(3, 3, x); Assert(t0 < t1); U u0 = underlying_ref(t0); U u1 = underlying_ref(t1); Assert(original_ref(u0) < original_ref(u1)); } template requires(Predicate(P) && T == Domain(P)) void algorithm_underlying_predicate(T& x0, T& x1, P p) { // Precondition: !p(x0) && p(x1) Assert(!p(x0) && p(x1)); underlying_predicate

up(p); Assert(!up(underlying_ref(x0)) && up(underlying_ref(x1))); } template requires(Relation(R) && T == Domain(R)) void algorithm_underlying_relation(T& x0, T& x1, R r) { // Precondition: r(x0, x1) && !r(x1, x0) typedef UnderlyingType(T) U; Assert(r(x0, x1) && !r(x1, x0)); underlying_relation ur(r); U& ux0(underlying_ref(x0)); U& ux1(underlying_ref(x1)); Assert(ur(ux0, ux1) && !ur(ux1, ux0)); } template requires(Linearizable(T)) bool nonempty(const T& x) { return !empty(x); } void test_ch_12() { print(" Chapter 12\n"); print(" array_k\n"); type_array_k(); print(" bounded_range\n"); array_k<3, int> ca; type_bounded_range(begin(ca), end(ca)); array< array_k<3, int> > da(5, 5, ca); type_bounded_range(begin(da), end(da)); slist< array< array_k<3, int> > > sl; extend_sequence_n(sl, 7, da); type_bounded_range(begin(sl), end(sl)); print(" counted_range\n"); type_counted_range(begin(ca), size(ca)); type_counted_range(begin(da), size(da)); type_counted_range(begin(sl), size(sl)); { print(" before, after, front, back, at\n"); const int N = 10; array da(N, N, 0); iota(N, begin(da)); slist sl(da); list l(da); test_Position(da, successor(begin(da))); test_Position(sl, successor(begin(sl))); test_Position(l, successor(begin(l))); } print(" slist\n"); type_list< slist >(); print(" list\n"); type_list< list >(); print(" ***** to do: stree, tree\n"); print(" array\n"); type_array(); print(" ***** to do: iterators/coordinates for slist, list, stree, tree, array\n"); print(" underlying type\n"); { int i = 1; int j = 2; swap_basic(i, j); Assert(i == 2 && j == 1); const int N = 10; array a0(N, N, 0); array a1(N, N, 1); pointer(int) p0 = begin(a0); pointer(int) p1 = begin(a1); swap(a0, a1); Assert(all(begin(a0), end(a0), equal_to_x(1))); Assert(all(begin(a1), end(a1), zero)); Assert(p0 == begin(a1) && p1 == begin(a0)); // remote parts were swapped } int i(0); algorithm_underlying_ref_array< array, int >(i); array ai(1, 1, 1); algorithm_underlying_ref_array< array< array > , array >(ai); type_underlying_iterator_array< array< array > >(ai); algorithm_original_ref_array< array< array > , array >(ai); array< array > a_empty; array< array > a_nonempty(1, 1, ai); algorithm_underlying_predicate(a_empty, a_nonempty, nonempty< array< array > >); less< array< array > > lt; algorithm_underlying_relation(a_empty, a_nonempty, lt); /* reverse_n_with_temporary_buffer using underlying_iterator */ } void run_tests() { // Call each procedure at least once. verify_conservation vsl(slist_node_count); verify_conservation vl(list_node_count); verify_conservation vst(stree_node_count); verify_conservation vt(tree_node_count); test_ch_1(); test_ch_2(); test_ch_3(); test_ch_4(); test_ch_5(); test_ch_6(); test_ch_7(); test_ch_8(); test_ch_9(); test_ch_10(); test_ch_11(); test_ch_12(); } #endif // EOP_TESTS