Numeric supplies named functions with the same semantics as Python's arithmetic, comparison, and bitwise operators. Similar semantics (element-wise operation, broadcasting, coercion) are also available with other mathematical functions, both binary and unary, that Numeric supplies. For example, Numeric supplies typical mathematical functions similar to those supplied by built-in module math, such as sin, cos, log, and exp.
These functions are objects of type ufunc (which stands for universal function) and share several traits in addition to those they have in common with array operators. Every ufunc instance u is callable, is applicable to sequences as well as to arrays, and lets you specify an optional output argument. If u is binary (i.e., if u accepts two operand arguments), u also has four callable attributes, named u.accumulate, u.outer, u.reduce, and u.reduceat. The ufunc objects supplied by Numeric apply only to arrays with numeric type codes (i.e., not to arrays with type code 'O' or 'c').
Any ufunc u applies to sequences, not just to arrays. When you start with a list L, it's faster to call u directly on L rather than to convert L to an array. u's return value is an array a; you can perform further computation, if any, on a, and then, if you need a list result, you can convert the resulting array to a list by calling its method tolist. For example, say you must compute the logarithm of each item of a list and return another list. On my system, with N set to 2222 and using python -O, a list comprehension such as:
def logsupto(N): return [math.log(x) for x in range(2,N)]
takes about 5.6 milliseconds. Using Python's built-in map:
def logsupto(N): return map(math.log, range(2,N))
takes around half the time, 2.8 milliseconds. Using Numeric's ufunc named log:
def logsupto(N): return Numeric.log(range(2,N)).tolist( )
reduces the time to about 2.0 milliseconds. Taking some care to exploit the output argument to the log ufunc:
def logsupto(N): temp = Numeric.arange(2, N, typecode=Numeric.Float) Numeric.log(temp, temp) return temp.tolist( )
further reduces the time, down to just 0.9 milliseconds. The ability to accelerate such simple but massive computations (here by about 6 times) with so little effort is a good part of the attraction of Numeric, and particularly of Numeric's ufunc objects.
Any ufunc u accepts an optional last argument output that specifies an output array. If supplied, output must be an array or array slice of the right shape and type for u's results (i.e., no coercion, no broadcasting). u stores results in output and does not create a new array. output can be the same as an input array argument a of u. Indeed, output is normally specified in order to substitute common idioms such as a=u(a,b) with faster equivalents such as u(a,b,a). However, output cannot share data with a without being a (i.e., output can't be a different view of some or all of a's data). If you pass such a disallowed output argument, Numeric is normally unable to diagnose your error and raise an exception, so instead you get wrong results.
Whether you pass the optional output argument or not, a ufunc u returns its results as the function's return value. When you do not pass output, u stores the results it returns in a new array object, so you normally bind u's return value to some reference in order to be able to access u's results later. When you pass the output argument, u stores the results in output, so you need not bind u's return value. You can later access u's results as the new contents of the array object passed as output.
Every binary ufunc u supplies four attributes that are also callable objects.
accumulate |
u.accumulate(a,axis=0) |
Returns an array r with the same shape and type code as a. Each element of r is the accumulation of elements of a along the given axis with the function or operator underlying u. For example:
print add.accumulate(range(10)) # prints: [0 1 3 6 10 15 21 28 36 45]
Since add's underlying operator is +, and a is sequence 0,1,2,...,9, r is 0,0+1,0+1+2,...,0+1+...+8+9. In other words, r[0] is a[0], r[1] is r[0] + a[1], r[2] is r[1] + a[2], and so on (i.e., each r[i] is r[i-1] + a[i]).
outer |
u.outer(a,b) |
Returns an array r whose shape tuple is a.shape+b.shape. For each tuple ta indexing a and tb indexing b, a[ta], operated (with the function or operator underlying u) with b[tb], is put in r[ta+tb] (the + here indicates tuple concatenation). The overall operation is known in mathematics as the outer product when u is multiply. For example:
a = Numeric.arange(3, 5) b = Numeric.arange(1, 6) c = Numeric.multiply.outer(a, b) print a.shape, b.shape, c.shape # prints: (2,) (5,) (2,5) print c # prints: [[3 6 9 12 15] # [4 8 12 16 20]]
c.shape is (2,5), the concatenation of the shape tuples of operands a and b. Each i row of c is the whole of b multiplied by the corresponding i element of a.
reduce |
u.reduce(a,axis=0) |
Returns an array r with the same type code as a and rank one less than a's rank. Each element of r is the reduction of the elements of a, along the given axis, with the function or operator underlying u. The functionality of u.reduce is therefore close to that of Python's built-in reduce function, covered in Chapter 8. For example, since 0+1+2+...+9 is 45, add.reduce(range(10)) is 45. This is just like, when using built-in reduce and import operator, reduce(operator.add,range(10)) is also 45.
reduceat |
u.reduceat(a,indices) |
Returns an array r with the same type code as a and the same shape as indices. Each element of r is the reduction, with the function or operator underlying u, of elements of a starting from the corresponding item of indices up to the next one excluded (up to the end, for the last one). For example:
print add.reduceat(range(10),(2,6,8)) # prints: [14 13 17]
Here, r's elements are the partial sums 2+3+4+5, 6+7, and 8+9.
Numeric supplies several ufunc objects, as listed in Table 15-4.
ufunc |
Behavior |
---|---|
absolute |
Behaves like the abs built-in function |
add |
Behaves like the + operator |
arccos |
Behaves like the acos function in math and cmath |
arccosh |
Behaves like the acosh function in cmath |
arcsin |
Behaves like the asin function in math and cmath |
arcsinh |
Behaves like the asinh function in cmath |
arctan |
Behaves like the atan function in math and cmath |
arctanh |
Behaves like the atanh function in cmath |
bitwise_and |
Behaves like the & operator |
bitwise_not |
Behaves like the ~ operator |
bitwise_or |
Behaves like the | operator |
bitwise_xor |
Behaves like the ^ operator |
ceil |
Behaves like the ceil function in math |
conjugate |
Computes the complex conjugate of each element (unary) |
cos |
Behaves like the cos function in math and cmath |
cosh |
Behaves like the cosh function in cmath |
divide |
Behaves like the / operator |
equal |
Behaves like the = = operator |
exp |
Behaves like the exp function in math and cmath |
fabs |
Behaves like the fabs function in math |
floor |
Behaves like the floor function in math |
fmod |
Behaves like the fmod function in math |
greater |
Behaves like the > operator |
greater_equal |
Behaves like the /= operator |
less |
Behaves like the < operator |
less_equal |
Behaves like the <= operator |
log |
Behaves like the log function in math and cmath |
log10 |
Behaves like the log10 function in math and cmath |
logical_and |
Behaves like the & operator; always returns an array containing 0s and 1s, the truth values of the operands' elements |
logical_not |
Returns an array of 0s and 1s, logical negations of the operand's elements |
logical_or |
Behaves like the | operator; always returns an array containing 0s and 1s, the truth values of the operands' elements |
logical_xor |
Behaves like the ^ operator; always returns an array containing 0s and 1s, the truth values of the operands' elements |
maximum |
Returns element-wise the larger of the two elements being operated on |
minimum |
Returns element-wise the smaller of the two elements being operated on |
multiply |
Behaves like the * operator |
not_equal |
Behaves like the != operator |
power |
Behaves like the ** operator |
remainder |
Behaves like the % operator |
sin |
Behaves like the sin function in math and cmath |
sinh |
Behaves like the sinh function in cmath |
sqrt |
Behaves like the sqrt function in math and cmath |
subtract |
Behaves like the - operator |
tan |
Behaves like the tan function in math and cmath |
tanh |
Behaves like the tanh function in cmath |
Here's how you might use the maximum ufunc to get a numeric ramp that goes down and then back up again:
print Numeric.maximum(range(1,20),range(20,1,-1)) # prints: [20 19 18 17 16 15 14 13 12 11 11 12 13 14 15 16 17 18 19]
Numeric defines function synonyms for some commonly used methods of ufunc objects, as listed in Table 15-5.
Synonym |
Stands for |
---|---|
alltrue |
logical_and.reduce |
cumproduct |
multiply.accumulate |
cumsum |
add.accumulate |
product |
multiply.reduce |
sometrue |
logical_or.reduce |
sum |
add.reduce |