-
Notifications
You must be signed in to change notification settings - Fork 36
Add eachTriangle #95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add eachTriangle #95
Conversation
source/mir/ndslice/algorithm.d
Outdated
@@ -1884,3 +1885,760 @@ size_t countImpl(alias fun, Slices...)(Slices slices) | |||
while(!slices[0].empty); | |||
return ret; | |||
} | |||
|
|||
private template eachLowerTriangle(alias fun, size_t k = 1, | |||
bool BeyondMainDiagonal = false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to have eachLowerTriangle(alias fun,ptrdiff_t diagonalOffset)
if I am understanding this correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's more-or-less how it originally was, but I thought the code was a little simpler when I had done it this way.
source/mir/ndslice/algorithm.d
Outdated
unittest | ||
{ | ||
import mir.ndslice.allocation: slice; | ||
import mir.ndslice.topology: iota, canonical; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to combine these essentially duplicate tests with an alias seq?
Something like
import mir.ndslice.topology: iota, canonical, universal;
/*static*/ foreach(type; AliasSeq!(identity, canonical, universal)
{
auto m = iota([3, 3], 1).slice.type;
m.eachLowerTriangle!((ref a) {a = 0; }, 0);
assert(m == [
[0, 2, 3],
[0, 0, 6],
[0, 0, 0]]);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, please. I like unittests, but it is nice to keep them smaller with the same coverage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thewilsonator The way I was able to get it to work looks like
version(unittest)
{
T identity(T)(T x) @property
{
return x;
}
}
unittest
{
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota, canonical, universal;
import std.meta: AliasSeq;
void test(alias func)()
{
// 1 2 3
// 4 5 6
// 7 8 9
auto m = func(iota([3, 3], 1).slice);
m.eachUpper!((ref a) {a = 0; }, 0);
assert(m == [
[0, 0, 0],
[4, 0, 0],
[7, 8, 0]]);
}
static foreach(type; AliasSeq!(identity, canonical, universal))
{
test!type;
}
}
I do not think we need this API. Maybe docs for |
@9il A few reasons I wrote this up: 1) This function makes it very easy to implement the |
OK, I see. What about |
I'm ok with that. I can also add specialization for the square cases where
eachUploPair can be used.
…On Mon, Sep 25, 2017 at 11:07 PM Ilya Yaroshenko ***@***.***> wrote:
OK, I see.
Please compress unittests where possible.
What about eachUpper and eachLower names?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#95 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AMJWyhjguOXEd-IRR5PZhtuyAA2HtyA0ks5smGpUgaJpZM4PjgSQ>
.
|
|
@jmh530 Possibly |
@9i With respect to |
LGTM |
Codecov Report
@@ Coverage Diff @@
## master #95 +/- ##
==========================================
+ Coverage 95.24% 96.62% +1.38%
==========================================
Files 45 30 -15
Lines 6599 5456 -1143
==========================================
- Hits 6285 5272 -1013
+ Misses 314 184 -130
Continue to review full report at Codecov.
|
LGTM. Resolve the conflict and make sure the CI passes. Wr.t the latter I'm not sure that LDC has static foreach yet, you may have to remove that, either way it will work without it. |
source/mir/ndslice/algorithm.d
Outdated
|
||
version(unittest) | ||
{ | ||
T identity(T)(T x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need in global declaration. can be replaced with lambda
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how to do this with lambdas without making it more complicated. The lambdas I was trying weren't inferring the return type correctly, so then I tried making it a template and it just got uglier. I just put the identity function in each of the unittests instead of the version.
source/mir/ndslice/algorithm.d
Outdated
fun = A function | ||
k = adjustment to diagonals (default = 1) | ||
+/ | ||
template eachLower(alias fun, ptrdiff_t k = 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not to make k
a runtime parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will make it a run-time parameter. The reason I hadn't is because I couldn't think of a time when I wanted to use triu
or tril
without knowing at compile-time how I was going to use it. Since this is more general than those functions, it probably makes sense.
As an aside, it would be much easier if in D you could have some parameters be available in run-time or compile-time.
source/mir/ndslice/algorithm.d
Outdated
static if (__traits(isSame, naryFun!fun, fun)) | ||
{ | ||
void eachLower(SliceKind kind, Iterator) | ||
(Slice!(kind, [2], Iterator) matrix) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple arguments is required for many algorithms (the same way as each
). For example, for triu
implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't fully understand this, but it is late and I will try to look at it again with fresh eyes.
source/mir/ndslice/algorithm.d
Outdated
|
||
void eachLowerImpl(T)(T matrix) | ||
{ | ||
void eachLowerImpl_i(U)(U e, size_t i) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No non-static inner functions plz
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
source/mir/ndslice/algorithm.d
Outdated
(Slice!(kind, [2], Iterator) matrix) | ||
{ | ||
immutable(size_t) m = matrix.length!0; | ||
immutable(size_t) n = matrix.length!1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, lets replace the implementation with single one loop and without eachUploPair
calls (sorry for wrong recommendation before, found algo issues with it now). We should be careful about code time generation and object code size.
x x x x < | 2D eachImpl
x x x x < |
x x x x < || Loop over 1D eachImpl
x x x < ||
x x < ||
x < ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I have implemented this in the latest commit.
source/mir/ndslice/algorithm.d
Outdated
if (i < (n + k)) | ||
e[0..(i - k + 1)].eachImpl!fun; | ||
else | ||
e.eachImpl!fun; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eachImpl
probably will be inlined, so the following code will be two times smaller (in terms of object code size):
eachImpl!fun(i < n + k ? e[0..(i - k + 1)] : e);
EDIT: generally we should not have conditions in the loop. So dismiss this comment.
125e60b
to
4ceeea6
Compare
@9il I think I've got a handle on how to make it work for multiple slices now, but still a little work to do. |
95c66bf
to
4eadd12
Compare
@9il I've submitted some updates. The only fail is on DMD nightly. Let me know if you want additional changes. |
The problem on Travis CI doesn't appear related to your pull request - the installer failed:
|
source/mir/ndslice/algorithm.d
Outdated
foreach(ref slice; slices) | ||
slice.popFront!0; | ||
i++; | ||
} while (i < k); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this loop can be replaced with slice.popFrontExactly!0(k)
source/mir/ndslice/algorithm.d
Outdated
val = i - k + 1; | ||
static if (slices[0].shape.length == 1) | ||
mixin("fun(" ~ | ||
frontSelectFrontOf!(Slices.length, "val") ~ ");"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use single line here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does mir follow a line length restriction? I normally use 80.
source/mir/ndslice/algorithm.d
Outdated
frontSelectFrontOf!(Slices.length, "val") ~ ");"); | ||
else | ||
mixin(".eachImpl!fun(" ~ | ||
frontSelectFrontOf!(Slices.length, "val") ~ ");"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
source/mir/ndslice/algorithm.d
Outdated
selectFrontOf!(Slices.length, "val") ~ ");"); | ||
do | ||
{ | ||
foreach(ref slice; slices) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto popFrontExactly
source/mir/ndslice/algorithm.d
Outdated
|
||
static if ((Inputs.length > 1) && (isIntegral!(Inputs[$ - 1]))) | ||
{ | ||
k = inputs[$ - 1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sizediff_t k = inputs[$ - 1];
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's sizediff_t
?
alias slices = inputs[0..($ - 1)]; | ||
} | ||
else | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enum sizediff_t k = 1;
source/mir/ndslice/package.d
Outdated
@@ -166,6 +166,7 @@ $(TR $(TDNW $(SUBMODULE algorithm) | |||
$(SUBREF algorithm, cmp) | |||
$(SUBREF algorithm, count) | |||
$(SUBREF algorithm, each) | |||
$(SUBREF algorithm, eachTriangle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
names was changed
source/mir/ndslice/algorithm.d
Outdated
function applied. | ||
+/ | ||
void eachLower(Inputs...)(Inputs inputs) | ||
if (Inputs.length) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs batter contraints:
(Inputs.length > 1) && (isIntegral!(Inputs[$ - 1])) || Inputs.length
source/mir/ndslice/algorithm.d
Outdated
if (k < 0) | ||
{ | ||
val = -k; | ||
static if (slices[0].shape.length == 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have 1D case?
source/mir/ndslice/algorithm.d
Outdated
import std.meta : allSatisfy; | ||
import std.traits : isIntegral; | ||
import mir.ndslice.traits : isMatrix; | ||
import mir.ndslice.slice : Slice; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is something from this imports are global in the module?
source/mir/ndslice/algorithm.d
Outdated
//| 5 6 7 8 | | ||
//| 9 10 11 12 | | ||
auto m = iota([3, 4], 1).slice; | ||
m.eachUpper!((ref a) {a = 0; })(-2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m.eachUpper!"a = 0"
should work too. Please use it since it does not generate template bloat for each difinition.
@9il ...and I just realized that there were changes requested here. Sorry about that. I'll try to get back to this. |
8ac2135
to
a4557b4
Compare
@9il I've made some updates. Travis-CI is failing on ldc-1.7.0 for some reason, but otherwise looks fine. |
awesome! |
After some of the work on
eachUploPair
I was thinking that it might make sense to specialize a version for upper and lower triangles. This would be useful for implementing functions similar totril
andtriu
from Matlab/Numpy in numir.I'm not sure this is the most efficient version, but at the moment it gets the job done and works on rectangular matrices the way I would expect.