<br><br><div class="gmail_quote">On Thu, Jan 19, 2012 at 6:25 PM, Wes McKinney <span dir="ltr">&lt;<a href="mailto:wesmckinn@gmail.com">wesmckinn@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="HOEnZb"><div class="h5">On Thu, Jan 19, 2012 at 7:20 PM, Alex Gaynor &lt;<a href="mailto:alex.gaynor@gmail.com">alex.gaynor@gmail.com</a>&gt; wrote:<br>
&gt;<br>
&gt;<br>
&gt; On Thu, Jan 19, 2012 at 6:15 PM, Wes McKinney &lt;<a href="mailto:wesmckinn@gmail.com">wesmckinn@gmail.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; On Thu, Jan 19, 2012 at 2:49 PM, Dmitrey &lt;<a href="mailto:dmitrey15@ukr.net">dmitrey15@ukr.net</a>&gt; wrote:<br>
&gt;&gt; &gt; On 01/19/2012 07:31 PM, Maciej Fijalkowski wrote:<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; On Thu, Jan 19, 2012 at 6:46 PM, Dmitrey&lt;<a href="mailto:dmitrey15@ukr.net">dmitrey15@ukr.net</a>&gt;  wrote:<br>
&gt;&gt; &gt;&gt;&gt;<br>
&gt;&gt; &gt;&gt;&gt; Hi all,<br>
&gt;&gt; &gt;&gt;&gt; could you provide clarification to numpypy new funcs accepting (not<br>
&gt;&gt; &gt;&gt;&gt; only<br>
&gt;&gt; &gt;&gt;&gt; for<br>
&gt;&gt; &gt;&gt;&gt; me, but for any other possible volunteers)?<br>
&gt;&gt; &gt;&gt;&gt; The doc I&#39;ve been directed says only &quot;You have to test exhaustively<br>
&gt;&gt; &gt;&gt;&gt; your<br>
&gt;&gt; &gt;&gt;&gt; module&quot;, while I would like to know more explicit rules.<br>
&gt;&gt; &gt;&gt;&gt; For example, &quot;at least 3 tests per func&quot; (however, I guess for funcs<br>
&gt;&gt; &gt;&gt;&gt; of<br>
&gt;&gt; &gt;&gt;&gt; different complexity and variability number of tests also should<br>
&gt;&gt; &gt;&gt;&gt; expected<br>
&gt;&gt; &gt;&gt;&gt; to<br>
&gt;&gt; &gt;&gt;&gt; be different).<br>
&gt;&gt; &gt;&gt;&gt; Also, are there any strict rules for the testcases to be submitted, or<br>
&gt;&gt; &gt;&gt;&gt; I,<br>
&gt;&gt; &gt;&gt;&gt; for example, can mere write<br>
&gt;&gt; &gt;&gt;&gt;<br>
&gt;&gt; &gt;&gt;&gt; if __name__ == &#39;__main__&#39;:<br>
&gt;&gt; &gt;&gt;&gt;    assert array_equal(1, 1)<br>
&gt;&gt; &gt;&gt;&gt;    assert array_equal([1, 2], [1, 2])<br>
&gt;&gt; &gt;&gt;&gt;    assert array_equal(N.array([1, 2]), N.array([1, 2]))<br>
&gt;&gt; &gt;&gt;&gt;    assert array_equal([1, 2], N.array([1, 2]))<br>
&gt;&gt; &gt;&gt;&gt;    assert array_equal([1, 2], [1, 2, 3]) is False<br>
&gt;&gt; &gt;&gt;&gt;    print(&#39;passed&#39;)<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; We have pretty exhaustive automated testing suites. Look for example<br>
&gt;&gt; &gt;&gt; in pypy/module/micronumpy/test directory for the test file style.<br>
&gt;&gt; &gt;&gt; They&#39;re run with py.test and we require at the very least full code<br>
&gt;&gt; &gt;&gt; coverage (every line has to be executed, there are tools to check,<br>
&gt;&gt; &gt;&gt; like coverage). Also passing &quot;unusual&quot; input, like sys.maxint  etc. is<br>
&gt;&gt; &gt;&gt; usually recommended. With your example, you would check if it works<br>
&gt;&gt; &gt;&gt; for say views and multidimensional arrays. Also &quot;is False&quot; is not<br>
&gt;&gt; &gt;&gt; considered good style.<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt;&gt; Or there is a certain rule for storing files with tests?<br>
&gt;&gt; &gt;&gt;&gt;<br>
&gt;&gt; &gt;&gt;&gt; If I or someone else will submit a func with some tests like in the<br>
&gt;&gt; &gt;&gt;&gt; example<br>
&gt;&gt; &gt;&gt;&gt; above, will you put the func and tests in the proper files by<br>
&gt;&gt; &gt;&gt;&gt; yourself?<br>
&gt;&gt; &gt;&gt;&gt; I&#39;m<br>
&gt;&gt; &gt;&gt;&gt; not lazy to go for it by myself, but I mere no merged enough into<br>
&gt;&gt; &gt;&gt;&gt; numpypy<br>
&gt;&gt; &gt;&gt;&gt; dev process, including mercurial branches and numpypy files structure,<br>
&gt;&gt; &gt;&gt;&gt; and<br>
&gt;&gt; &gt;&gt;&gt; can spend only quite limited time for diving into it in nearest<br>
&gt;&gt; &gt;&gt;&gt; future.<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; We generally require people to put their own tests as they go with the<br>
&gt;&gt; &gt;&gt; code (in appropriate places) because you also should not break<br>
&gt;&gt; &gt;&gt; anything. The usefullness of a patch that has to be sliced and diced<br>
&gt;&gt; &gt;&gt; and put into places is very limited and for straightforward<br>
&gt;&gt; &gt;&gt; mostly-copied code, like array_equal, plain useless, since it&#39;s almost<br>
&gt;&gt; &gt;&gt; as much work to just do it.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Well, for this func (array_equal) my docstrings really were copied from<br>
&gt;&gt; &gt; cpython numpy (why wouln&#39;t do this to save some time, while license<br>
&gt;&gt; &gt; allows<br>
&gt;&gt; &gt; it?), but<br>
&gt;&gt; &gt; * why would&#39;n go for this (), while other programmers are busy by other<br>
&gt;&gt; &gt; tasks?<br>
&gt;&gt; &gt; * engines of my and CPython numpy funcs complitely differs. At first, in<br>
&gt;&gt; &gt; PyPy the CPython code just doesn&#39;t work at all (because of the problem<br>
&gt;&gt; &gt; with<br>
&gt;&gt; &gt; ndarray.flat). At 2nd, I have implemented walkaround - just replaced<br>
&gt;&gt; &gt; some<br>
&gt;&gt; &gt; code lines by<br>
&gt;&gt; &gt;    Size = a1.size<br>
&gt;&gt; &gt;    f1, f2 = a1.flat, a2.flat<br>
&gt;&gt; &gt;    # TODO: replace xrange by range in Python3<br>
&gt;&gt; &gt;    for i in xrange(Size):<br>
&gt;&gt; &gt;        if f1.next() != f2.next(): return False<br>
&gt;&gt; &gt;    return True<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Here are some results in CPython for the following bench:<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; from time import time<br>
&gt;&gt; &gt; n = 100000<br>
&gt;&gt; &gt; m = 100<br>
&gt;&gt; &gt; a = N.zeros(n)<br>
&gt;&gt; &gt; b = N.ones(n)<br>
&gt;&gt; &gt; t = time()<br>
&gt;&gt; &gt; for i in range(m):<br>
&gt;&gt; &gt;    N.array_equal(a, b)<br>
&gt;&gt; &gt; print(&#39;classic numpy array_equal time elapsed (on different arrays):<br>
&gt;&gt; &gt; %0.5f&#39;<br>
&gt;&gt; &gt; % (time()-t))<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; t = time()<br>
&gt;&gt; &gt; for i in range(m):<br>
&gt;&gt; &gt;    array_equal(a, b)<br>
&gt;&gt; &gt; print(&#39;Alternative array_equal time elapsed (on different arrays):<br>
&gt;&gt; &gt; %0.5f&#39; %<br>
&gt;&gt; &gt; (time()-t))<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; b = N.zeros(n)<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; t = time()<br>
&gt;&gt; &gt; for i in range(m):<br>
&gt;&gt; &gt;    N.array_equal(a, b)<br>
&gt;&gt; &gt; print(&#39;classic numpy array_equal time elapsed (on same arrays): %0.5f&#39; %<br>
&gt;&gt; &gt; (time()-t))<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; t = time()<br>
&gt;&gt; &gt; for i in range(m):<br>
&gt;&gt; &gt;    array_equal(a, b)<br>
&gt;&gt; &gt; print(&#39;Alternative array_equal time elapsed (on same arrays): %0.5f&#39; %<br>
&gt;&gt; &gt; (time()-t))<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; CPython numpy results:<br>
&gt;&gt; &gt; classic numpy array_equal time elapsed (on different arrays): 0.07728<br>
&gt;&gt; &gt; Alternative array_equal time elapsed (on different arrays): 0.00056<br>
&gt;&gt; &gt; classic numpy array_equal time elapsed (on same arrays): 0.11163<br>
&gt;&gt; &gt; Alternative array_equal time elapsed (on same arrays): 9.09458<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; PyPy results (cannot test on &quot;classic&quot; version because it depends on<br>
&gt;&gt; &gt; some<br>
&gt;&gt; &gt; funcs that are unavailable yet):<br>
&gt;&gt; &gt; Alternative array_equal time elapsed (on different arrays): 0.00133<br>
&gt;&gt; &gt; Alternative array_equal time elapsed (on same arrays): 0.95038<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; So, as you see, even in CPython numpy my version is 138 times faster for<br>
&gt;&gt; &gt; different arrays (yet slower in 90 times for same arrays). However, in<br>
&gt;&gt; &gt; real<br>
&gt;&gt; &gt; world usually different arrays come to this func, and only sometimes<br>
&gt;&gt; &gt; similar<br>
&gt;&gt; &gt; arrays are encountered.<br>
&gt;&gt; &gt; Well, for my implementation for case of equal arrays time elapsed<br>
&gt;&gt; &gt; essentially depends on their size, but in either way I still think my<br>
&gt;&gt; &gt; implementation is better than CPython, - it&#39;s faster and doesn&#39;t require<br>
&gt;&gt; &gt; allocation of memory for the boolean array, that will go to the<br>
&gt;&gt; &gt; logical_and.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; I updated my array_equal implementation with the changes mentioned<br>
&gt;&gt; &gt; above,<br>
&gt;&gt; &gt; some tests on multidimensional arrays you&#39;ve asked and put it in<br>
&gt;&gt; &gt; <a href="http://pastebin.com/tg2aHE6x" target="_blank">http://pastebin.com/tg2aHE6x</a> (now I&#39;ll update the <a href="http://bugs.pypy.org" target="_blank">bugs.pypy.org</a> entry<br>
&gt;&gt; &gt; with<br>
&gt;&gt; &gt; the link).<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; -----------------------<br>
&gt;&gt; &gt; Regards, D.<br>
&gt;&gt; &gt; <a href="http://openopt.org/Dmitrey" target="_blank">http://openopt.org/Dmitrey</a><br>
&gt;&gt; &gt; _______________________________________________<br>
&gt;&gt; &gt; pypy-dev mailing list<br>
&gt;&gt; &gt; <a href="mailto:pypy-dev@python.org">pypy-dev@python.org</a><br>
&gt;&gt; &gt; <a href="http://mail.python.org/mailman/listinfo/pypy-dev" target="_blank">http://mail.python.org/mailman/listinfo/pypy-dev</a><br>
&gt;&gt;<br>
&gt;&gt; Worth pointing out that the implementation of array_equal and<br>
&gt;&gt; array_equiv in NumPy are a bit embarrassing because they require a<br>
&gt;&gt; full N comparisons instead of short-circuiting whenever a False value<br>
&gt;&gt; is found. This is completely silly IMHO:<br>
&gt;&gt;<br>
&gt;&gt; In [34]: x = np.random.randn(100000)<br>
&gt;&gt;<br>
&gt;&gt; In [35]: y = np.random.randn(100000)<br>
&gt;&gt;<br>
&gt;&gt; In [36]: timeit np.array_equal(x, y)<br>
&gt;&gt; 1000 loops, best of 3: 349 us per loop<br>
&gt;&gt;<br>
&gt;&gt; - W<br>
&gt;&gt; _______________________________________________<br>
&gt;&gt; pypy-dev mailing list<br>
&gt;&gt; <a href="mailto:pypy-dev@python.org">pypy-dev@python.org</a><br>
&gt;&gt; <a href="http://mail.python.org/mailman/listinfo/pypy-dev" target="_blank">http://mail.python.org/mailman/listinfo/pypy-dev</a><br>
&gt;<br>
&gt;<br>
&gt; The correct solution (IMO), is to reuse the original NumPy implementation,<br>
&gt; but have logical_and.reduce short circuit correctly.  This has the nice side<br>
&gt; effect of allowing all() and any() to use logical_and/logical_or.reduce.<br>
&gt;<br>
&gt; Alx<br>
<br>
</div></div>To do that, you&#39;re going to have to work around the eagerness of<br>
Python-- it sort of makes me cringe to see you guys copying<br>
eager-beaver NumPy when you have a wonderful opportunity to do<br>
something better. Imagine if NumPy and APL/J/K had a lazy functional<br>
lovechild implemented in PyPy. Though maybe you&#39;re already 10 steps<br>
ahead of me.<br></blockquote><div><br></div><div>Well, you&#39;re the first person to ever express the sentiment that we should do something else :)  But I think you&#39;ll be pleased, read on! </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<br>
Hopefully you could make the JIT automatically take a simple array<br>
expression like this:<br>
<br>
bool(logical_and.reduce(equal(a1,a2).ravel()))<br>
<br>
and examine the array expression and turn it into an ultra fast<br>
functional expression that short circuits immediately:<br>
<br>
for x, y in zip(a1, a2):<br>
    if x != y:<br>
        return False<br>
