From cd9300942087223c2dbc734cdccaf67fa69f3ec2 Mon Sep 17 00:00:00 2001 From: 9il Date: Tue, 21 Aug 2018 18:08:37 +0700 Subject: [PATCH] add OrthogonalReduceField --- source/mir/ndslice/field.d | 43 +++++++++++++++++ source/mir/ndslice/topology.d | 89 ++++++++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/source/mir/ndslice/field.d b/source/mir/ndslice/field.d index 951da054..835e012b 100644 --- a/source/mir/ndslice/field.d +++ b/source/mir/ndslice/field.d @@ -13,6 +13,7 @@ $(T2 LinspaceField, $(SUBREF topology, linspace)) $(T2 MagicField, $(SUBREF topology, magic)) $(T2 MapField, $(SUBREF topology, map)) $(T2 ndIotaField, $(SUBREF topology, ndiota)) +$(T2 OrthogonalReduceField, $(SUBREF topology, orthogonalReduceField)) $(T2 RepeatField, $(SUBREF topology, repeat)) ) @@ -302,6 +303,47 @@ unittest assert(packed[2] == 5); } +/// +struct OrthogonalReduceField(FieldsIterator, alias fun) +{ + import mir.ndslice.slice: Slice; + +@optmath: + /// non empty slice + + Slice!FieldsIterator _fields; + + /// + auto lightConst()() const @property + { + auto fields = _fields.lightConst; + return OrthogonalReduceField!(fields.Iterator, fun)(fields); + } + + /// + auto lightImmutable()() immutable @property + { + auto fields = _fields.lightImmutable; + return OrthogonalReduceField!(fields.Iterator, fun)(fields); + } + + /// `r = fun(r, fields[i][index]);` reduction by `i` + auto opIndex()(size_t index) const + { + assert(_fields.length); + auto fields = _fields.lightConst; + Unqual!(typeof(fun(fields.front[index], fields.front[index]))) r = fields.front[index]; + for(;;) + { + fields.popFront; + if (fields.empty) + break; + r = fun(r, fields.front[index]); + } + return r; + } +} + /++ `ndIotaField` is used by $(SUBREF topology, ndiota). +/ @@ -324,6 +366,7 @@ struct ndIotaField(size_t N) return ndIotaField!N(_lengths); } + /// size_t[N] opIndex()(size_t index) const { size_t[N] indexes; diff --git a/source/mir/ndslice/topology.d b/source/mir/ndslice/topology.d index 58bc554d..ba9dc012 100644 --- a/source/mir/ndslice/topology.d +++ b/source/mir/ndslice/topology.d @@ -38,6 +38,7 @@ $(T2 as, Convenience function that creates a lazy view, where each element of the original slice is converted to a type `T`.) $(T2 bitpack, Bitpack slice over an unsigned integral slice.) $(T2 bitwise, Bitwise slice over an unsigned integral slice.) +$(T2 bitwiseField, Bitwise field over an unsigned integral field.) $(T2 bytegroup, Groups existing slice into fixed length chunks and uses them as data store for destination type.) $(T2 cached, Random access cache. It is usefull in combiation with $(LREF map) and $(LREF vmap).) $(T2 cachedGC, Random access cache auto-allocated in GC heap. It is usefull in combiation with $(LREF map) and $(LREF vmap).) @@ -46,6 +47,7 @@ $(T2 flattened, Contiguous 1-dimensional slice of all elements of a slice.) $(T2 map, Multidimensional functional map.) $(T2 mapSubSlices, Maps indexes pairs to subslices.) $(T2 member, Field (element's member) projection.) +$(T2 orthogonalReduceField, Functional deep-element wise reduce of a slice composed of fields or iterators.) $(T2 pairwise, Pairwise map for vectors.) $(T2 pairwiseMapSubSlices, Maps pairwise indexes pairs to subslices.) $(T2 retro, Reverses order of iteration for all dimensions.) @@ -2087,6 +2089,18 @@ version(mir_test) unittest assert(bits[100] == false); } +/++ +Bitwise field over an integral field. +Params: + field = an integral field. +Returns: A bitwise field. ++/ +auto bitwiseField(Field)(Field field) + if (isIntegral!(typeof(Field.init[size_t.init]))) +{ + return BitwiseField!Field(field); +} + /++ Bitpack slice over an integral slice. @@ -2275,7 +2289,6 @@ template map(fun...) auto map(Iterator, size_t N, SliceKind kind) (Slice!(Iterator, N, kind) slice) { - import mir.ndslice.iterator: mapIterator; auto iterator = mapIterator!f(slice._iterator); return Slice!(typeof(iterator), N, kind)(slice._lengths, slice._strides, iterator); } @@ -2448,7 +2461,6 @@ See_Also: @optmath auto vmap(Iterator, size_t N, SliceKind kind, Callable) (Slice!(Iterator, N, kind) slice, auto ref Callable callable) { - import mir.ndslice.iterator: VmapIterator; alias It = VmapIterator!(Iterator, Callable); return Slice!(It, N, kind)(slice._lengths, slice._strides, It(slice._iterator, callable)); } @@ -4093,3 +4105,76 @@ template member(string name) matrix.member!"y"[] = matrix.member!"f"; assert(matrix.member!"y" == [2, 3].iota * 2); } + + +version(D_Exceptions) +private immutable orthogonalReduceFieldException = new Exception("orthogonalReduceField: Slice composed of fields must not be empty"); + +/++ +Functional deep-element wise reduce of a slice composed of fields or iterators. ++/ +template orthogonalReduceField(alias fun) +{ + import mir.functional: naryFun; + static if (__traits(isSame, naryFun!fun, fun)) + { + @optmath: + /++ + Params: + slice = Non empty input slice composed of fields or iterators. + Returns: + a lazy field with each element of which is reduced value of element of the same index of all iterators. + +/ + OrthogonalReduceField!(Iterator, fun) orthogonalReduceField(Iterator)(Slice!Iterator slice) + { + if (_expect(slice.empty, false)) + { + version(D_Exceptions) + return orthogonalReduceFieldException; + else + assert(0); + } + return typeof(return)(slice); + } + + /// ditto + auto orthogonalReduceField(T)(T[] array) + { + return orthogonalReduceField(array.sliced); + } + + /// ditto + auto orthogonalReduceField(T)(auto ref T withAsSlice) + if (hasAsSlice!T) + { + return orthogonalReduceField(withAsSlice.asSlice); + } + } + else alias orthogonalReduceField = .orthogonalReduceField!(naryFun!fun); +} + +/// bit array operations +unittest +{ + import mir.ndslice.allocation: bitSlice; + import mir.ndslice.dynamic: strided; + import mir.ndslice.topology: iota, orthogonalReduceField; + auto len = 100; + auto a = len.bitSlice; + auto b = len.bitSlice; + auto c = len.bitSlice; + a[len.iota.strided!0(7)][] = true; + b[len.iota.strided!0(11)][] = true; + c[len.iota.strided!0(13)][] = true; + + // this is valid since bitslices above are oroginal slices of allocated memory. + auto and = [ + a.iterator._field._field, // get raw data pointers + b.iterator._field._field, + c.iterator._field._field] + .orthogonalReduceField!"a & b" // operation on size_t + .bitwiseField + .slicedField(len); + + assert(and == (a & b & c)); +}