@@ -38,6 +38,7 @@ $(T2 as, Convenience function that creates a lazy view,
3838where each element of the original slice is converted to a type `T`.)
3939$(T2 bitpack, Bitpack slice over an unsigned integral slice.)
4040$(T2 bitwise, Bitwise slice over an unsigned integral slice.)
41+ $(T2 bitwiseField, Bitwise field over an unsigned integral field.)
4142$(T2 bytegroup, Groups existing slice into fixed length chunks and uses them as data store for destination type.)
4243$(T2 cached, Random access cache. It is usefull in combiation with $(LREF map) and $(LREF vmap).)
4344$(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.)
4647$(T2 map, Multidimensional functional map.)
4748$(T2 mapSubSlices, Maps indexes pairs to subslices.)
4849$(T2 member, Field (element's member) projection.)
50+ $(T2 orthogonalReduceField, Functional deep-element wise reduce of a slice composed of fields or iterators.)
4951$(T2 pairwise, Pairwise map for vectors.)
5052$(T2 pairwiseMapSubSlices, Maps pairwise indexes pairs to subslices.)
5153$(T2 retro, Reverses order of iteration for all dimensions.)
@@ -2087,6 +2089,18 @@ version(mir_test) unittest
20872089 assert (bits[100 ] == false );
20882090}
20892091
2092+ /+ +
2093+ Bitwise field over an integral field.
2094+ Params:
2095+ field = an integral field.
2096+ Returns: A bitwise field.
2097+ +/
2098+ auto bitwiseField (Field )(Field field)
2099+ if (isIntegral! (typeof (Field .init[size_t .init])))
2100+ {
2101+ return BitwiseField! Field (field);
2102+ }
2103+
20902104/+ +
20912105Bitpack slice over an integral slice.
20922106
@@ -2275,7 +2289,6 @@ template map(fun...)
22752289 auto map (Iterator, size_t N, SliceKind kind)
22762290 (Slice! (Iterator, N, kind) slice)
22772291 {
2278- import mir.ndslice.iterator: mapIterator;
22792292 auto iterator = mapIterator! f(slice._iterator);
22802293 return Slice! (typeof (iterator), N, kind)(slice._lengths, slice._strides, iterator);
22812294 }
@@ -2448,7 +2461,6 @@ See_Also:
24482461@optmath auto vmap(Iterator, size_t N, SliceKind kind, Callable)
24492462 (Slice! (Iterator, N, kind) slice, auto ref Callable callable)
24502463{
2451- import mir.ndslice.iterator: VmapIterator;
24522464 alias It = VmapIterator! (Iterator, Callable);
24532465 return Slice! (It, N, kind)(slice._lengths, slice._strides, It(slice._iterator, callable));
24542466}
@@ -4093,3 +4105,76 @@ template member(string name)
40934105 matrix.member! " y" [] = matrix.member! " f" ;
40944106 assert (matrix.member! " y" == [2 , 3 ].iota * 2 );
40954107}
4108+
4109+
4110+ version (D_Exceptions)
4111+ private immutable orthogonalReduceFieldException = new Exception (" orthogonalReduceField: Slice composed of fields must not be empty" );
4112+
4113+ /+ +
4114+ Functional deep-element wise reduce of a slice composed of fields or iterators.
4115+ +/
4116+ template orthogonalReduceField (alias fun)
4117+ {
4118+ import mir.functional: naryFun;
4119+ static if (__traits(isSame, naryFun! fun, fun))
4120+ {
4121+ @optmath:
4122+ /+ +
4123+ Params:
4124+ slice = Non empty input slice composed of fields or iterators.
4125+ Returns:
4126+ a lazy field with each element of which is reduced value of element of the same index of all iterators.
4127+ +/
4128+ OrthogonalReduceField! (Iterator, fun) orthogonalReduceField(Iterator)(Slice! Iterator slice)
4129+ {
4130+ if (_expect(slice.empty, false ))
4131+ {
4132+ version (D_Exceptions)
4133+ return orthogonalReduceFieldException;
4134+ else
4135+ assert (0 );
4136+ }
4137+ return typeof (return )(slice);
4138+ }
4139+
4140+ // / ditto
4141+ auto orthogonalReduceField (T)(T[] array)
4142+ {
4143+ return orthogonalReduceField (array.sliced);
4144+ }
4145+
4146+ // / ditto
4147+ auto orthogonalReduceField (T)(auto ref T withAsSlice)
4148+ if (hasAsSlice! T)
4149+ {
4150+ return orthogonalReduceField (withAsSlice.asSlice);
4151+ }
4152+ }
4153+ else alias orthogonalReduceField = .orthogonalReduceField! (naryFun! fun);
4154+ }
4155+
4156+ // / bit array operations
4157+ unittest
4158+ {
4159+ import mir.ndslice.allocation: bitSlice;
4160+ import mir.ndslice.dynamic: strided;
4161+ import mir.ndslice.topology: iota, orthogonalReduceField;
4162+ auto len = 100 ;
4163+ auto a = len.bitSlice;
4164+ auto b = len.bitSlice;
4165+ auto c = len.bitSlice;
4166+ a[len.iota.strided! 0 (7 )][] = true ;
4167+ b[len.iota.strided! 0 (11 )][] = true ;
4168+ c[len.iota.strided! 0 (13 )][] = true ;
4169+
4170+ // this is valid since bitslices above are oroginal slices of allocated memory.
4171+ auto and = [
4172+ a.iterator._field._field, // get raw data pointers
4173+ b.iterator._field._field,
4174+ c.iterator._field._field]
4175+ .orthogonalReduceField! " a & b" // operation on size_t
4176+ .bitwiseField
4177+ .slicedField(len);
4178+
4179+ assert (and == (a & b & c));
4180+ }
0 commit comments