Skip to content

Commit

Permalink
Merge pull request #58 from ljubobratovicrelja/optimization-patch-2
Browse files Browse the repository at this point in the history
Optimization pass
  • Loading branch information
ljubobratovicrelja authored Nov 12, 2016
2 parents 7b97737 + d88c786 commit 753a1d3
Show file tree
Hide file tree
Showing 14 changed files with 1,314 additions and 919 deletions.
41 changes: 29 additions & 12 deletions source/dcv/core/algorithm.d
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,21 @@ import std.traits : isNumeric, isFloatingPoint;
import mir.ndslice.slice : Slice, sliced, DeepElementType;
import mir.ndslice.algorithm : ndReduce, ndEach, Yes;

import dcv.core.utils : isSlice;

version(LDC)
{
import ldc.intrinsics : sqrt = llvm_sqrt, fabs = llvm_fabs, min = llvm_minnum, max = llvm_maxnum;
import ldc.intrinsics : sqrt = llvm_sqrt, fabs = llvm_fabs;
}
else
{
import std.math : sqrt, fabs;
import std.algorithm.comparison : min, max;
}

version(unittest)
{
import std.math : approxEqual;
import ldc.intrinsics : min = llvm_minnum, max = llvm_maxnum;
}

/**
Expand Down Expand Up @@ -170,10 +172,14 @@ Returns:
Scaled input tensor.
*/
@nogc nothrow auto scaled(Scalar, Range, size_t N)(auto ref Slice!(N, Range) tensor, Scalar alpha = 1, Scalar beta = 0)
if (isNumeric!Scalar)
nothrow @nogc auto scaled(Scalar, Tensor)(Tensor tensor, Scalar alpha = 1, Scalar beta = 0) if (isNumeric!Scalar)
in
{
static assert(isSlice!Tensor, "Input tensor has to be of type mir.ndslice.slice.Slice.");
}
body
{
tensor.ndEach!((ref v) { v = alpha * (v) + beta; }, Yes.vectorized);
tensor.ndEach!((ref v) { v = cast(DeepElementType!Tensor)(alpha * (v) + beta); }, Yes.vectorized);
return tensor;
}

Expand All @@ -198,21 +204,32 @@ Params:
maxValue = Maximal value output tensor should contain.
*/
@nogc auto ranged(Scalar, Range, size_t N)(auto ref Slice!(N, Range) tensor,
nothrow @nogc auto ranged(Scalar, Tensor)(Tensor tensor,
Scalar minValue = 0, Scalar maxValue = 1) if (isNumeric!Scalar)
in
{
static assert(isSlice!Tensor, "Input tensor has to be of type mir.ndslice.slice.Slice.");
}
body
{
alias RangeElementType = DeepElementType!(typeof(tensor));
alias T = DeepElementType!Tensor;

auto _min = ndReduce!(min, Yes.vectorized)(RangeElementType.max, tensor);
static if (isFloatingPoint!RangeElementType)
auto _max = ndReduce!(max, Yes.vectorized)(RangeElementType.min_normal, tensor);
static if (isFloatingPoint!T)
{
import ldc.intrinsics : min = llvm_minnum, max = llvm_maxnum;
auto _max = ndReduce!(max, Yes.vectorized)(T.min_normal, tensor);
}
else
auto _max = ndReduce!(max, Yes.vectorized)(RangeElementType.min, tensor);
{
import std.algorithm.comparison : min, max;
auto _max = ndReduce!(max, Yes.vectorized)(T.min, tensor);
}

auto _min = ndReduce!(min, Yes.vectorized)(T.max, tensor);
auto rn_val = _max - _min;
auto sc_val = maxValue - minValue;

tensor.ndEach!((ref a) { a = sc_val * ((a - _min) / rn_val) + minValue; }, Yes.vectorized);
tensor.ndEach!((ref a) { a = cast(T)(sc_val * ((a - _min) / rn_val) + minValue); }, Yes.vectorized);

return tensor;
}
Expand Down
148 changes: 109 additions & 39 deletions source/dcv/core/utils.d
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,77 @@ static Slice!(N, V*) emptySlice(size_t N, V)() pure @safe nothrow
return Slice!(N, V*)();
}

package(dcv) @nogc pure nothrow
{
/**
Pack and unpack (N, T*) slices to (N-1, T[M]*).
*/
auto staticPack(size_t CH, size_t N, T)(Slice!(N, T*) slice)
{
ulong[N-1] shape = slice.shape[0 .. N-1];
long[N-1] strides = [slice.structure.strides[0] / CH, slice.structure.strides[1] / CH];
T[CH]* ptr = cast(T[CH]*)slice.ptr;
return Slice!(N-1, T[CH]*)(shape, strides, ptr);
}

/// ditto
auto staticUnpack(size_t CH, size_t N, T)(Slice!(N, T[CH]*) slice)
{
ulong[N+1] shape = [slice.shape[0], slice.shape[1], CH];
long[N+1] strides = [slice.structure.strides[0] * CH, slice.structure.strides[1] * CH, 1];
T* ptr = cast(T*)slice.ptr;
return Slice!(N+1, T*)(shape, strides, ptr);
}

@safe @nogc nothrow pure auto borders(Shape)(Shape shape, size_t ks)
in
{
static assert(Shape.length == 2, "Non-matrix border extraction is not currently supported.");
}
body
{
import std.typecons : Tuple;
import std.algorithm.comparison : max;
import std.range : iota;
import std.traits : ReturnType;

struct Range(Iota)
{
Iota rows;
Iota cols;
@disable this();
this(Iota rows, Iota cols)
{
this.rows = rows;
this.cols = cols;
}
}

auto range(Iota)(Iota rows, Iota cols)
{
return Range!Iota(rows, cols);
}

// forced size_t cast...
auto _iota(B, E, S)(B begin, E end, S step = 1)
{
return iota(size_t(begin), size_t(end), size_t(step));
}

size_t kh = max(1, ks / 2);
alias Iota = ReturnType!(iota!(size_t, size_t, size_t));

Range!(Iota)[4] borders = [
range(_iota(0, shape[0]), _iota(0, kh)),
range(_iota(0, shape[0]), _iota(shape[1] - kh, shape[1])),
range(_iota(0, kh), _iota(0, shape[1])),
range(_iota(shape[0] - kh, shape[0]), _iota(0, shape[1]))
];

return borders;
}
}

