Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions source/mir/ndslice/field.d
Original file line number Diff line number Diff line change
Expand Up @@ -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))
)

Expand Down Expand Up @@ -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).
+/
Expand All @@ -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;
Expand Down
89 changes: 87 additions & 2 deletions source/mir/ndslice/topology.d
Original file line number Diff line number Diff line change
Expand Up @@ -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).)
Expand All @@ -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.)
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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));
}