<div dir="ltr"><div class="markdown-here-wrapper" style=""><p style="margin:0px 0px 1.2em!important">Eric,</p>
<p style="margin:0px 0px 1.2em!important">Great point. The multi-dimensional slicing and sequence return type is definitely strange. I was thinking about that last night.<br>I’m a little new to the <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">__array__</code> methods.<br>Are you saying that the sequence behaviour would stay the same, (ie. <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">__iter__</code>, <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">__revesed__</code>, <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">__contains__</code>), but<br><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.asarray(np.ndrange((3, 3)))</code><br>would return something like an array of tuples?<br>I’m not sure this is something that anybody can’t already with do <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">meshgrid</code> + stack</p>
<blockquote style="margin:1.2em 0px;border-left:4px solid rgb(221,221,221);padding:0px 1em;color:rgb(119,119,119);quotes:none">
<p style="margin:0px 0px 1.2em!important">and only implement methods already present in numpy.</p>
</blockquote>
<p style="margin:0px 0px 1.2em!important">I’m not sure what this means.</p>
<p style="margin:0px 0px 1.2em!important">I’ll note that in <a href="https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range">Python 3</a>, range is it’s own thing. It is still a sequence type but it doesn’t support addition.<br>I’m kinda ok with <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndrange</code>/<code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndindex</code> being a sequence type, supporting ND slicing, but not being an array ;)</p>
<p style="margin:0px 0px 1.2em!important">I’m kinda warming up to the idea of expanding <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndindex</code>.</p>
<ol style="margin:1.2em 0px;padding-left:2em">
<li style="margin:0.5em 0px">The additional <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">start</code> and <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">step</code> can be omitted from <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndindex</code> for a while (indefinitely?). Slicing is way more convenient anyway.</li>
<li style="margin:0.5em 0px">Warnings can help people move from <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">nd.index(1, 2, 3)</code> to <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">nd.index((1, 2, 3))</code></li>
<li style="margin:0.5em 0px">ndindex can return a seperate iterator, but the ndindex object would hold a reference to it. Calls to <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndindex.__next__</code> would simply <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">return next(of_that_object)</code><br> Note. This would break introspection since the iterator is no longer <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndindex</code> type. I’m kinda OK with this though, but breaking code is never nice :(</li>
<li style="margin:0.5em 0px">Bench-marking can help motivate the choice of iterator used for <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">step=(1,) * N</code> <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">start=(0,) * N</code></li>
<li style="margin:0.5em 0px">Wait until 2019 because I don’t want to deal with performance regressions of potentially using <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">range</code> in Python2 and I don’t want this to motivate any implementation details.</li>
</ol>
<p style="margin:0px 0px 1.2em!important">Mark</p>
<div title="MDH:PGRpdiBkaXI9Imx0ciI+PGRpdj5FcmljLDwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+R3JlYXQg
cG9pbnQuIFRoZSBtdWx0aS1kaW1lbnNpb25hbCBzbGljaW5nIGFuZCBzZXF1ZW5jZSByZXR1cm4g
dHlwZSBpcyBkZWZpbml0ZWx5IHN0cmFuZ2UuIEkgd2FzIHRoaW5raW5nIGFib3V0IHRoYXQgbGFz
dCBuaWdodC48YnI+PC9kaXY+PGRpdj5JJ20gYSBsaXR0bGUgbmV3IHRvIHRoZSBgX19hcnJheV9f
YCBtZXRob2RzLiA8YnI+PC9kaXY+PGRpdj5BcmUgeW91IHNheWluZyB0aGF0IHRoZSBzZXF1ZW5j
ZSBiZWhhdmlvdXIgd291bGQgc3RheSB0aGUgc2FtZSwgKGllLiBgX19pdGVyX19gLCBgX19yZXZl
c2VkX19gLCBgX19jb250YWluc19fYCksIGJ1dDxicj48L2Rpdj48ZGl2PmBucC5hc2FycmF5KG5w
Lm5kcmFuZ2UoKDMsIDMpKSlgPC9kaXY+PGRpdj53b3VsZCByZXR1cm4gc29tZXRoaW5nIGxpa2Ug
YW4gYXJyYXkgb2YgdHVwbGVzPzwvZGl2PjxkaXY+SSdtIG5vdCBzdXJlIHRoaXMgaXMgc29tZXRo
aW5nIHRoYXQgYW55Ym9keSBjYW4ndCBhbHJlYWR5IHdpdGggZG8gYG1lc2hncmlkYCArIHN0YWNr
PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj4mZ3Q7IGFuZCBvbmx5IGltcGxlbWVudCBtZXRob2Rz
IGFscmVhZHkgcHJlc2VudCBpbiBudW1weS48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkknbSBu
b3Qgc3VyZSB3aGF0IHRoaXMgbWVhbnMuPGJyPjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+SSds
bCBub3RlIHRoYXQgaW4gW1B5dGhvbiAzXShodHRwczovL2RvY3MucHl0aG9uLm9yZy8zL2xpYnJh
cnkvc3RkdHlwZXMuaHRtbCNzZXF1ZW5jZS10eXBlcy1saXN0LXR1cGxlLXJhbmdlKSwgcmFuZ2Ug
aXMgaXQncyBvd24gdGhpbmcuIEl0IGlzIHN0aWxsIGEgc2VxdWVuY2UgdHlwZSBidXQgaXQgZG9l
c24ndCBzdXBwb3J0IGFkZGl0aW9uLjwvZGl2PjxkaXY+SSdtIGtpbmRhIG9rIHdpdGggYG5kcmFu
Z2VgL2BuZGluZGV4YCBiZWluZyBhIHNlcXVlbmNlIHR5cGUsIHN1cHBvcnRpbmcgTkQgc2xpY2lu
ZywgYnV0IG5vdCBiZWluZyBhbiBhcnJheSA7KTxicj48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2
PkknbSBraW5kYSB3YXJtaW5nIHVwIHRvIHRoZSBpZGVhIG9mIGV4cGFuZGluZyBgbmRpbmRleGAu
PGJyPjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+MS4gVGhlIGFkZGl0aW9uYWwgYHN0YXJ0YCBh
bmQgYHN0ZXBgIGNhbiBiZSBvbWl0dGVkIGZyb20gYG5kaW5kZXhgIGZvciBhIHdoaWxlIChpbmRl
ZmluaXRlbHk/KS4gU2xpY2luZyBpcyB3YXkgbW9yZSBjb252ZW5pZW50IGFueXdheS48YnI+PC9k
aXY+PGRpdj4yLiBXYXJuaW5ncyBjYW4gaGVscCBwZW9wbGUgbW92ZSBmcm9tIGBuZC5pbmRleCgx
LCAyLCAzKWAgdG8gYG5kLmluZGV4KCgxLCAyLCAzKSlgPGJyPjwvZGl2PjxkaXY+My4gbmRpbmRl
eCBjYW4gcmV0dXJuIGEgc2VwZXJhdGUgaXRlcmF0b3IsIGJ1dCB0aGUgbmRpbmRleCBvYmplY3Qg
d291bGQgaG9sZCBhIHJlZmVyZW5jZSB0byBpdC4gQ2FsbHMgdG8gYG5kaW5kZXguX19uZXh0X19g
IHdvdWxkIHNpbXBseSBgcmV0dXJuIG5leHQob2ZfdGhhdF9vYmplY3QpYDwvZGl2PjxkaXY+Jm5i
c3A7Jm5ic3A7Jm5ic3A7IE5vdGUuIFRoaXMgd291bGQgYnJlYWsgaW50cm9zcGVjdGlvbiBzaW5j
ZSB0aGUgaXRlcmF0b3IgaXMgbm8gbG9uZ2VyIGBuZGluZGV4YCB0eXBlLiBJJ20ga2luZGEgT0sg
d2l0aCB0aGlzIHRob3VnaCwgYnV0IGJyZWFraW5nIGNvZGUgaXMgbmV2ZXIgbmljZSA6KDwvZGl2
PjxkaXY+NC4gQmVuY2gtbWFya2luZyBjYW4gaGVscCBtb3RpdmF0ZSB0aGUgY2hvaWNlIG9mIGl0
ZXJhdG9yIHVzZWQgZm9yIGBzdGVwPSgxLCkgKiBOYCBgc3RhcnQ9KDAsKSAqIE5gPC9kaXY+PGRp
dj41LiBXYWl0IHVudGlsIDIwMTkgYmVjYXVzZSBJIGRvbid0IHdhbnQgdG8gZGVhbCB3aXRoIHBl
cmZvcm1hbmNlIHJlZ3Jlc3Npb25zIG9mIHBvdGVudGlhbGx5IHVzaW5nIGByYW5nZWAgaW4gUHl0
aG9uMiBhbmQgSSBkb24ndCB3YW50IHRoaXMgdG8gbW90aXZhdGUgYW55IGltcGxlbWVudGF0aW9u
IGRldGFpbHMuPGJyPjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+TWFyazxicj48L2Rpdj48ZGl2
Pjxicj48L2Rpdj48L2Rpdj4=" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0"></div></div></div><br><div class="gmail_quote"><div dir="ltr">On Wed, Oct 10, 2018 at 12:36 AM Eric Wieser <<a href="mailto:wieser.eric%2Bnumpy@gmail.com">wieser.eric+numpy@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="m_-6486109353644383146markdown-here-wrapper" style="font-size:1em;font-family:Helvetica,arial,freesans,clean,sans-serif;color:rgb(34,34,34);background-color:rgb(255,255,255);border:none;line-height:1.2"><p style="margin:1em 0px">One thing that worries me here - in python, <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">range(...)</code> in essence generates a lazy <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">list</code> - so I’d expect <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndrange</code> to generate a lazy <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndarray</code>. In practice, that means it would be a duck-type defining an <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">__array__</code> method to evaluate it, and only implement methods already present in numpy.</p>
<p style="margin:1em 0px">It’s not clear to me what the datatype of such an array-like would be. Candidates I can think of are:</p>
<ol style="padding-left:2em;margin:1em 0px">
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">[('i0', intp), ('i1', intp), ...]</code>, but this makes tuple coercion a little awkward</li>
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">(intp, (N,))</code> - which collapses into a <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">shape + (3,)</code> array</li>
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">object_</code>.</li>
<li style="margin:1em 0px">Some new <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.tuple_</code> dtype, a heterogenous tuple, which is like the structured <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.void</code> but without field names. I’m not sure how vectorized element indexing would be spelt though.</li>
</ol>
<p style="margin:1em 0px">Eric</p>
<div title="MDH:T25lIHRoaW5nIHRoYXQgd29ycmllcyBtZSBoZXJlIC0gaW4gcHl0aG9uLCBgcmFuZ2UoLi4uKWAg
aW4gZXNzZW5jZSBnZW5lcmF0ZXMgYSBsYXp5IGBsaXN0YCAtIHNvIEknZCBleHBlY3QgYG5kcmFu
Z2VgIHRvIGdlbmVyYXRlIGEgbGF6eSBgbmRhcnJheWAuIEluIHByYWN0aWNlLCB0aGF0IG1lYW5z
IGl0IHdvdWxkIGJlIGEgZHVjay10eXBlIGRlZmluaW5nIGFuIGBfX2FycmF5X19gIG1ldGhvZCB0
byBldmFsdWF0ZSBpdCwgYW5kIG9ubHkgaW1wbGVtZW50IG1ldGhvZHMgYWxyZWFkeSBwcmVzZW50
IGluIG51bXB5LjxkaXY+PGJyPjwvZGl2PjxkaXY+SXQncyBub3QgY2xlYXIgdG8gbWUgd2hhdCB0
aGUgZGF0YXR5cGUgb2Ygc3VjaCBhbiBhcnJheS1saWtlIHdvdWxkIGJlLiBDYW5kaWRhdGVzIEkg
Y2FuIHRoaW5rIG9mIGFyZTo8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PjEuIGBbKCdpMCcsIGlu
dHApLCAoJ2kxJywgaW50cCksIC4uLl1gLCBidXQgdGhpcyBtYWtlcyB0dXBsZSBjb2VyY2lvbiBh
IGxpdHRsZSBhd2t3YXJkPC9kaXY+PGRpdj4yLiBgKGludHAsIChOLCkpYCAtIHdoaWNoIGNvbGxh
cHNlcyBpbnRvIGEgYHNoYXBlJm5ic3A7KyAoMywpYCBhcnJheTwvZGl2PjxkaXY+My4gYG9iamVj
dF9gLjwvZGl2PjxkaXY+NC4gU29tZSBuZXcgYG5wLnR1cGxlX2AgZHR5cGUsIGEgaGV0ZXJvZ2Vu
b3VzIHR1cGxlLCB3aGljaCBpcyBsaWtlIHRoZSBzdHJ1Y3R1cmVkIGBucC52b2lkYCBidXQgd2l0
aG91dCBmaWVsZCBuYW1lcy4gSSdtIG5vdCBzdXJlIGhvdyB2ZWN0b3JpemVkIGVsZW1lbnQgaW5k
ZXhpbmcgd291bGQgYmUgc3BlbHQgdGhvdWdoLjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+RXJp
YzwvZGl2Pg==" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div></div><br><div class="gmail_quote"><div dir="ltr">On Tue, 9 Oct 2018 at 21:59 Stephan Hoyer <<a href="mailto:shoyer@gmail.com" target="_blank">shoyer@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">The speed difference is interesting but really a different question than the public API.<div><br></div><div>I'm coming around to ndrange(). I can see how it could be useful for symbolic manipulation of arrays and indexing operations, similar to what we do in dask and xarray.</div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Oct 8, 2018 at 4:25 PM Mark Harfouche <<a href="mailto:mark.harfouche@gmail.com" target="_blank">mark.harfouche@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>since ndrange is a superset of the features of ndindex, we can implement ndindex with ndrange or keep it as is.</div><div>ndindex is now a glorified `nditer` object anyway. So it isn't so much of a maintenance burden. <br></div><div>As for how ndindex is implemented, I'm a little worried about python 2 performance seeing as range is a list. <br></div><div>I would wait on changing the way ndindex is implemented for now.<br></div><div><br></div><div>I agree with Stephan that ndindex should be kept in. Many want backward compatible code. It would be hard for me to justify why a dependency should be bumped up to bleeding edge numpy just for a convenience iterator.</div><div><br></div><div>Honestly, I was really surprised to see such a speed difference, I thought it would have been closer.</div><div><br></div><div></div><div>Allan, I decided to run a few more benchmarks, the nditer just seems slow for single array access some reason. Maybe a bug?</div><div><br></div><div>```</div><div>import numpy as np<br>import itertools<br>a = np.ones((1000, 1000))<br><br>b = {}<br>for i in np.ndindex(a.shape):<br>    b[i] = i<br></div><div><br>%%timeit</div><div># op_flag=('readonly',) doesn't change performance<br></div><div>for a_value in np.nditer(a):<br>    pass<br>109 ms ± 921 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)<br><br>%%timeit<br>for i in itertools.product(range(1000), range(1000)):<br>    a_value = a[i]<br>113 ms ± 1.72 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)<br><br>%%timeit<br>for i in itertools.product(range(1000), range(1000)):<br>    c = b[i]<br>193 ms ± 3.89 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)</div><div><br>%%timeit<br>for a_value in a.flat:<br>    pass<br>25.3 ms ± 278 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)</div><div><br></div><div>%%timeit<br>for k, v in b.items():<br>    pass<br>19.9 ms ± 675 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)</div><div><br></div><div>%%timeit<br>for i in itertools.product(range(1000), range(1000)):<br>    pass<br>28 ms ± 715 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)<br></div><div>```<br></div></div></div></div></div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Oct 8, 2018 at 4:26 PM Stephan Hoyer <<a href="mailto:shoyer@gmail.com" target="_blank">shoyer@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">I'm open to adding ndrange, and "soft-deprecating" ndindex (i.e., discouraging its use in our docs, but not actually deprecating it). Certainly ndrange seems like a small but meaningful improvement in the interface.<div><br></div><div>That said, I'm not convinced this is really worth the trouble. I think the nested loop is still pretty readable/clear, and there are few times when I've actually found ndindex() be useful.</div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Oct 8, 2018 at 12:35 PM Allan Haldane <<a href="mailto:allanhaldane@gmail.com" target="_blank">allanhaldane@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 10/8/18 12:21 PM, Mark Harfouche wrote:<br>
> 2. `ndindex` is an iterator itself. As proposed, `ndrange`, like<br>
> `range`, is not an iterator. Changing this behaviour would likely lead<br>
> to breaking code that uses that assumption. For example anybody using<br>
> introspection or code like:<br>
> <br>
> ```<br>
> indx = np.ndindex(5, 5)<br>
> next(indx)  # Don't look at the (0, 0) coordinate<br>
> for i in indx:<br>
>     print(i)<br>
> ```<br>
> would break if `ndindex` becomes "not an iterator"<br>
<br>
OK, I see now. Just like python3 has separate range and range_iterator<br>
types, where range is sliceable, we would have separate ndrange and<br>
ndindex types, where ndrange is sliceable. You're just copying the<br>
python3 api. That justifies it pretty well for me.<br>
<br>
I still think we shouldn't have two functions which do nearly the same<br>
thing. We should only have one, and get rid of the other. I see two ways<br>
forward:<br>
<br>
 * replace ndindex by your ndrange code, so it is no longer an iter.<br>
   This would require some deprecation cycles for the cases that break.<br>
 * deprecate ndindex in favor of a new function ndrange. We would keep<br>
   ndindex around for back-compatibility, with a dep warning to use<br>
   ndrange instead.<br>
<br>
Doing a code search on github, I can see that a lot of people's code<br>
would break if ndindex no longer was an iter. I also like the name<br>
ndrange for its allusion to python3's range behavior. That makes me lean<br>
towards the second option of a separate ndrange, with possible<br>
deprecation of ndindex.<br>
<br>
> itertools.product + range seems to be much faster than the current<br>
> implementation of ndindex<br>
> <br>
> (python 3.6)<br>
> ```<br>
> %%timeit<br>
> <br>
> for i in np.ndindex(100, 100):<br>
>     pass<br>
> 3.94 ms ± 19.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)<br>
> <br>
> %%timeit<br>
> import itertools<br>
> for i in itertools.product(range(100), range(100)):<br>
>     pass<br>
> 231 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)<br>
> ```<br>
<br>
If the new code ends up faster than the old code, that's great, and<br>
further justification for using ndrange instead of ndindex. I had<br>
thought using nditer in the old code was fastest.<br>
<br>
So as far as I am concerned, I say go ahead with the PR the way you are<br>
doing it.<br>
<br>
Allan<br>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>