/**
Take another typed Slice. Type conversion for the Slice object.
Expand Down Expand Up @@ -185,43 +256,39 @@ static if (__VERSION__ >= 2071)
/// Check if given function can perform boundary condition test.
template isBoundaryCondition(alias bc)
{
import std.typetuple;
enum bool isBoundaryCondition = true;
}

nothrow @nogc pure
{

alias Indices = TypeTuple!(int, int);
alias bct = bc!(2, float, Indices);
static if (isCallable!(bct) && is(Parameters!bct[0] == Slice!(2, float*))
&& is(Parameters!bct[1] == int) && is(Parameters!bct[2] == int) && is(ReturnType!bct == float))
/// $(LINK2 https://en.wikipedia.org/wiki/Neumann_boundary_condition, Neumann) boundary condition test
auto neumann(Tensor, Indices...)(Tensor tensor, Indices indices)
if (isSlice!Tensor && allSameType!Indices && allSatisfy!(isIntegral, Indices))
{
enum bool isBoundaryCondition = true;
immutable N = ReturnType!(Tensor.shape).length;
static assert(indices.length == N, "Invalid index dimension");
return tensor.bcImpl!_neumann(indices);
}
else

/// $(LINK2 https://en.wikipedia.org/wiki/Periodic_boundary_conditions,Periodic) boundary condition test
auto periodic(Tensor, Indices...)(Tensor tensor, Indices indices)
if (isSlice!Tensor && allSameType!Indices && allSatisfy!(isIntegral, Indices))
{
enum bool isBoundaryCondition = false;
immutable N = ReturnType!(Tensor.shape).length;
static assert(indices.length == N, "Invalid index dimension");
return tensor.bcImpl!_periodic(indices);
}
}

/// $(LINK2 https://en.wikipedia.org/wiki/Neumann_boundary_condition, Neumann) boundary condition test
ref T neumann(size_t N, T, Indices...)(ref Slice!(N, T*) slice, Indices indices)
if (allSameType!Indices && allSatisfy!(isIntegral, Indices))
{
static assert(indices.length == N, "Invalid index dimension");
return slice.bcImpl!_neumann(indices);
}

/// $(LINK2 https://en.wikipedia.org/wiki/Periodic_boundary_conditions,Periodic) boundary condition test
ref T periodic(size_t N, T, Indices...)(ref Slice!(N, T*) slice, Indices indices)
if (allSameType!Indices && allSatisfy!(isIntegral, Indices))
{
static assert(indices.length == N, "Invalid index dimension");
return slice.bcImpl!_periodic(indices);
}
/// Symmetric boundary condition test
auto symmetric(Tensor, Indices...)(Tensor tensor, Indices indices)
if (isSlice!Tensor && allSameType!Indices && allSatisfy!(isIntegral, Indices))
{
immutable N = ReturnType!(Tensor.shape).length;
static assert(indices.length == N, "Invalid index dimension");
return tensor.bcImpl!_symmetric(indices);
}

/// Symmetric boundary condition test
ref T symmetric(size_t N, T, Indices...)(ref Slice!(N, T*) slice, Indices indices)
if (allSameType!Indices && allSatisfy!(isIntegral, Indices))
{
static assert(indices.length == N, "Invalid index dimension");
return slice.bcImpl!_symmetric(indices);
}

/// Alias for generalized boundary condition test function.
Expand Down Expand Up @@ -264,30 +331,33 @@ unittest

private:

ref auto bcImpl(alias bcfunc, size_t N, T, Indices...)(ref Slice!(N, T*) slice, Indices indices)
nothrow @nogc pure:

auto bcImpl(alias bcfunc, Tensor, Indices...)(Tensor tensor, Indices indices)
{
immutable N = ReturnType!(Tensor.shape).length;
static if (N == 1)
{
return slice[bcfunc(cast(int)indices[0], cast(int)slice.length)];
return tensor[bcfunc(cast(int)indices[0], cast(int)tensor.length)];
}
else static if (N == 2)
{
return slice[bcfunc(cast(int)indices[0], cast(int)slice.length!0),
bcfunc(cast(int)indices[1], cast(int)slice.length!1)];
return tensor[bcfunc(cast(int)indices[0], cast(int)tensor.length!0),
bcfunc(cast(int)indices[1], cast(int)tensor.length!1)];
}
else static if (N == 3)
{
return slice[bcfunc(cast(int)indices[0], cast(int)slice.length!0),
bcfunc(cast(int)indices[1], cast(int)slice.length!1), bcfunc(cast(int)indices[2],
cast(int)slice.length!2)];
return tensor[bcfunc(cast(int)indices[0], cast(int)tensor.length!0),
bcfunc(cast(int)indices[1], cast(int)tensor.length!1), bcfunc(cast(int)indices[2],
cast(int)tensor.length!2)];
}
else
{
foreach (i, ref id; indices)
{
id = bcfunc(cast(int)id, cast(int)slice.shape[i]);
id = bcfunc(cast(int)id, cast(int)tensor.shape[i]);
}
return slice[indices];
return tensor[indices];
}
}

Expand Down
Loading

0 comments on commit 753a1d3

Please sign in to comment.