return True<br>
<br>
To do that you would need to make all your ufuncs return generators<br>
instead of ndarrays. With the JIT infrastructure you could probably<br>
make this work. If ever ufunc yields a generator you could build<br>
functional array pipelines (now I&#39;m talking like Peter Wang). But if<br>
you insist on replicating C NumPy, well...<br>
<div class="HOEnZb"><div class="h5"><br>
W<br>
<br>
&gt;<br>
&gt; --<br>
&gt; &quot;I disapprove of what you say, but I will defend to the death your right to<br>
&gt; say it.&quot; -- Evelyn Beatrice Hall (summarizing Voltaire)<br>
&gt; &quot;The people&#39;s good is the highest law.&quot; -- Cicero<br>
&gt;<br>
</div></div></blockquote></div><br>These don&#39;t need to return generators, they just need to return things that look like ndarrays, but are internally lazy.  And that&#39;s exactly what we do.<div><br></div><div>Using .all() instead of logical_and.reduce() (since we don&#39;t have logical_and yet, and even if we did it wouldn&#39;t short circuit without some extra work), the JIT will generate almost exactly the code you posted (except in x86 :P).</div>
<div><br></div><div>Alex<br clear="all"><div><br></div>-- <br>&quot;I disapprove of what you say, but I will defend to the death your right to say it.&quot; -- Evelyn Beatrice Hall (summarizing Voltaire)<br>&quot;The people&#39;s good is the highest law.&quot; -- Cicero<br>
<br>
</div>