Hi All,

On Fri, May 23, 2008 at 4:50 PM, Andrea Gavana wrote:
> Hi Peter & All,
>
> On Fri, May 23, 2008 at 4:16 PM, Peter Creasey wrote:
>> Hi Andrea,
>>
>> 2008/5/23  "Andrea Gavana" <[EMAIL PROTECTED]>:
>>> And so on. The probelm with this approach is that I lose the original
>>> indices for which I want all the inequality tests to succeed:
>>
>> To have the original indices you just need to re-index your indices, as it 
>> were
>>
>> idx = flatnonzero(xCent >= xMin)
>> idx = idx[flatnonzero(xCent[idx] <= xMax)]
>> idx = idx[flatnonzero(yCent[idx] >= yMin)]
>> idx = idx[flatnonzero(yCent[idx] <= yMax)]
>> ...
>> (I haven't tested this code, apologies for bugs)
>>
>> However, there is a performance penalty for doing all this re-indexing
>> (I once fell afoul of this), and if these conditions "mostly" evaluate
>> to True you can often be better off with one of the solutions already
>> suggested.
>
> Thank you for your answer. I have tried your suggestion, and the
> performances are more or less comparable with the other NumPy
> implementations (yours is roughly 1.2 times slower than the others),
> but I do gain some advantage when the subgrids are very small (i.e.,
> most of the values in the first array are already False). I'll go and
> implement your solution when I have many small subgrids in my model.

I have added a few more implementations for this issue. One think that
stroke me was that I could actually use sorted arrays for my xCent,
yCent and zCent vectors, so I came up with a solution which uses
numpy.searchsorted but the speed is more or less as it was without
sorting. The specific function is this:

def MultipleBoolean13():
    """ Numpy solution 5 (Andrea). """

    searchsorted = numpy.searchsorted

    indxStart, indxEnd = searchsorted(xCentS, [xMin, xMax])
    indyStart, indyEnd = searchsorted(yCentS, [yMin, yMax])
    indzStart, indzEnd = searchsorted(zCentS, [zMin, zMax])

    xInd = numpy.zeros((nCells), dtype=numpy.bool)
    yInd = xInd.copy()
    zInd = xInd.copy()

    xInd[xIndices[indxStart:indxEnd]] = True
    yInd[yIndices[indyStart:indyEnd]] = True
    zInd[zIndices[indzStart:indzEnd]] = True

    xyzReq = numpy.nonzero(xInd & yInd & zInd)[0]


Where xCentS, yCentS and zCentS are the sorted arrays. I don't see any
easy way to optimize this method, so I'd like to know if it is
possible to code it better than I did. I have done some testing and
timings of all the solutions we came up until now (12
implementations), and this is what I get (please notice the nice work
or ascii art :-D :-D  ):

*******************
* SUMMARY RESULTS *
*******************

---------------------------------------------------------------------
                       Number Of Cells: 50000
---------------------------------------------------------------------
| Rank |      Method Name      | Execution Time | Relative Slowness |
---------------------------------------------------------------------
   1        NumPy 5 (Andrea)       0.00562803          1.00000
   2       NumPy 1 (Francesc)      0.00563365          1.00100
   3        NumPy 2 (Nathan)       0.00577322          1.02580
   4    NumPy 4 (Nathan-Vector)    0.00580577          1.03158
   5       Fortran 6 (James)       0.00660514          1.17361
   6        Fortran 3 (Alex)       0.00709856          1.26129
   7       Fortran 5 (James)       0.00748726          1.33035
   8        Fortran 2 (Mine)       0.00748816          1.33051
   9        Fortran 1 (Mine)       0.00775906          1.37864
  10      Fortran 4 {Michael)      0.00777685          1.38181
  11        NumPy 3 (Peter)        0.01253662          2.22753
  12        Cython (Stefan)        0.01597804          2.83901
---------------------------------------------------------------------

---------------------------------------------------------------------
                       Number Of Cells: 100000
---------------------------------------------------------------------
| Rank |      Method Name      | Execution Time | Relative Slowness |
---------------------------------------------------------------------
   1        NumPy 5 (Andrea)       0.01080372          1.00000
   2        NumPy 2 (Nathan)       0.01109147          1.02663
   3       NumPy 1 (Francesc)      0.01114189          1.03130
   4    NumPy 4 (Nathan-Vector)    0.01214118          1.12380
   5       Fortran 6 (James)       0.01351264          1.25074
   6       Fortran 5 (James)       0.01368450          1.26665
   7        Fortran 3 (Alex)       0.01373010          1.27087
   8        Fortran 2 (Mine)       0.01415306          1.31002
   9        Fortran 1 (Mine)       0.01425558          1.31951
  10      Fortran 4 {Michael)      0.01443192          1.33583
  11        NumPy 3 (Peter)        0.02463268          2.28002
  12        Cython (Stefan)        0.04298108          3.97836
---------------------------------------------------------------------

---------------------------------------------------------------------
                       Number Of Cells: 150000
---------------------------------------------------------------------
| Rank |      Method Name      | Execution Time | Relative Slowness |
---------------------------------------------------------------------
   1       NumPy 1 (Francesc)      0.01613255          1.00000
   2        NumPy 5 (Andrea)       0.01619734          1.00402
   3        NumPy 2 (Nathan)       0.01647855          1.02145
   4    NumPy 4 (Nathan-Vector)    0.01779452          1.10302
   5        Fortran 3 (Alex)       0.02064676          1.27982
   6        Fortran 2 (Mine)       0.02382278          1.47669
   7      Fortran 4 {Michael)      0.02404563          1.49050
   8       Fortran 5 (James)       0.02734487          1.69501
   9       Fortran 6 (James)       0.02762538          1.71240
  10        Fortran 1 (Mine)       0.03028402          1.87720
  11        NumPy 3 (Peter)        0.03625735          2.24746
  12        Cython (Stefan)        0.07515276          4.65845
---------------------------------------------------------------------

---------------------------------------------------------------------
                       Number Of Cells: 200000
---------------------------------------------------------------------
| Rank |      Method Name      | Execution Time | Relative Slowness |
---------------------------------------------------------------------
   1        NumPy 5 (Andrea)       0.02187359          1.00000
   2       NumPy 1 (Francesc)      0.02309221          1.05571
   3        NumPy 2 (Nathan)       0.02323452          1.06222
   4    NumPy 4 (Nathan-Vector)    0.02378610          1.08743
   5        Fortran 3 (Alex)       0.02792134          1.27649
   6        Fortran 2 (Mine)       0.03119301          1.42606
   7      Fortran 4 {Michael)      0.03221007          1.47256
   8       Fortran 5 (James)       0.03584257          1.63862
   9       Fortran 6 (James)       0.03627464          1.65838
  10        Fortran 1 (Mine)       0.04048422          1.85083
  11        NumPy 3 (Peter)        0.04765184          2.17851
  12        Cython (Stefan)        0.09927396          4.53853
---------------------------------------------------------------------

---------------------------------------------------------------------
                       Number Of Cells: 250000
---------------------------------------------------------------------
| Rank |      Method Name      | Execution Time | Relative Slowness |
---------------------------------------------------------------------
   1        NumPy 5 (Andrea)       0.02651608          1.00000
   2       NumPy 1 (Francesc)      0.02864898          1.08044
   3        NumPy 2 (Nathan)       0.02933160          1.10618
   4    NumPy 4 (Nathan-Vector)    0.02960466          1.11648
   5        Fortran 3 (Alex)       0.03427299          1.29254
   6        Fortran 2 (Mine)       0.03848291          1.45130
   7      Fortran 4 {Michael)      0.03919467          1.47815
   8       Fortran 6 (James)       0.04430585          1.67091
   9       Fortran 5 (James)       0.04765620          1.79726
  10        Fortran 1 (Mine)       0.04914228          1.85330
  11        NumPy 3 (Peter)        0.05981760          2.25590
  12        Cython (Stefan)        0.12797177          4.82619
---------------------------------------------------------------------

---------------------------------------------------------------------
                       Number Of Cells: 300000
---------------------------------------------------------------------
| Rank |      Method Name      | Execution Time | Relative Slowness |
---------------------------------------------------------------------
   1        NumPy 5 (Andrea)       0.03365729          1.00000
   2       NumPy 1 (Francesc)      0.03470315          1.03107
   3        NumPy 2 (Nathan)       0.03519601          1.04572
   4    NumPy 4 (Nathan-Vector)    0.03529574          1.04868
   5        Fortran 3 (Alex)       0.04167365          1.23818
   6        Fortran 2 (Mine)       0.04653522          1.38262
   7      Fortran 4 {Michael)      0.04711222          1.39976
   8       Fortran 6 (James)       0.05287650          1.57103
   9       Fortran 5 (James)       0.05686667          1.68958
  10        Fortran 1 (Mine)       0.05913682          1.75703
  11        NumPy 3 (Peter)        0.07183072          2.13418
  12        Cython (Stefan)        0.15876811          4.71720
---------------------------------------------------------------------


******************************
* ELAPSED TIME: 64.828 Seconds *
******************************

Just in case someone is interested in it, I attach the source code of
the implementations I have so far. Thank you vey much for your
suggestions!

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/
# Begin Code

import time
import numpy
from timeit import Timer

# FORTRAN modules
from MultipleBooleanFortran import multipleboolean3, multipleboolean4
from MultipleBooleanFortran import multipleboolean7, multipleboolean8
from MultipleBooleanFortran import multipleboolean10, multipleboolean11

# Cython implementation
from MultipleBooleanCython import multipleboolean6

# Define some constraints for X, Y, Z (constants all over the tests)
xMin, xMax = 250.0, 700.0
yMin, yMax = 1000.0, 1900.0
zMin, zMax = 120.0, 300.0

# And a couple of vectors to hold them (needed by a Fortran solution)
xyzMin = [xMin, yMin, zMin]
xyzMax = [xMax, yMax, zMax]


def MultipleBoolean2():
    """ Numpy solution 1 (Francesc). """

    xyzReq = (xCent >= xMin) & (xCent <= xMax) &  \
             (yCent >= yMin) & (yCent <= yMax) &  \
             (zCent >= zMin) & (zCent <= zMax)

    xyzReq = numpy.nonzero(xyzReq)[0]


def MultipleBoolean3():
    """ Fortran solution 1 (Mine). """

    xyzReq = multipleboolean3(xCent, yCent, zCent, xMin, xMax, yMin, yMax, 
zMin, zMax, nCells)
    xyzReq = numpy.nonzero(xyzReq)[0]


def MultipleBoolean4():
    """ Fortran solution 2 (Mine). """

    xyzReq = multipleboolean4(xCent, yCent, zCent, xMin, xMax, yMin, yMax, 
zMin, zMax, nCells)
    xyzReq = numpy.nonzero(xyzReq)[0]
    

def MultipleBoolean5():
    """ Numpy solution 2 (Nathan). """

    xyzReq = (xCent >= xMin)
    xyzReq &= (xCent <= xMax)
    xyzReq &= (yCent >= yMin)
    xyzReq &= (yCent <= yMax)
    xyzReq &= (zCent >= zMin)
    xyzReq &= (zCent <= zMax)

    xyzReq = numpy.nonzero(xyzReq)[0]

    
def MultipleBoolean6():
    """ Cython solution (Stefan). """

    xyzReq = multipleboolean6(xCent, xMin, xMax, yCent, yMin, yMax, zCent, 
zMin, zMax)
    xyzReq = numpy.nonzero(xyzReq)[0]
    

def MultipleBoolean7():
    """ Fortran solution 3 (Alex). """

    xyzReq = multipleboolean7(xyzCent, xyzMin, xyzMax, nCells)
    xyzReq = numpy.nonzero(xyzReq)[0]


def MultipleBoolean8():
    """ Fortran solution 4 (Michael). """

    xyzReq = multipleboolean8(xCent, yCent, zCent, xMin, xMax, yMin, yMax, 
zMin, zMax, nCells)
    xyzReq = numpy.nonzero(xyzReq)[0]


def MultipleBoolean9():
    """ Numpy solution 3 (Peter) . """

    flatnonzero = numpy.flatnonzero
    
    idx = flatnonzero(xCent >= xMin)
    idx = idx[flatnonzero(xCent[idx] <= xMax)]
    idx = idx[flatnonzero(yCent[idx] >= yMin)]
    idx = idx[flatnonzero(yCent[idx] <= yMax)]
    idx = idx[flatnonzero(zCent[idx] >= zMin)]
    idx = idx[flatnonzero(zCent[idx] <= zMax)]
    

def MultipleBoolean10():
    """ Fortran solution 5 (Michael). """

    xyzReq = multipleboolean10(xCent, yCent, zCent, xMin, xMax, yMin, yMax, 
zMin, zMax, nCells)
    xyzReq = numpy.nonzero(xyzReq)[0]


def MultipleBoolean11():
    """ Fortran solution 6 (Michael). """

    xyzReq = multipleboolean11(xCent, yCent, zCent, xMin, xMax, yMin, yMax, 
zMin, zMax, nCells)
    xyzReq = numpy.nonzero(xyzReq)[0]

    
def MultipleBoolean12():
    """ Numpy solution 3 (Nathan). """

    xyzReq = (xyzCent2[0, :] >= xyzMin[0])
    xyzReq &= (xyzCent2[0, :] <= xyzMax[0])
    xyzReq &= (xyzCent2[1, :] >= xyzMin[1])
    xyzReq &= (xyzCent2[1, :] <= xyzMax[1])
    xyzReq &= (xyzCent2[2, :] >= xyzMin[2])
    xyzReq &= (xyzCent2[2, :] <= xyzMax[2])

    xyzReq = numpy.nonzero(xyzReq)[0]


def MultipleBoolean13():
    """ Numpy solution 5 (Andrea). """

    searchsorted = numpy.searchsorted

    indxStart, indxEnd = searchsorted(xCentS, [xMin, xMax])
    indyStart, indyEnd = searchsorted(yCentS, [yMin, yMax])
    indzStart, indzEnd = searchsorted(zCentS, [zMin, zMax])

    xInd = numpy.zeros((nCells), dtype=numpy.bool)
    yInd = xInd.copy()
    zInd = xInd.copy()
    
    xInd[xIndices[indxStart:indxEnd]] = True
    yInd[yIndices[indyStart:indyEnd]] = True
    zInd[zIndices[indzStart:indzEnd]] = True

    xyzReq = numpy.nonzero(xInd & yInd & zInd)[0]
    


def intersect(a, b):
    """ return the intersection of two lists """
    return list(set(a) & set(b))

    
def GenerateInputs(nCells):   

    # Generate random centroids for the cells
    xCent = 1000.0*numpy.random.rand(nCells)
    yCent = 2500.0*numpy.random.rand(nCells)
    zCent = 400.0*numpy.random.rand(nCells)

    # These are needed for multipleboolean7 and multipleboolean8
    xyzCent = numpy.empty((nCells, 3))
    xyzCent[:, 0] = xCent
    xyzCent[:, 1] = yCent
    xyzCent[:, 2] = zCent

    xyzCent2 = numpy.empty((3, nCells))
    xyzCent2[0, :] = xCent
    xyzCent2[1, :] = yCent
    xyzCent2[2, :] = zCent

    indices = range(len(xCent))
    xCentSorted = xCent.copy()
    xCentSorted = zip(xCentSorted, indices)
    xCentSorted = sorted(xCentSorted)
    
    yCentSorted = yCent.copy()
    yCentSorted = zip(yCentSorted, indices)
    yCentSorted = sorted(yCentSorted)

    zCentSorted = zCent.copy()
    zCentSorted = zip(zCentSorted, indices)
    zCentSorted = sorted(zCentSorted)

    ravel = numpy.ravel
    xCentS, xIndices = ravel([x[0] for x in xCentSorted]), ravel([x[1] for x in 
xCentSorted])
    yCentS, yIndices = ravel([y[0] for y in yCentSorted]), ravel([y[1] for y in 
yCentSorted])
    zCentS, zIndices = ravel([z[0] for z in zCentSorted]), ravel([z[1] for z in 
zCentSorted])

    return xCent, yCent, zCent, xyzCent, xyzCent2, xCentS, yCentS, zCentS, 
xIndices, yIndices, zIndices


def FormatTime(timerDict):

    methodNames = ["NumPy 1 (Francesc)", "NumPy 2 (Nathan)", "Cython (Stefan)",
                   "Fortran 1 (Mine)", "Fortran 2 (Mine)", "Fortran 3 (Alex)",
                   "Fortran 4 {Michael)", "NumPy 3 (Peter)", "Fortran 5 
(James)",
                   "Fortran 6 (James)", "NumPy 4 (Nathan-Vector)", "NumPy 5 
(Andrea)"]

    nCells = timerDict.keys()
    nCells.sort()

    print "\n\n"
    print "*"*19
    print "* SUMMARY RESULTS *"
    print "*"*19, "\n"

    topText = "| Rank |      Method Name      | Execution Time | Relative 
Slowness |"
    separator = "-"*len(topText)
    maxLen = max([len(text) for text in methodNames])

    for cells in nCells:
        print separator
        print ("Number Of Cells: %d "%cells).center(len(topText))
        print separator
        print topText
        print separator
        
        ranking = sorted(timerDict[cells])
        maxSpeed = ranking[0][0]
        counter = 1
        
        for timer, methodNumber in ranking:
            name = methodNames[methodNumber]
            print "%4d    %s    %0.8f          %0.5f"% \
                  (counter, name.center(maxLen), timer, timer/maxSpeed)
            counter += 1
            
        print separator
        print

    print
    

timerDict = {}
repeat = 10

startTime = time.time()

for nCells in xrange(50000, 350000, 50000):

    xCent, yCent, zCent, xyzCent, xyzCent2, xCentS, yCentS, zCentS, xIndices, 
yIndices, zIndices = GenerateInputs(nCells)

    t = Timer("MultipleBoolean2()", "from __main__ import MultipleBoolean2")
    t1 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean5()", "from __main__ import MultipleBoolean5")
    t2 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean6()", "from __main__ import MultipleBoolean6")
    t3 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean3()", "from __main__ import MultipleBoolean3")
    t4 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean4()", "from __main__ import MultipleBoolean4")
    t5 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean7()", "from __main__ import MultipleBoolean7")
    t6 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean8()", "from __main__ import MultipleBoolean8")
    t7 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean9()", "from __main__ import MultipleBoolean9")
    t8 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean10()", "from __main__ import MultipleBoolean10")
    t9 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean11()", "from __main__ import MultipleBoolean11")
    t10 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean12()", "from __main__ import MultipleBoolean12")
    t11 = t.timeit(number=repeat)/repeat

    t = Timer("MultipleBoolean13()", "from __main__ import MultipleBoolean13")
    t12 = t.timeit(number=repeat)/repeat

    timerDict[nCells] = [(t1, 0), (t2, 1), (t3, 2), (t4, 3),
                         (t5, 4), (t6, 5), (t7, 6), (t8, 7),
                         (t9, 8), (t10, 9), (t11, 10), (t12, 11)]

FormatTime(timerDict)

print "*"*30
print "* ELAPSED TIME: %0.5g Seconds *"%(time.time() - startTime)
print "*"*30, "\n\n"

# End Code

Attachment: MultipleBooleanCython.pyx
Description: Binary data

Attachment: numpy.pxi
Description: Binary data

Attachment: python.pxi
Description: Binary data

Attachment: MultipleBooleanFortran.f90
Description: Binary data

_______________________________________________
Numpy-discussion mailing list
Numpy-discussion@scipy.org
http://projects.scipy.org/mailman/listinfo/numpy-discussion

Reply via email to