1 /** Sparseness and denseness of ranges. 2 */ 3 module nxt.nesses; 4 5 import nxt.rational: Rational; 6 import std.traits : isIterable, isFloatingPoint; 7 8 /** Returns: number of default-initialized (zero) elements in $(D x) at 9 * recursion depth $(D depth). 10 * 11 * Depth defaults -1 meaning infinite depth. 12 */ 13 Rational!ulong sparseness(T)(const scope T x, 14 int depth = -1) 15 { 16 alias R = typeof(return); // rational shorthand 17 static if (isIterable!T) 18 { 19 import std.range: empty; 20 immutable isEmpty = x.empty; 21 if (isEmpty || depth == 0) 22 return R(isEmpty, 1); 23 else 24 { 25 immutable nextDepth = (depth == -1 ? depth : depth - 1); 26 ulong nums, denoms; 27 foreach (const ref elt; x) 28 { 29 const sub = elt.sparseness(nextDepth); 30 nums += sub.numerator; 31 denoms += sub.denominator; 32 } 33 return R(nums, denoms); 34 } 35 } 36 else static if (isFloatingPoint!T) 37 return R(x == 0, 1); // explicit zero because T.init is nan here 38 else 39 return R(x == T.init, 1); 40 } 41 42 pure nothrow @safe unittest { 43 assert(1.sparseness == 0); 44 assert(0.sparseness == 1); 45 assert(0.0.sparseness == 1); 46 assert(0.1.sparseness == 0); 47 assert(0.0f.sparseness == 1); 48 assert(0.1f.sparseness == 0); 49 alias Q = Rational!ulong; 50 { immutable ubyte[3] x = [1, 2, 3]; assert(x[].sparseness == Q(0, 3)); } 51 { immutable float[3] x = [1, 2, 3]; assert(x[].sparseness == Q(0, 3)); } 52 /+ TODO: { immutable ubyte[2][2] x = [0, 1, 0, 1]; assert(x[].sparseness == Q(2, 4)); } +/ 53 /+ TODO: immutable ubyte[2][2] x22z = [0, 0, 0, 0]; assert(x22z[].sparseness == Q(4, 4)); +/ 54 assert("".sparseness == 1); /+ TODO: Is this correct? +/ 55 assert(null.sparseness == 1); 56 } 57 58 /** Returns: Number of Non-Zero Elements in $(D range) at recursion depth $(D 59 depth) defaulting infinite depth (-1). */ 60 auto denseness(T)(const scope T x, int depth = -1) 61 => 1 - x.sparseness(depth); 62 63 pure nothrow @safe @nogc unittest { 64 immutable float[3] f = [1, 2, 3]; 65 alias Q = Rational!ulong; 66 assert(f[].denseness == Q(1, 1)); /+ TODO: should this be 3/3? +/ 67 assert(f.denseness == Q(1, 1)); /+ TODO: should this be 3/3? +/ 68 }