[Scipy-svn] r3583 - in branches/scipy.scons: . scipy/sandbox/numexpr scipy/sandbox/numexpr/bench scipy/sandbox/numexpr/tests scipy/sandbox/timeseries scipy/sandbox/timeseries/include scipy/sandbox/timeseries/lib scipy/sandbox/timeseries/src scipy/sandbox/timeseries/tests scipy/signal

scipy-svn at scipy.org scipy-svn at scipy.org
Sat Nov 24 05:54:47 EST 2007


Author: cdavid
Date: 2007-11-24 04:53:58 -0600 (Sat, 24 Nov 2007)
New Revision: 3583

Added:
   branches/scipy.scons/scipy/sandbox/numexpr/bench/
   branches/scipy.scons/scipy/sandbox/numexpr/bench/boolean_timing.py
   branches/scipy.scons/scipy/sandbox/numexpr/bench/timing.py
Removed:
   branches/scipy.scons/scipy/sandbox/numexpr/bench/boolean_timing.py
   branches/scipy.scons/scipy/sandbox/numexpr/bench/timing.py
   branches/scipy.scons/scipy/sandbox/numexpr/timing.py
Modified:
   branches/scipy.scons/
   branches/scipy.scons/scipy/sandbox/numexpr/__init__.py
   branches/scipy.scons/scipy/sandbox/numexpr/compiler.py
   branches/scipy.scons/scipy/sandbox/numexpr/complex_functions.inc
   branches/scipy.scons/scipy/sandbox/numexpr/expressions.py
   branches/scipy.scons/scipy/sandbox/numexpr/info.py
   branches/scipy.scons/scipy/sandbox/numexpr/interp_body.c
   branches/scipy.scons/scipy/sandbox/numexpr/interpreter.c
   branches/scipy.scons/scipy/sandbox/numexpr/tests/test_numexpr.py
   branches/scipy.scons/scipy/sandbox/timeseries/dates.py
   branches/scipy.scons/scipy/sandbox/timeseries/include/c_dates.h
   branches/scipy.scons/scipy/sandbox/timeseries/lib/moving_funcs.py
   branches/scipy.scons/scipy/sandbox/timeseries/plotlib.py
   branches/scipy.scons/scipy/sandbox/timeseries/report.py
   branches/scipy.scons/scipy/sandbox/timeseries/src/c_dates.c
   branches/scipy.scons/scipy/sandbox/timeseries/src/cseries.c
   branches/scipy.scons/scipy/sandbox/timeseries/tests/test_dates.py
   branches/scipy.scons/scipy/sandbox/timeseries/tseries.py
   branches/scipy.scons/scipy/signal/signaltools.py
Log:
Merged revisions 3557-3582 via svnmerge from 
http://svn.scipy.org/svn/scipy/trunk

........
  r3566 | jarrod.millman | 2007-11-22 19:55:50 +0900 (Thu, 22 Nov 2007) | 2 lines
  
  fixed missing import as per ticket #542
........
  r3568 | cookedm | 2007-11-23 16:20:02 +0900 (Fri, 23 Nov 2007) | 7 lines
  
  [numexpr] Merge improvements from PyTables into numexpr (#529), thanks to Francesc Altet.
  This includes:
   - support for long long int datatype
   - support for string datatype
   - optimization of the unidimensional strided array case
   - optimization of the unidimensional unaligned array case
........
  r3569 | cookedm | 2007-11-23 16:21:55 +0900 (Fri, 23 Nov 2007) | 2 lines
  
  [numexpr] Move timing files to a bench/ subdirectory
........
  r3570 | mattknox_ca | 2007-11-24 06:42:20 +0900 (Sat, 24 Nov 2007) | 4 lines
  
  - renamed 'thisday' to 'now' (left 'thisday' and 'today' as deprecated aliases)
  - added tolist method to DateArray which returns a list of datetime objects
  - added additional documentation
  - renamed 'day_of_week' to 'weekday' (left 'day_of_week' as deprecated alias for now)
........
  r3571 | pierregm | 2007-11-24 08:26:02 +0900 (Sat, 24 Nov 2007) | 4 lines
  
  plotlib : ensured that TimeSeriesPlot.tsplot returns the plotted elements
          : prevented the minor ticks on the date axis to overwrite the major ticks
          : improved the finder functions
  dates   : prevented the use of the combination toordinal()/fromordinal() in date_array
........
  r3572 | mattknox_ca | 2007-11-24 09:01:30 +0900 (Sat, 24 Nov 2007) | 1 line
  
  putting some modifications back in that were overwritten in previous commit
........
  r3573 | pierregm | 2007-11-24 09:15:38 +0900 (Sat, 24 Nov 2007) | 2 lines
  
  dates   : improved .tolist()
  plotlib : fixed a wrong format
........



Property changes on: branches/scipy.scons
___________________________________________________________________
Name: svnmerge-integrated
   - /trunk:1-3556
   + /trunk:1-3582

Modified: branches/scipy.scons/scipy/sandbox/numexpr/__init__.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/__init__.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/__init__.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -1,6 +1,6 @@
-from info import __doc__
-from expressions import E
-from compiler import numexpr, disassemble, evaluate
+from numexpr.info import __doc__
+from numexpr.expressions import E
+from numexpr.compiler import numexpr, disassemble, evaluate
 
 def test(level=1, verbosity=1):
     from numpy.testing import NumpyTest

Copied: branches/scipy.scons/scipy/sandbox/numexpr/bench (from rev 3573, trunk/scipy/sandbox/numexpr/bench)

Deleted: branches/scipy.scons/scipy/sandbox/numexpr/bench/boolean_timing.py
===================================================================
--- trunk/scipy/sandbox/numexpr/bench/boolean_timing.py	2007-11-24 00:15:38 UTC (rev 3573)
+++ branches/scipy.scons/scipy/sandbox/numexpr/bench/boolean_timing.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -1,139 +0,0 @@
-import sys
-import timeit
-import numpy
-
-array_size = 1000*1000
-iterations = 10
-
-numpy_ttime = 0
-numpy_sttime = 0
-numpy_nttime = 0
-numexpr_ttime = 0
-numexpr_sttime = 0
-numexpr_nttime = 0
-
-def compare_times(expr, nexpr):
-    global numpy_ttime
-    global numpy_sttime
-    global numpy_nttime
-    global numexpr_ttime
-    global numexpr_sttime
-    global numexpr_nttime
-
-    print "******************* Expression:", expr
-
-    setup_contiguous = setupNP_contiguous
-    setup_strided = setupNP_strided
-    setup_unaligned = setupNP_unaligned
-
-    numpy_timer = timeit.Timer(expr, setup_contiguous)
-    numpy_time = round(numpy_timer.timeit(number=iterations), 4)
-    numpy_ttime += numpy_time
-    print 'numpy:', numpy_time / iterations
-
-    numpy_timer = timeit.Timer(expr, setup_strided)
-    numpy_stime = round(numpy_timer.timeit(number=iterations), 4)
-    numpy_sttime += numpy_stime
-    print 'numpy strided:', numpy_stime / iterations
-
-    numpy_timer = timeit.Timer(expr, setup_unaligned)
-    numpy_ntime = round(numpy_timer.timeit(number=iterations), 4)
-    numpy_nttime += numpy_ntime
-    print 'numpy unaligned:', numpy_ntime / iterations
-
-    evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
-    numexpr_timer = timeit.Timer(evalexpr, setup_contiguous)
-    numexpr_time = round(numexpr_timer.timeit(number=iterations), 4)
-    numexpr_ttime += numexpr_time
-    print "numexpr:", numexpr_time/iterations,
-    print "Speed-up of numexpr over numpy:", round(numpy_time/numexpr_time, 4)
-
-    evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
-    numexpr_timer = timeit.Timer(evalexpr, setup_strided)
-    numexpr_stime = round(numexpr_timer.timeit(number=iterations), 4)
-    numexpr_sttime += numexpr_stime
-    print "numexpr strided:", numexpr_stime/iterations,
-    print "Speed-up of numexpr strided over numpy:", \
-          round(numpy_stime/numexpr_stime, 4)
-
-    evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
-    numexpr_timer = timeit.Timer(evalexpr, setup_unaligned)
-    numexpr_ntime = round(numexpr_timer.timeit(number=iterations), 4)
-    numexpr_nttime += numexpr_ntime
-    print "numexpr unaligned:", numexpr_ntime/iterations,
-    print "Speed-up of numexpr unaligned over numpy:", \
-          round(numpy_ntime/numexpr_ntime, 4)
-
-
-
-setupNP = """\
-from numpy import arange, where, arctan2, sqrt
-from numpy import rec as records
-from numexpr import evaluate
-
-# Initialize a recarray of 16 MB in size
-r=records.array(None, formats='a%s,i4,f8', shape=%s)
-c1 = r.field('f0')%s
-i2 = r.field('f1')%s
-f3 = r.field('f2')%s
-c1[:] = "a"
-i2[:] = arange(%s)/1000
-f3[:] = i2/2.
-"""
-
-setupNP_contiguous = setupNP % (4, array_size,
-                                ".copy()", ".copy()", ".copy()",
-                                array_size)
-setupNP_strided = setupNP % (4, array_size, "", "", "", array_size)
-setupNP_unaligned = setupNP % (1, array_size, "", "", "", array_size)
-
-
-expressions = []
-expressions.append('i2 > 0')
-expressions.append('i2 < 0')
-expressions.append('i2 < f3')
-expressions.append('i2-10 < f3')
-expressions.append('i2*f3+f3*f3 > i2')
-expressions.append('0.1*i2 > arctan2(i2, f3)')
-expressions.append('i2%2 > 3')
-expressions.append('i2%10 < 4')
-expressions.append('i2**2 + (f3+1)**-2.5 < 3')
-expressions.append('(f3+1)**50 > i2')
-expressions.append('sqrt(i2**2 + f3**2) > 1')
-expressions.append('(i2>2) | ((f3**2>3) & ~(i2*f3<2))')
-
-def compare(expression=False):
-    if expression:
-        compare_times(expression, 1)
-        sys.exit(0)
-    nexpr = 0
-    for expr in expressions:
-        nexpr += 1
-        compare_times(expr, nexpr)
-    print
-
-if __name__ == '__main__':
-
-    print 'Python version:    %s' % sys.version
-    print "NumPy version:     %s" % numpy.__version__
-
-    if len(sys.argv) > 1:
-        expression = sys.argv[1]
-        print "expression-->", expression
-        compare(expression)
-    else:
-        compare()
-
-    print "*************** TOTALS **************************"
-    print "numpy total:", numpy_ttime/iterations
-    print "numpy strided total:", numpy_sttime/iterations
-    print "numpy unaligned total:", numpy_nttime/iterations
-    print "numexpr total:", numexpr_ttime/iterations
-    print "Speed-up of numexpr over numpy:", \
-          round(numpy_ttime/numexpr_ttime, 3)
-    print "numexpr strided total:", numexpr_sttime/iterations
-    print "Speed-up of numexpr strided over numpy:", \
-          round(numpy_sttime/numexpr_sttime, 3)
-    print "numexpr unaligned total:", numexpr_nttime/iterations
-    print "Speed-up of numexpr unaligned over numpy:", \
-          round(numpy_nttime/numexpr_nttime, 3)

Copied: branches/scipy.scons/scipy/sandbox/numexpr/bench/boolean_timing.py (from rev 3573, trunk/scipy/sandbox/numexpr/bench/boolean_timing.py)

Deleted: branches/scipy.scons/scipy/sandbox/numexpr/bench/timing.py
===================================================================
--- trunk/scipy/sandbox/numexpr/bench/timing.py	2007-11-24 00:15:38 UTC (rev 3573)
+++ branches/scipy.scons/scipy/sandbox/numexpr/bench/timing.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -1,136 +0,0 @@
-import timeit, numpy
-
-array_size = 1e6
-iterations = 10
-
-def compare_times(setup, expr):
-    print "Expression:", expr
-    namespace = {}
-    exec setup in namespace
-
-    numpy_timer = timeit.Timer(expr, setup)
-    numpy_time = numpy_timer.timeit(number=iterations)
-    print 'numpy:', numpy_time / iterations
-
-    try:
-        weave_timer = timeit.Timer('blitz("result=%s")' % expr, setup)
-        weave_time = weave_timer.timeit(number=iterations)
-        print "Weave:", weave_time/iterations
-
-        print "Speed-up of weave over numpy:", numpy_time/weave_time
-    except:
-        print "Skipping weave timing"
-
-    numexpr_timer = timeit.Timer('evaluate("%s", optimization="aggressive")' % expr, setup)
-    numexpr_time = numexpr_timer.timeit(number=iterations)
-    print "numexpr:", numexpr_time/iterations
-
-    print "Speed-up of numexpr over numpy:", numpy_time/numexpr_time
-    return numpy_time/numexpr_time
-
-setup1 = """\
-from numpy import arange
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-result = arange(%f)
-b = arange(%f)
-c = arange(%f)
-d = arange(%f)
-e = arange(%f)
-""" % ((array_size,)*5)
-expr1 = 'b*c+d*e'
-
-setup2 = """\
-from numpy import arange
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-a = arange(%f)
-b = arange(%f)
-result = arange(%f)
-""" % ((array_size,)*3)
-expr2 = '2*a+3*b'
-
-
-setup3 = """\
-from numpy import arange, sin, cos, sinh
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-a = arange(2*%f)[::2]
-b = arange(%f)
-result = arange(%f)
-""" % ((array_size,)*3)
-expr3 = '2*a + (cos(3)+5)*sinh(cos(b))'
-
-
-setup4 = """\
-from numpy import arange, sin, cos, sinh, arctan2
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-a = arange(2*%f)[::2]
-b = arange(%f)
-result = arange(%f)
-""" % ((array_size,)*3)
-expr4 = '2*a + arctan2(a, b)'
-
-
-setup5 = """\
-from numpy import arange, sin, cos, sinh, arctan2, sqrt, where
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-a = arange(2*%f, dtype=float)[::2]
-b = arange(%f, dtype=float)
-result = arange(%f, dtype=float)
-""" % ((array_size,)*3)
-expr5 = 'where(0.1*a > arctan2(a, b), 2*a, arctan2(a,b))'
-
-expr6 = 'where(a != 0.0, 2, b)'
-
-expr7 = 'where(a-10 != 0.0, a, 2)'
-
-expr8 = 'where(a%2 != 0.0, b+5, 2)'
-
-expr9 = 'where(a%2 != 0.0, 2, b+5)'
-
-expr10 = 'a**2 + (b+1)**-2.5'
-
-expr11 = '(a+1)**50'
-
-expr12 = 'sqrt(a**2 + b**2)'
-
-def compare(check_only=False):
-    total = 0
-    total += compare_times(setup1, expr1)
-    print
-    total += compare_times(setup2, expr2)
-    print
-    total += compare_times(setup3, expr3)
-    print
-    total += compare_times(setup4, expr4)
-    print
-    total += compare_times(setup5, expr6)
-    print
-    total += compare_times(setup5, expr7)
-    print
-    total += compare_times(setup5, expr8)
-    print
-    total += compare_times(setup5, expr9)
-    print
-    total += compare_times(setup5, expr10)
-    print
-    total += compare_times(setup5, expr11)
-    print
-    total += compare_times(setup5, expr12)
-    print
-    print "Average =", total / 11.0
-    return total
-
-if __name__ == '__main__':
-    averages = []
-    for i in range(iterations):
-        averages.append(compare())
-    print "Averages:", ', '.join("%.2f" % x for x in averages)

Copied: branches/scipy.scons/scipy/sandbox/numexpr/bench/timing.py (from rev 3573, trunk/scipy/sandbox/numexpr/bench/timing.py)

Modified: branches/scipy.scons/scipy/sandbox/numexpr/compiler.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/compiler.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/compiler.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -1,12 +1,12 @@
 import sys
 import numpy
 
-import interpreter, expressions
+from numexpr import interpreter, expressions
 
-typecode_to_kind = {'b': 'bool', 'i': 'int', 'f': 'float',
-                    'c': 'complex', 'n' : 'none'}
-kind_to_typecode = {'bool': 'b', 'int': 'i', 'float': 'f',
-                    'complex': 'c', 'none' : 'n'}
+typecode_to_kind = {'b': 'bool', 'i': 'int', 'l': 'long', 'f': 'float',
+                    'c': 'complex', 's': 'str', 'n' : 'none'}
+kind_to_typecode = {'bool': 'b', 'int': 'i', 'long': 'l', 'float': 'f',
+                    'complex': 'c', 'str': 's', 'none' : 'n'}
 type_to_kind = expressions.type_to_kind
 kind_to_type = expressions.kind_to_type
 
@@ -91,7 +91,7 @@
     """Generate all possible signatures derived by upcasting the given
     signature.
     """
-    codes = 'bifc'
+    codes = 'bilfc'
     if not s:
         yield ''
     elif s[0] in codes:
@@ -99,6 +99,9 @@
         for x in codes[start:]:
             for y in sigPerms(s[1:]):
                 yield x + y
+    elif s[0] == 's':  # numbers shall not be cast to strings
+        for y in sigPerms(s[1:]):
+            yield 's' + y
     else:
         yield s
 
@@ -198,6 +201,10 @@
         for name in c.co_names:
             if name == "None":
                 names[name] = None
+            elif name == "True":
+                names[name] = True
+            elif name == "False":
+                names[name] = False
             else:
                 t = types.get(name, float)
                 names[name] = expressions.VariableNode(name, type_to_kind[t])
@@ -206,6 +213,8 @@
         ex = eval(c, names)
         if expressions.isConstant(ex):
             ex = expressions.ConstantNode(ex, expressions.getKind(ex))
+        elif not isinstance(ex, expressions.ExpressionNode):
+            raise TypeError("unsupported expression type: %s" % type(ex))
     finally:
         expressions._context.ctx = old_ctx
     return ex
@@ -308,8 +317,8 @@
         for c in n.children:
             if c.reg.temporary:
                 users_of[c.reg].add(n)
-    unused = {'bool' : set(), 'int' : set(),
-              'float' : set(), 'complex' : set()}
+    unused = {'bool' : set(), 'int' : set(), 'long': set(),
+              'float' : set(), 'complex' : set(), 'str': set()}
     for n in nodes:
         for reg, users in users_of.iteritems():
             if n in users:
@@ -435,7 +444,7 @@
 
     ast = expressionToAST(ex)
 
-    # Add a copy for strided or unaligned arrays
+    # Add a copy for strided or unaligned unidimensional arrays
     for a in ast.postorderWalk():
         if a.astType == "variable" and a.value in copy_args:
             newVar = ASTNode(*a.key())
@@ -536,15 +545,19 @@
 
 
 def getType(a):
-    t = a.dtype.type
-    if issubclass(t, numpy.bool_):
+    kind = a.dtype.kind
+    if kind == 'b':
         return bool
-    if issubclass(t, numpy.integer):
+    if kind in 'iu':
+        if a.dtype.itemsize > 4:
+            return long  # ``long`` is for integers of more than 32 bits
         return int
-    if issubclass(t, numpy.floating):
+    if kind == 'f':
         return float
-    if issubclass(t, numpy.complexfloating):
+    if kind == 'c':
         return complex
+    if kind == 'S':
+        return str
     raise ValueError("unkown type %s" % a.dtype.name)
 
 
@@ -589,12 +602,29 @@
             a = local_dict[name]
         except KeyError:
             a = global_dict[name]
-        # byteswapped arrays are taken care of in the extension.
-        arguments.append(numpy.asarray(a)) # don't make a data copy, if possible
-        if (hasattr(a, "flags") and            # numpy object
-            (not a.flags.contiguous or
-             not a.flags.aligned)):
-            copy_args.append(name)    # do a copy to temporary
+        b = numpy.asarray(a)
+        # Byteswapped arrays are dealt with in the extension
+        # All the opcodes can deal with strided arrays directly as
+        # long as they are undimensional (strides in other
+        # dimensions are dealt within the extension), so we don't
+        # need a copy for the strided case.
+        if not b.flags.aligned:
+            # For the unaligned case, we have two cases:
+            if b.ndim == 1:
+                # For unidimensional arrays we can use the copy opcode
+                # because it can deal with unaligned arrays as long
+                # as they are unidimensionals with a possible stride
+                # (very common case for recarrays).  This can be up to
+                # 2x faster than doing a copy using NumPy.
+                copy_args.append(name)
+            else:
+                # For multimensional unaligned arrays do a plain copy.
+                # We could refine more this and do a plain copy only
+                # in the case that strides doesn't exist in dimensions
+                # other than the last one (whose case is supported by
+                # the copy opcode).
+                b = b.copy()
+        arguments.append(b)
 
     # Create a signature
     signature = [(name, getType(arg)) for (name, arg) in zip(names, arguments)]

Modified: branches/scipy.scons/scipy/sandbox/numexpr/complex_functions.inc
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/complex_functions.inc	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/complex_functions.inc	2007-11-24 10:53:58 UTC (rev 3583)
@@ -365,3 +365,34 @@
 	r->imag = (is*rc-rs*ic)/d;
 	return;
 }
+
+
+/* The next nowarn1() and nowarn2() are defined in order to avoid
+   compiler warnings about unused functions.  Just add to nowarn1() a
+   call to each function the compiler complains about to make it look
+   like it gets used somewhere.
+
+   Of course, you shouldn't directly invoke neither of these two
+   functions, since they cause a stack overflow. */
+
+void nowarn2(cdouble *x, cdouble *r, cdouble *b);
+
+void
+nowarn1(cdouble *x, cdouble *r, cdouble *b)
+{
+	nc_floor_quot(x, b, r);
+	nc_log1p(x, r);
+	nc_expm1(x, r);
+	nc_log10(x, r);
+	nc_asinh(x, r);
+	nc_acosh(x, r);
+	nc_atanh(x, r);
+	/* Append more calls here. */
+	nowarn2(x, r, b);
+}
+
+void
+nowarn2(cdouble *x, cdouble *r, cdouble *b)
+{
+	nowarn1(x, r, b);
+}

Modified: branches/scipy.scons/scipy/sandbox/numexpr/expressions.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/expressions.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/expressions.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -6,7 +6,7 @@
 
 import numpy
 
-import interpreter
+from numexpr import interpreter
 
 class Expression(object):
     def __init__(self):
@@ -55,25 +55,53 @@
 
 def isConstant(ex):
     "Returns True if ex is a constant scalar of an allowed type."
-    return isinstance(ex, (bool, int, float, complex))
+    return isinstance(ex, (bool, int, long, float, complex, str))
 
-type_to_kind = {bool: 'bool', int: 'int', float: 'float', complex: 'complex'}
-kind_to_type = {'bool': bool, 'int': int, 'float': float, 'complex': complex}
-kind_rank = ['bool', 'int', 'float', 'complex', 'none']
+type_to_kind = {bool: 'bool', int: 'int', long: 'long', float: 'float', complex: 'complex', str: 'str'}
+kind_to_type = {'bool': bool, 'int': int, 'long': long, 'float': float, 'complex': complex, 'str': str}
+kind_rank = ['bool', 'int', 'long', 'float', 'complex', 'none']
 
 def commonKind(nodes):
+    node_kinds = [node.astKind for node in nodes]
+    str_count = node_kinds.count('str')
+    if 0 < str_count < len(node_kinds):  # some args are strings, but not all
+        raise TypeError("strings can only be operated with strings")
+    if str_count > 0:  # if there are some, all of them must be
+        return 'str'
     n = -1
     for x in nodes:
         n = max(n, kind_rank.index(x.astKind))
     return kind_rank[n]
 
+max_int32 = 2147483647
+min_int32 = -max_int32 - 1
 def bestConstantType(x):
-    for converter in bool, int, float, complex:
+    if isinstance(x, str):  # ``numpy.string_`` is a subclass of ``str``
+        return str
+    # ``long`` objects are kept as is to allow the user to force
+    # promotion of results by using long constants, e.g. by operating
+    # a 32-bit array with a long (64-bit) constant.
+    if isinstance(x, (long, numpy.int64)):
+        return long
+    # Numeric conversion to boolean values is not tried because
+    # ``bool(1) == True`` (same for 0 and False), so 0 and 1 would be
+    # interpreted as booleans when ``False`` and ``True`` are already
+    # supported.
+    if isinstance(x, (bool, numpy.bool_)):
+        return bool
+    # ``long`` is not explicitly needed since ``int`` automatically
+    # returns longs when needed (since Python 2.3).
+    for converter in int, float, complex:
         try:
             y = converter(x)
         except StandardError, err:
             continue
         if x == y:
+            # Constants needing more than 32 bits are always
+            # considered ``long``, *regardless of the platform*, so we
+            # can clearly tell 32- and 64-bit constants apart.
+            if converter is int and not (min_int32 <= x <= max_int32):
+                return long
             return converter
 
 def getKind(x):
@@ -94,7 +122,7 @@
             return OpNode(opname, (self, other), kind=kind)
     return operation
 
-def func(func, minkind=None):
+def func(func, minkind=None, maxkind=None):
     @ophelper
     def function(*args):
         if allConstantNodes(args):
@@ -102,6 +130,8 @@
         kind = commonKind(args)
         if minkind and kind_rank.index(minkind) > kind_rank.index(kind):
             kind = minkind
+        if maxkind and kind_rank.index(maxkind) < kind_rank.index(kind):
+            kind = maxkind
         return FuncNode(func.__name__, args, kind)
     return function
 
@@ -129,23 +159,17 @@
     axis = encode_axis(axis)
     if isinstance(a, ConstantNode):
         return a
-    if isinstance(a, (bool, int, float, complex)):
+    if isinstance(a, (bool, int, long, float, complex)):
         a = ConstantNode(a)
-    kind = a.astKind
-    if kind == 'bool':
-        kind = 'int'
-    return FuncNode('sum', [a, axis], kind=kind)
+    return FuncNode('sum', [a, axis], kind=a.astKind)
 
 def prod_func(a, axis=-1):
     axis = encode_axis(axis)
-    if isinstance(a, (bool, int, float, complex)):
+    if isinstance(a, (bool, int, long, float, complex)):
         a = ConstantNode(a)
     if isinstance(a, ConstantNode):
         return a
-    kind = a.astKind
-    if kind == 'bool':
-        kind = 'int'
-    return FuncNode('prod', [a, axis], kind=kind)
+    return FuncNode('prod', [a, axis], kind=a.astKind)
 
 @ophelper
 def div_op(a, b):
@@ -182,7 +206,7 @@
                     p = OpNode('mul', [p,p])
                 if ishalfpower:
                     kind = commonKind([a])
-                    if kind == 'int': kind = 'float'
+                    if kind in ('int', 'long'): kind = 'float'
                     r = multiply(r, OpNode('sqrt', [a], kind))
                 if r is None:
                     r = OpNode('ones_like', [a])
@@ -196,7 +220,7 @@
                 return FuncNode('ones_like', [a])
             if x == 0.5:
                 kind = a.astKind
-                if kind == 'int': kind = 'float'
+                if kind in ('int', 'long'): kind = 'float'
                 return FuncNode('sqrt', [a], kind=kind)
             if x == 1:
                 return a
@@ -224,6 +248,8 @@
 
     'where' : where_func,
 
+    'real': func(numpy.real, 'float', 'float'),
+    'imag': func(numpy.imag, 'float', 'float'),
     'complex' : func(complex, 'complex'),
 
     'sum' : sum_func,
@@ -306,7 +332,7 @@
 class VariableNode(LeafNode):
     astType = 'variable'
     def __init__(self, value=None, kind=None, children=None):
-        ExpressionNode.__init__(self, value=value, kind=kind)
+        LeafNode.__init__(self, value=value, kind=kind)
 
 class RawNode(object):
     """Used to pass raw integers to interpreter.

Modified: branches/scipy.scons/scipy/sandbox/numexpr/info.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/info.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/info.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -2,25 +2,55 @@
 
 Usage:
 
-Build an expression up by using E.<variable> for the variables:
+The easiest way is to use the ``evaluate`` function:
 
->>> ex = 2.0 * E.a + 3 * E.b * E.c
+>>> a = numpy.array([1., 2, 3])
+>>> b = numpy.array([4, 5, 6])
+>>> c = numpy.array([7., 8, 9])
+>>> numexpr.evaluate("2.0 * a + 3 * b * c")
+array([  86.,  124.,  168.])
 
-then compile it to a function:
+This works for every datatype defined in NumPy and the next operators
+are supported:
 
->>> func = numexpr(ex, input_names=('a', 'b', 'c'))
+    Logical operators: &, |, ~
+    Comparison operators: <, <=, ==, !=, >=, >
+    Unary arithmetic operators: -
+    Binary arithmetic operators: +, -, *, /, **, %
 
-(if input_names is not given to compile, the variables are sort lexically.)
+Note: Types do not support all operators. Boolean values only support
+    logical and strict (in)equality comparison operators, while
+    strings only support comparisons, numbers do not work with logical
+    operators, and complex comparisons can only check for strict
+    (in)equality. Unsupported operations (including invalid castings)
+    raise NotImplementedError exceptions.
 
-Then, you can use that function for elementwise operations:
+The next functions are also supported:
 
->>> func(array([1., 2, 3]), array([4., 5, 6]), array([7., 8, 9]))
-array([  86.,  124.,  168.])
+    where(bool, number1, number2): number - number1 if the bool
+    condition is true, number2 otherwise.
 
-Currently, this is only implemented for arrays of float64, and only
-for the simple operations +, -, *, and /.
+    {sin,cos,tan}(float|complex): float|complex - trigonometric sinus,
+    cosinus or tangent.
 
-Copyright 2006 David M. Cooke <cookedm at physics.mcmaster.ca>
+    {arcsin,arccos,arctan}(float|complex): float|complex -
+    trigonometric inverse sinus, cosinus or tangent.
+
+    arctan2(float1, float2): float - trigonometric inverse tangent of
+    float1/float2.
+
+    {sinh,cosh,tanh}(float|complex): float|complex - hyperbolic sinus,
+    cosinus or tangent.
+
+    sqrt(float|complex): float|complex - square root.
+
+    {real,imag}(complex): float - real or imaginary part of complex.
+
+    complex(float, float): complex - complex from real and imaginary
+    parts.
+
+
+Copyright 2006,2007 David M. Cooke <cookedm at physics.mcmaster.ca>
 Licenced under a BSD-style license. See LICENSE.txt in the scipy source
 directory.
 """

Modified: branches/scipy.scons/scipy/sandbox/numexpr/interp_body.c
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/interp_body.c	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/interp_body.c	2007-11-24 10:53:58 UTC (rev 3583)
@@ -8,9 +8,13 @@
     {                                           \
         char *dest = params.mem[store_in];      \
         char *x1 = params.mem[arg1];            \
+        intp ss1 = params.memsizes[arg1];       \
         intp sb1 = params.memsteps[arg1];       \
-        intp si1 = sb1 / sizeof(long);          \
-        intp sf1 = sb1 / sizeof(double);        \
+        /* nowarns is defined and used so as to \
+        avoid compiler warnings about unused    \
+        variables */                            \
+        intp nowarns = ss1+sb1+*x1;             \
+        nowarns += 1;                           \
         VEC_LOOP(expr);                         \
     } break
 #define VEC_ARG2(expr)                          \
@@ -20,14 +24,16 @@
     {                                           \
         char *dest = params.mem[store_in];      \
         char *x1 = params.mem[arg1];            \
+        intp ss1 = params.memsizes[arg1];       \
         intp sb1 = params.memsteps[arg1];       \
-        intp si1 = sb1 / sizeof(long);          \
-        intp sf1 = sb1 / sizeof(double);        \
+        /* nowarns is defined and used so as to \
+        avoid compiler warnings about unused    \
+        variables */                            \
+        intp nowarns = ss1+sb1+*x1;             \
         char *x2 = params.mem[arg2];            \
+        intp ss2 = params.memsizes[arg2];       \
         intp sb2 = params.memsteps[arg2];       \
-        intp si2 = sb2 / sizeof(long);          \
-        intp sf2 = sb2 / sizeof(double);        \
-        intp s2 = params.memsteps[arg2];        \
+        nowarns += ss2+sb2+*x2;                 \
         VEC_LOOP(expr);                         \
     } break
 
@@ -39,19 +45,20 @@
     {                                           \
         char *dest = params.mem[store_in];      \
         char *x1 = params.mem[arg1];            \
+        intp ss1 = params.memsizes[arg1];       \
         intp sb1 = params.memsteps[arg1];       \
-        intp si1 = sb1 / sizeof(long);          \
-        intp sf1 = sb1 / sizeof(double);        \
+        /* nowarns is defined and used so as to \
+        avoid compiler warnings about unused    \
+        variables */                            \
+        intp nowarns = ss1+sb1+*x1;             \
         char *x2 = params.mem[arg2];            \
-        intp s2 = params.memsteps[arg2];        \
+        intp ss2 = params.memsizes[arg2];       \
         intp sb2 = params.memsteps[arg2];       \
-        intp si2 = sb2 / sizeof(long);          \
-        intp sf2 = sb2 / sizeof(double);        \
         char *x3 = params.mem[arg3];            \
-        intp s3 = params.memsteps[arg3];        \
+        intp ss3 = params.memsizes[arg3];       \
         intp sb3 = params.memsteps[arg3];       \
-        intp si3 = sb3 / sizeof(long);          \
-        intp sf3 = sb3 / sizeof(double);        \
+        nowarns += ss2+sb2+*x2;                 \
+        nowarns += ss3+sb3+*x3;                 \
         VEC_LOOP(expr);                         \
     } break
 
@@ -82,6 +89,11 @@
             params.mem[1+r] = params.inputs[r] + index * params.memsteps[1+r];
         }
     }
+
+    /* WARNING: From now on, only do references to params.mem[arg[123]]
+       & params.memsteps[arg[123]] inside the VEC_ARG[123] macros,
+       or you will risk accessing invalid addresses.  */
+
     for (pc = 0; pc < params.prog_len; pc += 4) {
         unsigned char op = params.program[pc];
         unsigned int store_in = params.program[pc+1];
@@ -89,37 +101,41 @@
         unsigned int arg2 = params.program[pc+3];
         #define      arg3   params.program[pc+5]
         #define store_index params.index_data[store_in]
-        
-       /* WARNING: From now on, only do references to params.mem[arg[123]]
-         & params.memsteps[arg[123]] inside the VEC_ARG[123] macros,
-          or you will risk accessing invalid addresses.  */
-        
         #define reduce_ptr  (dest + flat_index(&store_index, j))
-        #define i_reduce    *(long *)reduce_ptr
+        #define i_reduce    *(int *)reduce_ptr
+        #define l_reduce    *(long long *)reduce_ptr
         #define f_reduce    *(double *)reduce_ptr
         #define cr_reduce   *(double *)ptr
         #define ci_reduce   *((double *)ptr+1)
         #define b_dest ((char *)dest)[j]
-        #define i_dest ((long *)dest)[j]
+        #define i_dest ((int *)dest)[j]
+        #define l_dest ((long long *)dest)[j]
         #define f_dest ((double *)dest)[j]
         #define cr_dest ((double *)dest)[2*j]
         #define ci_dest ((double *)dest)[2*j+1]
-        #define b1    ((char   *)x1)[j*sb1]
-        #define i1    ((long   *)x1)[j*si1]
-        #define f1    ((double *)x1)[j*sf1]
-        #define c1r   ((double *)x1)[j*sf1]
-        #define c1i   ((double *)x1)[j*sf1+1]
-        #define b2    ((char   *)x2)[j*sb2]
-        #define i2    ((long   *)x2)[j*si2]
-        #define f2    ((double *)x2)[j*sf2]
-        #define c2r   ((double *)x2)[j*sf2]
-        #define c2i   ((double *)x2)[j*sf2+1]
-        #define b3    ((char   *)x3)[j*sb3]
-        #define i3    ((long   *)x3)[j*si3]
-        #define f3    ((double *)x3)[j*sf3]
-        #define c3r   ((double *)x3)[j*sf3]
-        #define c3i   ((double *)x3)[j*sf3+1]
-
+        #define s_dest ((char *)dest + j*params.memsteps[store_in])
+        #define b1    ((char   *)(x1+j*sb1))[0]
+        #define i1    ((int    *)(x1+j*sb1))[0]
+        #define l1    ((long long *)(x1+j*sb1))[0]
+        #define f1    ((double *)(x1+j*sb1))[0]
+        #define c1r   ((double *)(x1+j*sb1))[0]
+        #define c1i   ((double *)(x1+j*sb1))[1]
+        #define s1    ((char   *)x1+j*sb1)
+        #define b2    ((char   *)(x2+j*sb2))[0]
+        #define i2    ((int    *)(x2+j*sb2))[0]
+        #define l2    ((long long *)(x2+j*sb2))[0]
+        #define f2    ((double *)(x2+j*sb2))[0]
+        #define c2r   ((double *)(x2+j*sb2))[0]
+        #define c2i   ((double *)(x2+j*sb2))[1]
+        #define s2    ((char   *)x2+j*sb2)
+        #define b3    ((char   *)(x3+j*sb3))[0]
+        #define i3    ((int    *)(x3+j*sb3))[0]
+        #define l3    ((long long *)(x3+j*sb3))[0]
+        #define f3    ((double *)(x3+j*sb3))[0]
+        #define c3r   ((double *)(x3+j*sb3))[0]
+        #define c3i   ((double *)(x3+j*sb3))[1]
+        #define s3    ((char   *)x3+j*sb3)
+	/* Some temporaries */
         double fa, fb;
         cdouble ca, cb;
         char *ptr;
@@ -129,27 +145,42 @@
         case OP_NOOP: break;
 
         case OP_COPY_BB: VEC_ARG1(b_dest = b1);
-        case OP_COPY_II: VEC_ARG1(i_dest = i1);
-        case OP_COPY_FF: VEC_ARG1(f_dest = f1);
-        case OP_COPY_CC: VEC_ARG1(cr_dest = c1r;
-                                  ci_dest = c1i);
+        case OP_COPY_SS: VEC_ARG1(memcpy(s_dest, s1, ss1));
+        /* The next versions of copy opcodes can cope with unaligned
+           data even on platforms that crash while accessing it
+           (like the Sparc architecture under Solaris). */
+        case OP_COPY_II: VEC_ARG1(memcpy(&i_dest, s1, sizeof(int)));
+        case OP_COPY_LL: VEC_ARG1(memcpy(&f_dest, s1, sizeof(long long)));
+        case OP_COPY_FF: VEC_ARG1(memcpy(&f_dest, s1, sizeof(double)));
+        case OP_COPY_CC: VEC_ARG1(memcpy(&cr_dest, s1, sizeof(double)*2));
 
         case OP_INVERT_BB: VEC_ARG1(b_dest = !b1);
+        case OP_AND_BBB: VEC_ARG2(b_dest = (b1 && b2));
+        case OP_OR_BBB: VEC_ARG2(b_dest = (b1 || b2));
 
-        case OP_AND_BBB: VEC_ARG2(b_dest = b1 && b2);
-        case OP_OR_BBB: VEC_ARG2(b_dest = b1 || b2);
+        case OP_EQ_BBB: VEC_ARG2(b_dest = (b1 == b2));
+        case OP_NE_BBB: VEC_ARG2(b_dest = (b1 != b2));
 
-        case OP_GT_BII: VEC_ARG2(b_dest = (i1 > i2) ? 1 : 0);
-        case OP_GE_BII: VEC_ARG2(b_dest = (i1 >= i2) ? 1 : 0);
-        case OP_EQ_BII: VEC_ARG2(b_dest = (i1 == i2) ? 1 : 0);
-        case OP_NE_BII: VEC_ARG2(b_dest = (i1 != i2) ? 1 : 0);
+        case OP_GT_BII: VEC_ARG2(b_dest = (i1 > i2));
+        case OP_GE_BII: VEC_ARG2(b_dest = (i1 >= i2));
+        case OP_EQ_BII: VEC_ARG2(b_dest = (i1 == i2));
+        case OP_NE_BII: VEC_ARG2(b_dest = (i1 != i2));
 
-        case OP_GT_BFF: VEC_ARG2(b_dest = (f1 > f2) ? 1 : 0);
-        case OP_GE_BFF: VEC_ARG2(b_dest = (f1 >= f2) ? 1 : 0);
-        case OP_EQ_BFF: VEC_ARG2(b_dest = (f1 == f2) ? 1 : 0);
-        case OP_NE_BFF: VEC_ARG2(b_dest = (f1 != f2) ? 1 : 0);
+        case OP_GT_BLL: VEC_ARG2(b_dest = (l1 > l2));
+        case OP_GE_BLL: VEC_ARG2(b_dest = (l1 >= l2));
+        case OP_EQ_BLL: VEC_ARG2(b_dest = (l1 == l2));
+        case OP_NE_BLL: VEC_ARG2(b_dest = (l1 != l2));
 
-        case OP_CAST_IB: VEC_ARG1(i_dest = (long)b1);
+        case OP_GT_BFF: VEC_ARG2(b_dest = (f1 > f2));
+        case OP_GE_BFF: VEC_ARG2(b_dest = (f1 >= f2));
+        case OP_EQ_BFF: VEC_ARG2(b_dest = (f1 == f2));
+        case OP_NE_BFF: VEC_ARG2(b_dest = (f1 != f2));
+
+        case OP_GT_BSS: VEC_ARG2(b_dest = (stringcmp(s1, s2, ss1, ss2) > 0));
+        case OP_GE_BSS: VEC_ARG2(b_dest = (stringcmp(s1, s2, ss1, ss2) >= 0));
+        case OP_EQ_BSS: VEC_ARG2(b_dest = (stringcmp(s1, s2, ss1, ss2) == 0));
+        case OP_NE_BSS: VEC_ARG2(b_dest = (stringcmp(s1, s2, ss1, ss2) != 0));
+
         case OP_ONES_LIKE_II: VEC_ARG1(i_dest = 1);
         case OP_NEG_II: VEC_ARG1(i_dest = -i1);
 
@@ -157,13 +188,26 @@
         case OP_SUB_III: VEC_ARG2(i_dest = i1 - i2);
         case OP_MUL_III: VEC_ARG2(i_dest = i1 * i2);
         case OP_DIV_III: VEC_ARG2(i_dest = i1 / i2);
-        case OP_POW_III: VEC_ARG2(i_dest = (i2 < 0) ? (1 / i1) : (long)pow(i1, i2));
+        case OP_POW_III: VEC_ARG2(i_dest = (i2 < 0) ? (1 / i1) : (int)pow(i1, i2));
         case OP_MOD_III: VEC_ARG2(i_dest = i1 % i2);
 
-        case OP_WHERE_IFII: VEC_ARG3(i_dest = f1 ? i2 : i3);
+        case OP_WHERE_IBII: VEC_ARG3(i_dest = b1 ? i2 : i3);
 
-        case OP_CAST_FB: VEC_ARG1(f_dest = (long)b1);
+        case OP_CAST_LI: VEC_ARG1(l_dest = (long long)(i1));
+        case OP_ONES_LIKE_LL: VEC_ARG1(l_dest = 1);
+        case OP_NEG_LL: VEC_ARG1(l_dest = -i1);
+
+        case OP_ADD_LLL: VEC_ARG2(l_dest = l1 + l2);
+        case OP_SUB_LLL: VEC_ARG2(l_dest = l1 - l2);
+        case OP_MUL_LLL: VEC_ARG2(l_dest = l1 * l2);
+        case OP_DIV_LLL: VEC_ARG2(l_dest = l1 / l2);
+        case OP_POW_LLL: VEC_ARG2(l_dest = (l2 < 0) ? (1 / l1) : (long long)pow(l1, l2));
+        case OP_MOD_LLL: VEC_ARG2(l_dest = l1 % l2);
+
+        case OP_WHERE_LBLL: VEC_ARG3(l_dest = b1 ? l2 : l3);
+
         case OP_CAST_FI: VEC_ARG1(f_dest = (double)(i1));
+        case OP_CAST_FL: VEC_ARG1(f_dest = (double)(l1));
         case OP_ONES_LIKE_FF: VEC_ARG1(f_dest = 1.0);
         case OP_NEG_FF: VEC_ARG1(f_dest = -f1);
 
@@ -180,15 +224,15 @@
         case OP_SQRT_FF: VEC_ARG1(f_dest = sqrt(f1));
         case OP_ARCTAN2_FFF: VEC_ARG2(f_dest = atan2(f1, f2));
 
-        case OP_WHERE_FFFF: VEC_ARG3(f_dest = f1 ? f2 : f3);
+        case OP_WHERE_FBFF: VEC_ARG3(f_dest = b1 ? f2 : f3);
 
         case OP_FUNC_FF: VEC_ARG1(f_dest = functions_f[arg2](f1));
         case OP_FUNC_FFF: VEC_ARG2(f_dest = functions_ff[arg3](f1, f2));
 
-        case OP_CAST_CB: VEC_ARG1(cr_dest = (double)b1;
-                                  ci_dest = 0);
         case OP_CAST_CI: VEC_ARG1(cr_dest = (double)(i1);
                                   ci_dest = 0);
+        case OP_CAST_CL: VEC_ARG1(cr_dest = (double)(l1);
+                                  ci_dest = 0);
         case OP_CAST_CF: VEC_ARG1(cr_dest = f1;
                                   ci_dest = 0);
         case OP_ONES_LIKE_CC: VEC_ARG1(cr_dest = 1;
@@ -208,11 +252,11 @@
                                   ci_dest = (c1i*c2r - c1r*c2i) / fa;
                                   cr_dest = fb);
 
-        case OP_EQ_BCC: VEC_ARG2(b_dest = (c1r == c2r && c1i == c2i) ? 1 : 0);
-        case OP_NE_BCC: VEC_ARG2(b_dest = (c1r != c2r || c1i != c2i) ? 1 : 0);
+        case OP_EQ_BCC: VEC_ARG2(b_dest = (c1r == c2r && c1i == c2i));
+        case OP_NE_BCC: VEC_ARG2(b_dest = (c1r != c2r || c1i != c2i));
 
-        case OP_WHERE_CFCC: VEC_ARG3(cr_dest = f1 ? c2r : c3r;
-                                     ci_dest = f1 ? c2i : c3i);
+        case OP_WHERE_CBCC: VEC_ARG3(cr_dest = b1 ? c2r : c3r;
+                                     ci_dest = b1 ? c2i : c3i);
         case OP_FUNC_CC: VEC_ARG1(ca.real = c1r;
                                   ca.imag = c1i;
                                   functions_cc[arg2](&ca, &ca);
@@ -232,12 +276,14 @@
                                       ci_dest = f2);
 
         case OP_SUM_IIN: VEC_ARG1(i_reduce += i1);
+        case OP_SUM_LLN: VEC_ARG1(l_reduce += l1);
         case OP_SUM_FFN: VEC_ARG1(f_reduce += f1);
         case OP_SUM_CCN: VEC_ARG1(ptr = reduce_ptr;
                                   cr_reduce += c1r;
                                   ci_reduce += c1i);
 
         case OP_PROD_IIN: VEC_ARG1(i_reduce *= i1);
+        case OP_PROD_LLN: VEC_ARG1(l_reduce *= l1);
         case OP_PROD_FFN: VEC_ARG1(f_reduce *= f1);
         case OP_PROD_CCN: VEC_ARG1(ptr = reduce_ptr;
                                    fa = cr_reduce*c1r - ci_reduce*c1i;
@@ -258,22 +304,30 @@
 
 #undef b_dest
 #undef i_dest
+#undef l_dest
 #undef f_dest
 #undef cr_dest
 #undef ci_dest
+#undef s_dest
 #undef b1
 #undef i1
+#undef l1
 #undef f1
 #undef c1r
 #undef c1i
+#undef s1
 #undef b2
 #undef i2
+#undef l2
 #undef f2
 #undef c2r
 #undef c2i
+#undef s2
 #undef b3
 #undef i3
+#undef l3
 #undef f3
 #undef c3r
 #undef c3i
+#undef s3
 }

Modified: branches/scipy.scons/scipy/sandbox/numexpr/interpreter.c
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/interpreter.c	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/interpreter.c	2007-11-24 10:53:58 UTC (rev 3583)
@@ -2,6 +2,8 @@
 #include "structmember.h"
 #include "numpy/noprefix.h"
 #include "math.h"
+#include "string.h"
+#include "assert.h"
 
 #include "complex_functions.inc"
 
@@ -25,17 +27,29 @@
     OP_AND_BBB,
     OP_OR_BBB,
 
+    OP_EQ_BBB,
+    OP_NE_BBB,
+
     OP_GT_BII,
     OP_GE_BII,
     OP_EQ_BII,
     OP_NE_BII,
 
+    OP_GT_BLL,
+    OP_GE_BLL,
+    OP_EQ_BLL,
+    OP_NE_BLL,
+
     OP_GT_BFF,
     OP_GE_BFF,
     OP_EQ_BFF,
     OP_NE_BFF,
 
-    OP_CAST_IB,
+    OP_GT_BSS,
+    OP_GE_BSS,
+    OP_EQ_BSS,
+    OP_NE_BSS,
+
     OP_COPY_II,
     OP_ONES_LIKE_II,
     OP_NEG_II,
@@ -45,10 +59,22 @@
     OP_DIV_III,
     OP_POW_III,
     OP_MOD_III,
-    OP_WHERE_IFII,
+    OP_WHERE_IBII,
 
-    OP_CAST_FB,
+    OP_CAST_LI,
+    OP_COPY_LL,
+    OP_ONES_LIKE_LL,
+    OP_NEG_LL,
+    OP_ADD_LLL,
+    OP_SUB_LLL,
+    OP_MUL_LLL,
+    OP_DIV_LLL,
+    OP_POW_LLL,
+    OP_MOD_LLL,
+    OP_WHERE_LBLL,
+
     OP_CAST_FI,
+    OP_CAST_FL,
     OP_COPY_FF,
     OP_ONES_LIKE_FF,
     OP_NEG_FF,
@@ -63,15 +89,15 @@
     OP_TAN_FF,
     OP_SQRT_FF,
     OP_ARCTAN2_FFF,
-    OP_WHERE_FFFF,
+    OP_WHERE_FBFF,
     OP_FUNC_FF,
     OP_FUNC_FFF,
 
     OP_EQ_BCC,
     OP_NE_BCC,
 
-    OP_CAST_CB,
     OP_CAST_CI,
+    OP_CAST_CL,
     OP_CAST_CF,
     OP_ONES_LIKE_CC,
     OP_COPY_CC,
@@ -80,7 +106,7 @@
     OP_SUB_CCC,
     OP_MUL_CCC,
     OP_DIV_CCC,
-    OP_WHERE_CFCC,
+    OP_WHERE_CBCC,
     OP_FUNC_CC,
     OP_FUNC_CCC,
 
@@ -88,15 +114,19 @@
     OP_IMAG_FC,
     OP_COMPLEX_CFF,
 
+    OP_COPY_SS,
+
     OP_REDUCTION,
 
     OP_SUM,
     OP_SUM_IIN,
+    OP_SUM_LLN,
     OP_SUM_FFN,
     OP_SUM_CCN,
 
     OP_PROD,
     OP_PROD_IIN,
+    OP_PROD_LLN,
     OP_PROD_FFN,
     OP_PROD_CCN
 
@@ -116,6 +146,8 @@
             break;
         case OP_AND_BBB:
         case OP_OR_BBB:
+        case OP_EQ_BBB:
+        case OP_NE_BBB:
             if (n == 0 || n == 1 || n == 2) return 'b';
             break;
         case OP_GT_BII:
@@ -125,6 +157,13 @@
             if (n == 0) return 'b';
             if (n == 1 || n == 2) return 'i';
             break;
+        case OP_GT_BLL:
+        case OP_GE_BLL:
+        case OP_EQ_BLL:
+        case OP_NE_BLL:
+            if (n == 0) return 'b';
+            if (n == 1 || n == 2) return 'l';
+            break;
         case OP_GT_BFF:
         case OP_GE_BFF:
         case OP_EQ_BFF:
@@ -132,9 +171,12 @@
             if (n == 0) return 'b';
             if (n == 1 || n == 2) return 'f';
             break;
-        case OP_CAST_IB:
-            if (n == 0) return 'i';
-            if (n == 1) return 'b';
+        case OP_GT_BSS:
+        case OP_GE_BSS:
+        case OP_EQ_BSS:
+        case OP_NE_BSS:
+            if (n == 0) return 'b';
+            if (n == 1 || n == 2) return 's';
             break;
         case OP_COPY_II:
         case OP_ONES_LIKE_II:
@@ -149,18 +191,39 @@
         case OP_POW_III:
             if (n == 0 || n == 1 || n == 2) return 'i';
             break;
-        case OP_WHERE_IFII:
+        case OP_WHERE_IBII:
             if (n == 0 || n == 2 || n == 3) return 'i';
-            if (n == 1) return 'f';
+            if (n == 1) return 'b';
             break;
-        case OP_CAST_FB:
-            if (n == 0) return 'f';
+        case OP_CAST_LI:
+            if (n == 0) return 'l';
+            if (n == 1) return 'i';
+            break;
+        case OP_COPY_LL:
+        case OP_ONES_LIKE_LL:
+        case OP_NEG_LL:
+            if (n == 0 || n == 1) return 'l';
+            break;
+        case OP_ADD_LLL:
+        case OP_SUB_LLL:
+        case OP_MUL_LLL:
+        case OP_DIV_LLL:
+        case OP_MOD_LLL:
+        case OP_POW_LLL:
+            if (n == 0 || n == 1 || n == 2) return 'l';
+            break;
+        case OP_WHERE_LBLL:
+            if (n == 0 || n == 2 || n == 3) return 'l';
             if (n == 1) return 'b';
             break;
         case OP_CAST_FI:
             if (n == 0) return 'f';
             if (n == 1) return 'i';
             break;
+        case OP_CAST_FL:
+            if (n == 0) return 'f';
+            if (n == 1) return 'l';
+            break;
         case OP_COPY_FF:
         case OP_ONES_LIKE_FF:
         case OP_NEG_FF:
@@ -179,8 +242,9 @@
         case OP_ARCTAN2_FFF:
             if (n == 0 || n == 1 || n == 2) return 'f';
             break;
-        case OP_WHERE_FFFF:
-            if (n == 0 || n == 1 || n == 2 || n == 3) return 'f';
+        case OP_WHERE_FBFF:
+            if (n == 0 || n == 2 || n == 3) return 'f';
+            if (n == 1) return 'b';
             break;
         case OP_FUNC_FF:
             if (n == 0 || n == 1) return 'f';
@@ -195,14 +259,14 @@
             if (n == 0) return 'b';
             if (n == 1 || n == 2) return 'c';
             break;
-        case OP_CAST_CB:
-            if (n == 0) return 'c';
-            if (n == 1) return 'b';
-            break;
         case OP_CAST_CI:
             if (n == 0) return 'c';
             if (n == 1) return 'i';
             break;
+        case OP_CAST_CL:
+            if (n == 0) return 'c';
+            if (n == 1) return 'l';
+            break;
         case OP_CAST_CF:
             if (n == 0) return 'c';
             if (n == 1) return 'f';
@@ -218,9 +282,9 @@
         case OP_DIV_CCC:
             if (n == 0 || n == 1 || n == 2) return 'c';
             break;
-        case OP_WHERE_CFCC:
+        case OP_WHERE_CBCC:
             if (n == 0 || n == 2 || n == 3) return 'c';
-            if (n == 1) return 'f';
+            if (n == 1) return 'b';
             break;
         case OP_FUNC_CC:
             if (n == 0 || n == 1) return 'c';
@@ -239,11 +303,19 @@
             if (n == 0) return 'c';
             if (n == 1 || n == 2) return 'f';
             break;
+        case OP_COPY_SS:
+            if (n == 0 || n == 1) return 's';
+            break;
         case OP_PROD_IIN:
         case OP_SUM_IIN:
             if (n == 0 || n == 1) return 'i';
             if (n == 2) return 'n';
             break;
+        case OP_PROD_LLN:
+        case OP_SUM_LLN:
+            if (n == 0 || n == 1) return 'l';
+            if (n == 2) return 'n';
+            break;
         case OP_PROD_FFN:
         case OP_SUM_FFN:
             if (n == 0 || n == 1) return 'f';
@@ -383,6 +455,7 @@
     char **mem;             /* pointers to registers */
     char *rawmem;           /* a chunks of raw memory for storing registers */
     intp *memsteps;
+    intp *memsizes;
     int  rawmemsize;
 } NumExprObject;
 
@@ -399,6 +472,7 @@
     PyMem_Del(self->mem);
     PyMem_Del(self->rawmem);
     PyMem_Del(self->memsteps);
+    PyMem_Del(self->memsizes);
     self->ob_type->tp_free((PyObject*)self);
 }
 
@@ -425,6 +499,7 @@
         self->mem = NULL;
         self->rawmem = NULL;
         self->memsteps = NULL;
+        self->memsizes = NULL;
         self->rawmemsize = 0;
 #undef INIT_WITH
     }
@@ -454,11 +529,13 @@
 {
     switch (c) {
         case 'b': return sizeof(char);
-        case 'i': return sizeof(long);
+        case 'i': return sizeof(int);
+        case 'l': return sizeof(long long);
         case 'f': return sizeof(double);
         case 'c': return 2*sizeof(double);
+        case 's': return 0;  /* strings are ok but size must be computed */
         default:
-            PyErr_SetString(PyExc_TypeError, "signature value not in 'bifc'");
+            PyErr_SetString(PyExc_TypeError, "signature value not in 'bilfcs'");
             return -1;
     }
 }
@@ -482,11 +559,13 @@
 {
     switch (c) {
         case 'b': return PyArray_BOOL;
-        case 'i': return PyArray_LONG;
+        case 'i': return PyArray_INT;
+        case 'l': return PyArray_LONGLONG;
         case 'f': return PyArray_DOUBLE;
         case 'c': return PyArray_CDOUBLE;
+        case 's': return PyArray_STRING;
         default:
-            PyErr_SetString(PyExc_TypeError, "signature value not in 'ifc'");
+            PyErr_SetString(PyExc_TypeError, "signature value not in 'bilfcs'");
             return -1;
     }
 }
@@ -502,7 +581,6 @@
 
 static int
 get_reduction_axis(PyObject* program) {
-    char last_opcode, sig;
     int end = PyString_Size(program);
     int axis = ((unsigned char *)PyString_AS_STRING(program))[end-1];
     if (axis != 255 && axis >= MAX_DIMS)
@@ -579,7 +657,7 @@
             }
             arg = program[argloc];
 
-            if (sig != 'n' && (arg >= n_buffers) || (arg < 0)) {
+            if (sig != 'n' && ((arg >= n_buffers) || (arg < 0))) {
                 PyErr_Format(PyExc_RuntimeError, "invalid program: buffer out of range (%i) at %i", arg, argloc);
                 return -1;
             }
@@ -630,8 +708,10 @@
     PyObject *signature = NULL, *tempsig = NULL, *constsig = NULL;
     PyObject *fullsig = NULL, *program = NULL, *constants = NULL;
     PyObject *input_names = NULL, *o_constants = NULL;
+    int *itemsizes = NULL;
     char **mem = NULL, *rawmem = NULL;
     intp *memsteps;
+    intp *memsizes;
     int rawmemsize;
     static char *kwlist[] = {"signature", "tempsig",
                              "program",  "constants",
@@ -660,33 +740,53 @@
             Py_DECREF(constants);
             return -1;
         }
+        if (!(itemsizes = PyMem_New(int, n_constants))) {
+            Py_DECREF(constants);
+            return -1;
+        }
         for (i = 0; i < n_constants; i++) {
             PyObject *o;
             if (!(o = PySequence_GetItem(o_constants, i))) { /* new reference */
                 Py_DECREF(constants);
                 Py_DECREF(constsig);
+                PyMem_Del(itemsizes);
                 return -1;
             }
             PyTuple_SET_ITEM(constants, i, o); /* steals reference */
             if (PyBool_Check(o)) {
                 PyString_AS_STRING(constsig)[i] = 'b';
+                itemsizes[i] = size_from_char('b');
                 continue;
             }
             if (PyInt_Check(o)) {
                 PyString_AS_STRING(constsig)[i] = 'i';
+                itemsizes[i] = size_from_char('i');
                 continue;
             }
+            if (PyLong_Check(o)) {
+                PyString_AS_STRING(constsig)[i] = 'l';
+                itemsizes[i] = size_from_char('l');
+                continue;
+            }
             if (PyFloat_Check(o)) {
                 PyString_AS_STRING(constsig)[i] = 'f';
+                itemsizes[i] = size_from_char('f');
                 continue;
             }
             if (PyComplex_Check(o)) {
                 PyString_AS_STRING(constsig)[i] = 'c';
+                itemsizes[i] = size_from_char('c');
                 continue;
             }
-            PyErr_SetString(PyExc_TypeError, "constants must be of type int/float/complex");
+            if (PyString_Check(o)) {
+                PyString_AS_STRING(constsig)[i] = 's';
+                itemsizes[i] = PyString_GET_SIZE(o);
+                continue;
+            }
+            PyErr_SetString(PyExc_TypeError, "constants must be of type bool/int/long/float/complex/str");
             Py_DECREF(constsig);
             Py_DECREF(constants);
+            PyMem_Del(itemsizes);
             return -1;
         }
     } else {
@@ -705,23 +805,34 @@
     if (!fullsig) {
         Py_DECREF(constants);
         Py_DECREF(constsig);
+        PyMem_Del(itemsizes);
+        return -1;
     }
 
     if (!input_names) {
         input_names = Py_None;
     }
 
-    rawmemsize = BLOCK_SIZE1 * (size_from_sig(constsig) + size_from_sig(tempsig));
+    /* Compute the size of registers. */
+    rawmemsize = 0;
+    for (i = 0; i < n_constants; i++)
+        rawmemsize += itemsizes[i];
+    rawmemsize += size_from_sig(tempsig);  /* no string temporaries */
+    rawmemsize *= BLOCK_SIZE1;
+
     mem = PyMem_New(char *, 1 + n_inputs + n_constants + n_temps);
     rawmem = PyMem_New(char, rawmemsize);
-    memsteps = PyMem_New(int, 1 + n_inputs + n_constants + n_temps);
-    if (!mem || !rawmem || !memsteps) {
+    memsteps = PyMem_New(intp, 1 + n_inputs + n_constants + n_temps);
+    memsizes = PyMem_New(intp, 1 + n_inputs + n_constants + n_temps);
+    if (!mem || !rawmem || !memsteps || !memsizes) {
         Py_DECREF(constants);
         Py_DECREF(constsig);
         Py_DECREF(fullsig);
+        PyMem_Del(itemsizes);
         PyMem_Del(mem);
         PyMem_Del(rawmem);
         PyMem_Del(memsteps);
+        PyMem_Del(memsizes);
         return -1;
     }
     /*
@@ -734,10 +845,10 @@
     mem_offset = 0;
     for (i = 0; i < n_constants; i++) {
         char c = PyString_AS_STRING(constsig)[i];
-        int size = size_from_char(c);
+        int size = itemsizes[i];
         mem[i+n_inputs+1] = rawmem + mem_offset;
         mem_offset += BLOCK_SIZE1 * size;
-        memsteps[i+n_inputs+1] = size;
+        memsteps[i+n_inputs+1] = memsizes[i+n_inputs+1] = size;
         /* fill in the constants */
         if (c == 'b') {
             char *bmem = (char*)mem[i+n_inputs+1];
@@ -746,11 +857,17 @@
                 bmem[j] = value;
             }
         } else if (c == 'i') {
-            long *imem = (long*)mem[i+n_inputs+1];
-            long value = PyInt_AS_LONG(PyTuple_GET_ITEM(constants, i));
+            int *imem = (int*)mem[i+n_inputs+1];
+            int value = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(constants, i));
             for (j = 0; j < BLOCK_SIZE1; j++) {
                 imem[j] = value;
             }
+        } else if (c == 'l') {
+            long long *lmem = (long long*)mem[i+n_inputs+1];
+            long long value = PyLong_AsLongLong(PyTuple_GET_ITEM(constants, i));
+            for (j = 0; j < BLOCK_SIZE1; j++) {
+                lmem[j] = value;
+            }
         } else if (c == 'f') {
             double *dmem = (double*)mem[i+n_inputs+1];
             double value = PyFloat_AS_DOUBLE(PyTuple_GET_ITEM(constants, i));
@@ -764,14 +881,32 @@
                 cmem[j] = value.real;
                 cmem[j+1] = value.imag;
             }
+        } else if (c == 's') {
+            char *smem = (char*)mem[i+n_inputs+1];
+            char *value = PyString_AS_STRING(PyTuple_GET_ITEM(constants, i));
+            for (j = 0; j < size*BLOCK_SIZE1; j+=size) {
+                memcpy(smem + j, value, size);
+            }
         }
     }
+    /* This is no longer needed since no unusual item sizes appear
+       in temporaries (there are no string temporaries). */
+    PyMem_Del(itemsizes);
+
     /* Fill in 'mem' for temps */
     for (i = 0; i < n_temps; i++) {
-        int size = size_from_char(PyString_AS_STRING(tempsig)[i]);
+        char c = PyString_AS_STRING(tempsig)[i];
+        int size = size_from_char(c);
+        /* XXX: This check is quite useless, since using a string temporary
+           still causes a crash when freeing rawmem.  Why? */
+        if (c == 's') {
+            PyErr_SetString(PyExc_NotImplementedError,
+                            "string temporaries are not supported");
+            break;
+        }
         mem[i+n_inputs+n_constants+1] = rawmem + mem_offset;
         mem_offset += BLOCK_SIZE1 * size;
-        memsteps[i+n_inputs+n_constants+1] = size;
+        memsteps[i+n_inputs+n_constants+1] = memsizes[i+n_inputs+n_constants+1] = size;
     }
     /* See if any errors occured (e.g., in size_from_char) or if mem_offset is wrong */
     if (PyErr_Occurred() || mem_offset != rawmemsize) {
@@ -784,6 +919,7 @@
         PyMem_Del(mem);
         PyMem_Del(rawmem);
         PyMem_Del(memsteps);
+        PyMem_Del(memsizes);
         return -1;
     }
 
@@ -805,6 +941,7 @@
     REPLACE_MEM(mem);
     REPLACE_MEM(rawmem);
     REPLACE_MEM(memsteps);
+    REPLACE_MEM(memsizes);
     self->rawmemsize = rawmemsize;
 
     #undef REPLACE_OBJ
@@ -832,8 +969,8 @@
     int count;
     int size;
     int findex;
-    int *shape;
-    int *strides;
+    intp *shape;
+    intp *strides;
     int *index;
     char *buffer;
 };
@@ -847,6 +984,7 @@
     char **inputs;
     char **mem;
     intp *memsteps;
+    intp *memsizes;
     struct index_data *index_data;
 };
 
@@ -886,6 +1024,26 @@
 #define BOUNDS_CHECK(arg)
 #endif
 
+int
+stringcmp(const char *s1, const char *s2, intp maxlen1, intp maxlen2)
+{
+    intp maxlen, nextpos;
+    /* Point to this when the end of a string is found,
+       to simulate infinte trailing NUL characters. */
+    const char null = 0;
+
+    maxlen = (maxlen1 > maxlen2) ? maxlen1 : maxlen2;
+    for (nextpos = 1;  nextpos <= maxlen;  nextpos++) {
+        if (*s1 < *s2)
+            return -1;
+        if (*s1 > *s2)
+            return +1;
+        s1 = (nextpos >= maxlen1) ? &null : s1+1;
+        s2 = (nextpos >= maxlen2) ? &null : s2+1;
+    }
+    return 0;
+}
+
 static inline int
 vm_engine_1(int start, int blen, struct vm_params params, int *pc_error)
 {
@@ -943,6 +1101,7 @@
     params.index_data = index_data;
     params.mem = self->mem;
     params.memsteps = self->memsteps;
+    params.memsizes = self->memsizes;
     params.r_end = PyString_Size(self->fullsig);
     blen1 = len - len % BLOCK_SIZE1;
     r = vm_engine_1(0, blen1, params, pc_error);
@@ -966,7 +1125,7 @@
     PyObject *output = NULL, *a_inputs = NULL;
     struct index_data *inddata = NULL;
     unsigned int n_inputs, n_dimensions = 0;
-    int shape[MAX_DIMS];
+    intp shape[MAX_DIMS];
     int i, j, size, r, pc_error;
     char **inputs = NULL;
     intp strides[MAX_DIMS]; /* clean up XXX */
@@ -1004,7 +1163,12 @@
         int typecode = typecode_from_char(c);
         if (typecode == -1) goto cleanup_and_exit;
         /* Convert it just in case of a non-swapped array */
-        a = PyArray_FROM_OTF(o, typecode, NOTSWAPPED);
+        if (!PyArray_Check(o) || PyArray_TYPE(o) != PyArray_STRING) {
+            a = PyArray_FROM_OTF(o, typecode, NOTSWAPPED);
+        } else {
+            Py_INCREF(PyArray_DESCR(o));  /* typecode is not enough */
+            a = PyArray_FromAny(o, PyArray_DESCR(o), 0, 0, NOTSWAPPED, NULL);
+        }
         if (!a) goto cleanup_and_exit;
         PyTuple_SET_ITEM(a_inputs, i, a);  /* steals reference */
         if (PyArray_NDIM(a) > n_dimensions)
@@ -1042,7 +1206,7 @@
     for (i = 0; i < n_inputs; i++) {
         PyObject *a = PyTuple_GET_ITEM(a_inputs, i);
         PyObject *b;
-        int strides[MAX_DIMS];
+        intp strides[MAX_DIMS];
         int delta = n_dimensions - PyArray_NDIM(a);
         if (PyArray_NDIM(a)) {
             for (j = 0; j < n_dimensions; j++)
@@ -1071,15 +1235,25 @@
         if (PyArray_NDIM(a) == 0) {
             /* Broadcast scalars */
             intp dims[1] = {BLOCK_SIZE1};
-            b = PyArray_SimpleNew(1, dims, typecode);
+            Py_INCREF(PyArray_DESCR(a));
+            b = PyArray_SimpleNewFromDescr(1, dims, PyArray_DESCR(a));
             if (!b) goto cleanup_and_exit;
             self->memsteps[i+1] = 0;
+            self->memsizes[i+1] = PyArray_ITEMSIZE(a);
             PyTuple_SET_ITEM(a_inputs, i+2*n_inputs, b);  /* steals reference */
             inputs[i] = PyArray_DATA(b);
-            if (typecode == PyArray_LONG) {
-                long value = ((long*)PyArray_DATA(a))[0];
+            if (typecode == PyArray_BOOL) {
+                char value = ((char*)PyArray_DATA(a))[0];
                 for (j = 0; j < BLOCK_SIZE1; j++)
-                    ((long*)PyArray_DATA(b))[j] = value;
+                    ((char*)PyArray_DATA(b))[j] = value;
+            } else if (typecode == PyArray_INT) {
+                int value = ((int*)PyArray_DATA(a))[0];
+                for (j = 0; j < BLOCK_SIZE1; j++)
+                    ((int*)PyArray_DATA(b))[j] = value;
+            } else if (typecode == PyArray_LONGLONG) {
+                long long value = ((long long*)PyArray_DATA(a))[0];
+                for (j = 0; j < BLOCK_SIZE1; j++)
+                    ((long long*)PyArray_DATA(b))[j] = value;
             } else if (typecode == PyArray_DOUBLE) {
                 double value = ((double*)PyArray_DATA(a))[0];
                 for (j = 0; j < BLOCK_SIZE1; j++)
@@ -1091,17 +1265,25 @@
                     ((double*)PyArray_DATA(b))[j] = rvalue;
                     ((double*)PyArray_DATA(b))[j+1] = ivalue;
                 }
+            } else if (typecode == PyArray_STRING) {
+                int itemsize = PyArray_ITEMSIZE(a);
+                char *value = (char*)(PyArray_DATA(a));
+                for (j = 0; j < itemsize*BLOCK_SIZE1; j+=itemsize)
+                    memcpy((char*)(PyArray_DATA(b)) + j, value, itemsize);
             } else {
                 PyErr_SetString(PyExc_RuntimeError, "illegal typecode value");
                 goto cleanup_and_exit;
             }
         } else {
-            PyObject *origA = a;
-            int inner_size = -1;
-            /* Check array is contiguous */
-            for (j = PyArray_NDIM(a)-1; j >= 0; j--) {
-                if ((inner_size == -1 && PyArray_STRIDE(a, j) % PyArray_ITEMSIZE(a)) ||
-                    (inner_size != -1 && PyArray_STRIDE(a, j) != inner_size)) {
+            /* Check that discontiguous strides appear only on the last
+               dimension. If not, the arrays should be copied.
+               Furthermore, such arrays can appear when doing
+               broadcasting above, so this check really needs to be
+               here, and not in Python space. */
+            intp inner_size;
+            for (j = PyArray_NDIM(a)-2; j >= 0; j--) {
+                inner_size = PyArray_STRIDE(a, j) * PyArray_DIM(a, j);
+                if (PyArray_STRIDE(a, j+1) != inner_size) {
                     intp dims[1] = {BLOCK_SIZE1};
                     inddata[i+1].count = PyArray_NDIM(a);
                     inddata[i+1].findex = -1;
@@ -1112,20 +1294,24 @@
                     inddata[i+1].index = PyMem_New(int, inddata[i+1].count);
                     for (j = 0; j < inddata[i+1].count; j++)
                         inddata[i+1].index[j] = 0;
-                    a = PyArray_SimpleNew(1, dims, typecode);
-                    PyTuple_SET_ITEM(a_inputs, i+2*n_inputs, a);  /* steals reference */
+                    Py_INCREF(PyArray_DESCR(a));
+                    a = PyArray_SimpleNewFromDescr(1, dims, PyArray_DESCR(a));
+                    /* steals reference below */
+                    PyTuple_SET_ITEM(a_inputs, i+2*n_inputs, a);
                     break;
                 }
-                inner_size = PyArray_STRIDE(a, j) * PyArray_DIM(a, j);
             }
 
             self->memsteps[i+1] = PyArray_STRIDE(a, PyArray_NDIM(a)-1);
+            self->memsizes[i+1] = PyArray_ITEMSIZE(a);
             inputs[i] = PyArray_DATA(a);
 
         }
     }
 
     if (last_opcode(self->program) > OP_REDUCTION) {
+        /* A reduction can not result in a string,
+           so we don't need to worry about item sizes here. */
         char retsig = get_return_sig(self->program);
         int axis = get_reduction_axis(self->program);
         self->memsteps[0] = 0; /*size_from_char(retsig);*/
@@ -1188,10 +1374,26 @@
     }
     else {
         char retsig = get_return_sig(self->program);
-        self->memsteps[0] = size_from_char(retsig);
-        output = PyArray_SimpleNew(n_dimensions,
-                                   shape,
-                                   typecode_from_char(retsig));
+        if (retsig != 's') {
+            self->memsteps[0] = self->memsizes[0] = size_from_char(retsig);
+            output = PyArray_SimpleNew(
+                n_dimensions, shape, typecode_from_char(retsig));
+        } else {
+            /* Since the *only* supported operation returning a string
+             * is a copy, the size of returned strings
+             * can be directly gotten from the first (and only)
+             * input/constant/temporary. */
+            PyArray_Descr *descr;
+            if (n_inputs > 0) {  /* input, like in 'a' where a -> 'foo' */
+                descr = PyArray_DESCR(PyTuple_GET_ITEM(a_inputs, 1));
+            Py_INCREF(descr);
+            } else {  /* constant, like in '"foo"' */
+                descr = PyArray_DescrFromType(PyArray_STRING);
+                descr->elsize = self->memsizes[1];
+            }  /* no string temporaries, so no third case  */
+            self->memsteps[0] = self->memsizes[0] = self->memsizes[1];
+            output = PyArray_SimpleNewFromDescr(n_dimensions, shape, descr);
+        }
         if (!output) goto cleanup_and_exit;
     }
 
@@ -1311,17 +1513,30 @@
     add_op("invert_bb", OP_INVERT_BB);
     add_op("and_bbb", OP_AND_BBB);
     add_op("or_bbb", OP_OR_BBB);
+
+    add_op("eq_bbb", OP_EQ_BBB);
+    add_op("ne_bbb", OP_NE_BBB);
+
     add_op("gt_bii", OP_GT_BII);
     add_op("ge_bii", OP_GE_BII);
     add_op("eq_bii", OP_EQ_BII);
     add_op("ne_bii", OP_NE_BII);
 
+    add_op("gt_bll", OP_GT_BLL);
+    add_op("ge_bll", OP_GE_BLL);
+    add_op("eq_bll", OP_EQ_BLL);
+    add_op("ne_bll", OP_NE_BLL);
+
     add_op("gt_bff", OP_GT_BFF);
     add_op("ge_bff", OP_GE_BFF);
     add_op("eq_bff", OP_EQ_BFF);
     add_op("ne_bff", OP_NE_BFF);
 
-    add_op("cast_ib", OP_CAST_IB);
+    add_op("gt_bss", OP_GT_BSS);
+    add_op("ge_bss", OP_GE_BSS);
+    add_op("eq_bss", OP_EQ_BSS);
+    add_op("ne_bss", OP_NE_BSS);
+
     add_op("ones_like_ii", OP_ONES_LIKE_II);
     add_op("copy_ii", OP_COPY_II);
     add_op("neg_ii", OP_NEG_II);
@@ -1331,10 +1546,22 @@
     add_op("div_iii", OP_DIV_III);
     add_op("pow_iii", OP_POW_III);
     add_op("mod_iii", OP_MOD_III);
-    add_op("where_ifii", OP_WHERE_IFII);
+    add_op("where_ibii", OP_WHERE_IBII);
 
-    add_op("cast_fb", OP_CAST_FB);
+    add_op("cast_li", OP_CAST_LI);
+    add_op("ones_like_ll", OP_ONES_LIKE_LL);
+    add_op("copy_ll", OP_COPY_LL);
+    add_op("neg_ll", OP_NEG_LL);
+    add_op("add_lll", OP_ADD_LLL);
+    add_op("sub_lll", OP_SUB_LLL);
+    add_op("mul_lll", OP_MUL_LLL);
+    add_op("div_lll", OP_DIV_LLL);
+    add_op("pow_lll", OP_POW_LLL);
+    add_op("mod_lll", OP_MOD_LLL);
+    add_op("where_lbll", OP_WHERE_LBLL);
+
     add_op("cast_fi", OP_CAST_FI);
+    add_op("cast_fl", OP_CAST_FL);
     add_op("copy_ff", OP_COPY_FF);
     add_op("ones_like_ff", OP_ONES_LIKE_FF);
     add_op("neg_cc", OP_NEG_CC);
@@ -1350,15 +1577,15 @@
     add_op("tan_ff", OP_TAN_FF);
     add_op("sqrt_ff", OP_SQRT_FF);
     add_op("arctan2_fff", OP_ARCTAN2_FFF);
-    add_op("where_ffff", OP_WHERE_FFFF);
+    add_op("where_fbff", OP_WHERE_FBFF);
     add_op("func_ff", OP_FUNC_FF);
     add_op("func_fff", OP_FUNC_FFF);
 
     add_op("eq_bcc", OP_EQ_BCC);
     add_op("ne_bcc", OP_NE_BCC);
 
-    add_op("cast_cb", OP_CAST_CB);
     add_op("cast_ci", OP_CAST_CI);
+    add_op("cast_cl", OP_CAST_CL);
     add_op("cast_cf", OP_CAST_CF);
     add_op("copy_cc", OP_COPY_CC);
     add_op("ones_like_cc", OP_ONES_LIKE_CC);
@@ -1367,7 +1594,7 @@
     add_op("sub_ccc", OP_SUB_CCC);
     add_op("mul_ccc", OP_MUL_CCC);
     add_op("div_ccc", OP_DIV_CCC);
-    add_op("where_cfcc", OP_WHERE_CFCC);
+    add_op("where_cbcc", OP_WHERE_CBCC);
     add_op("func_cc", OP_FUNC_CC);
     add_op("func_ccc", OP_FUNC_CCC);
 
@@ -1375,11 +1602,15 @@
     add_op("imag_fc", OP_IMAG_FC);
     add_op("complex_cff", OP_COMPLEX_CFF);
 
+    add_op("copy_ss", OP_COPY_SS);
+
     add_op("sum_iin", OP_SUM_IIN);
+    add_op("sum_lln", OP_SUM_LLN);
     add_op("sum_ffn", OP_SUM_FFN);
     add_op("sum_ccn", OP_SUM_CCN);
 
     add_op("prod_iin", OP_PROD_IIN);
+    add_op("prod_lln", OP_PROD_LLN);
     add_op("prod_ffn", OP_PROD_FFN);
     add_op("prod_ccn", OP_PROD_CCN);
 

Modified: branches/scipy.scons/scipy/sandbox/numexpr/tests/test_numexpr.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/tests/test_numexpr.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/tests/test_numexpr.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -6,7 +6,7 @@
 from numexpr import E, numexpr, evaluate, disassemble
 restore_path()
 
-class TestNumExpr(NumpyTestCase):
+class test_numexpr(NumpyTestCase):
     def check_simple(self):
         ex = 2.0 * E.a + 3.0 * E.b * E.c
         func = numexpr(ex, signature=[('a', float), ('b', float), ('c', float)])
@@ -63,14 +63,14 @@
         x = x.astype(int)
         assert_equal(evaluate("sum(x**2+2,axis=0)"), sum(x**2+2,axis=0))
         assert_equal(evaluate("prod(x**2+2,axis=0)"), prod(x**2+2,axis=0))
+        # Check longs
+        x = x.astype(long)
+        assert_equal(evaluate("sum(x**2+2,axis=0)"), sum(x**2+2,axis=0))
+        assert_equal(evaluate("prod(x**2+2,axis=0)"), prod(x**2+2,axis=0))
         # Check complex
         x = x + 5j
         assert_equal(evaluate("sum(x**2+2,axis=0)"), sum(x**2+2,axis=0))
         assert_equal(evaluate("prod(x**2+2,axis=0)"), prod(x**2+2,axis=0))
-        # Check boolean (should cast to integer)
-        x = (arange(10) % 2).astype(bool)
-        assert_equal(evaluate("prod(x,axis=0)"), prod(x,axis=0))
-        assert_equal(evaluate("sum(x,axis=0)"), sum(x,axis=0))
 
     def check_axis(self):
         y = arange(9.0).reshape(3,3)
@@ -95,7 +95,7 @@
                     [('mul_fff', 'r0', 'r1[x]', 'r1[x]'),
                      ('add_fff', 'r0', 'r0', 'c2[2.0]')])
 
-class TestEvaluate(NumpyTestCase):
+class test_evaluate(NumpyTestCase):
     def check_simple(self):
         a = array([1., 2., 3.])
         b = array([4., 5., 6.])
@@ -187,8 +187,8 @@
           '2*a + (cos(3)+5)*sinh(cos(b))',
           '2*a + arctan2(a, b)',
           'arcsin(0.5)',
-          'where(a, 2, b)',
-          'where((a-10).real, a, 2)',
+          'where(a != 0.0, 2, b)',
+          'where((a-10).real != 0.0, a, 2)',
           'cos(1+1)',
           '1+1',
           '1',
@@ -239,7 +239,7 @@
 
 class Skip(Exception): pass
 
-class TestExpressions(NumpyTestCase):
+class test_expressions(NumpyTestCase):
     pass
 
 def generate_check_expressions():
@@ -274,7 +274,7 @@
                 new.instancemethod(method, None, test_expressions))
     x = None
     for test_scalar in [0,1,2]:
-        for dtype in [int, float, complex]:
+        for dtype in [int, long, float, complex]:
             array_size = 100
             a = arange(2*array_size, dtype=dtype)[::2]
             a2 = zeros([array_size, array_size], dtype=dtype)
@@ -298,7 +298,7 @@
                                '<' in expr or '>' in expr or '%' in expr
                                or "arctan2" in expr or "fmod" in expr):
                             continue # skip complex comparisons
-                        if dtype == int and test_scalar and expr == '(a+1) ** -1':
+                        if dtype in (int, long) and test_scalar and expr == '(a+1) ** -1':
                             continue
                         make_check_method(a, a2, b, c, d, e, x,
                                           expr, test_scalar, dtype,
@@ -306,5 +306,145 @@
 
 generate_check_expressions()
 
+class test_int32_int64(NumpyTestCase):
+    def check_small_long(self):
+        # Small longs should not be downgraded to ints.
+        res = evaluate('42L')
+        assert_array_equal(res, 42)
+        self.assertEqual(res.dtype.name, 'int64')
+
+    def check_big_int(self):
+        # Big ints should be promoted to longs.
+        # This test may only fail under 64-bit platforms.
+        res = evaluate('2**40')
+        assert_array_equal(res, 2**40)
+        self.assertEqual(res.dtype.name, 'int64')
+
+    def check_long_constant_promotion(self):
+        int32array = arange(100, dtype='int32')
+        res = int32array * 2
+        res32 = evaluate('int32array * 2')
+        res64 = evaluate('int32array * 2L')
+        assert_array_equal(res, res32)
+        assert_array_equal(res, res64)
+        self.assertEqual(res32.dtype.name, 'int32')
+        self.assertEqual(res64.dtype.name, 'int64')
+
+    def check_int64_array_promotion(self):
+        int32array = arange(100, dtype='int32')
+        int64array = arange(100, dtype='int64')
+        respy = int32array * int64array
+        resnx = evaluate('int32array * int64array')
+        assert_array_equal(respy, resnx)
+        self.assertEqual(resnx.dtype.name, 'int64')
+
+class test_strings(NumpyTestCase):
+    BLOCK_SIZE1 = 128
+    BLOCK_SIZE2 = 8
+    str_list1 = ['foo', 'bar', '', '  ']
+    str_list2 = ['foo', '', 'x', ' ']
+    str_nloops = len(str_list1) * (BLOCK_SIZE1 + BLOCK_SIZE2 + 1)
+    str_array1 = array(str_list1 * str_nloops)
+    str_array2 = array(str_list2 * str_nloops)
+    str_constant = 'doodoo'
+
+    def check_null_chars(self):
+        str_list = [
+            '\0\0\0', '\0\0foo\0', '\0\0foo\0b', '\0\0foo\0b\0',
+            'foo\0', 'foo\0b', 'foo\0b\0', 'foo\0bar\0baz\0\0' ]
+        for s in str_list:
+            r = evaluate('s')
+            self.assertEqual(s, r.tostring())  # check *all* stored data
+
+    def check_compare_copy(self):
+        sarr = self.str_array1
+        expr = 'sarr'
+        res1 = eval(expr)
+        res2 = evaluate(expr)
+        assert_array_equal(res1, res2)
+
+    def check_compare_array(self):
+        sarr1 = self.str_array1
+        sarr2 = self.str_array2
+        expr = 'sarr1 >= sarr2'
+        res1 = eval(expr)
+        res2 = evaluate(expr)
+        assert_array_equal(res1, res2)
+
+    def check_compare_variable(self):
+        sarr = self.str_array1
+        svar = self.str_constant
+        expr = 'sarr >= svar'
+        res1 = eval(expr)
+        res2 = evaluate(expr)
+        assert_array_equal(res1, res2)
+
+    def check_compare_constant(self):
+        sarr = self.str_array1
+        expr = 'sarr >= %r' % self.str_constant
+        res1 = eval(expr)
+        res2 = evaluate(expr)
+        assert_array_equal(res1, res2)
+
+    def check_add_string_array(self):
+        sarr1 = self.str_array1
+        sarr2 = self.str_array2
+        expr = 'sarr1 + sarr2'
+        self.assert_missing_op('add_sss', expr, locals())
+
+    def check_add_numeric_array(self):
+        sarr = self.str_array1
+        narr = arange(len(sarr), dtype='int32')
+        expr = 'sarr >= narr'
+        self.assert_missing_op('ge_bsi', expr, locals())
+
+    def assert_missing_op(self, op, expr, local_dict):
+        msg = "expected NotImplementedError regarding '%s'" % op
+        try:
+            evaluate(expr, local_dict)
+        except NotImplementedError, nie:
+            if "'%s'" % op not in nie.args[0]:
+                self.fail(msg)
+        else:
+            self.fail(msg)
+
+    def check_compare_prefix(self):
+        # Check comparing two strings where one is a prefix of the
+        # other.
+        for s1, s2 in [ ('foo', 'foobar'), ('foo', 'foo\0bar'),
+                        ('foo\0a', 'foo\0bar') ]:
+            self.assert_(evaluate('s1 < s2'))
+            self.assert_(evaluate('s1 <= s2'))
+            self.assert_(evaluate('~(s1 == s2)'))
+            self.assert_(evaluate('~(s1 >= s2)'))
+            self.assert_(evaluate('~(s1 > s2)'))
+
+        # Check for NumPy array-style semantics in string equality.
+        s1, s2 = 'foo', 'foo\0\0'
+        self.assert_(evaluate('s1 == s2'))
+
+# Case for testing selections in fields which are aligned but whose
+# data length is not an exact multiple of the length of the record.
+# The following test exposes the problem only in 32-bit machines,
+# because in 64-bit machines 'c2' is unaligned.  However, this should
+# check most platforms where, while not unaligned, 'len(datatype) >
+# boundary_alignment' is fullfilled.
+class test_irregular_stride(NumpyTestCase):
+    def check_select(self):
+        f0 = arange(10, dtype=int32)
+        f1 = arange(10, dtype=float64)
+
+        irregular = rec.fromarrays([f0, f1])
+
+        f0 = irregular['f0']
+        f1 = irregular['f1']
+
+        i0 = evaluate('f0 < 5')
+        i1 = evaluate('f1 < 5')
+
+        assert_array_equal(f0[i0], arange(5, dtype=int32))
+        assert_array_equal(f1[i1], arange(5, dtype=float64))
+
+
 if __name__ == '__main__':
     NumpyTest().run()

Deleted: branches/scipy.scons/scipy/sandbox/numexpr/timing.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/numexpr/timing.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/numexpr/timing.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -1,136 +0,0 @@
-import timeit, numpy
-
-array_size = 1e6
-iterations = 10
-
-def compare_times(setup, expr):
-    print "Expression:", expr
-    namespace = {}
-    exec setup in namespace
-
-    numpy_timer = timeit.Timer(expr, setup)
-    numpy_time = numpy_timer.timeit(number=iterations)
-    print 'numpy:', numpy_time / iterations
-
-    try:
-        weave_timer = timeit.Timer('blitz("result=%s")' % expr, setup)
-        weave_time = weave_timer.timeit(number=iterations)
-        print "Weave:", weave_time/iterations
-
-        print "Speed-up of weave over numpy:", numpy_time/weave_time
-    except:
-        print "Skipping weave timing"
-
-    numexpr_timer = timeit.Timer('evaluate("%s", optimization="aggressive")' % expr, setup)
-    numexpr_time = numexpr_timer.timeit(number=iterations)
-    print "numexpr:", numexpr_time/iterations
-
-    print "Speed-up of numexpr over numpy:", numpy_time/numexpr_time
-    return numpy_time/numexpr_time
-
-setup1 = """\
-from numpy import arange
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-result = arange(%f)
-b = arange(%f)
-c = arange(%f)
-d = arange(%f)
-e = arange(%f)
-""" % ((array_size,)*5)
-expr1 = 'b*c+d*e'
-
-setup2 = """\
-from numpy import arange
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-a = arange(%f)
-b = arange(%f)
-result = arange(%f)
-""" % ((array_size,)*3)
-expr2 = '2*a+3*b'
-
-
-setup3 = """\
-from numpy import arange, sin, cos, sinh
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-a = arange(2*%f)[::2]
-b = arange(%f)
-result = arange(%f)
-""" % ((array_size,)*3)
-expr3 = '2*a + (cos(3)+5)*sinh(cos(b))'
-
-
-setup4 = """\
-from numpy import arange, sin, cos, sinh, arctan2
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-a = arange(2*%f)[::2]
-b = arange(%f)
-result = arange(%f)
-""" % ((array_size,)*3)
-expr4 = '2*a + arctan2(a, b)'
-
-
-setup5 = """\
-from numpy import arange, sin, cos, sinh, arctan2, sqrt, where
-try: from scipy.weave import blitz
-except: pass
-from numexpr import evaluate
-a = arange(2*%f, dtype=float)[::2]
-b = arange(%f, dtype=float)
-result = arange(%f, dtype=float)
-""" % ((array_size,)*3)
-expr5 = 'where(0.1*a > arctan2(a, b), 2*a, arctan2(a,b))'
-
-expr6 = 'where(a, 2, b)'
-
-expr7 = 'where(a-10, a, 2)'
-
-expr8 = 'where(a%2, b+5, 2)'
-
-expr9 = 'where(a%2, 2, b+5)'
-
-expr10 = 'a**2 + (b+1)**-2.5'
-
-expr11 = '(a+1)**50'
-
-expr12 = 'sqrt(a**2 + b**2)'
-
-def compare(check_only=False):
-    total = 0
-    total += compare_times(setup1, expr1)
-    print
-    total += compare_times(setup2, expr2)
-    print
-    total += compare_times(setup3, expr3)
-    print
-    total += compare_times(setup4, expr4)
-    print
-    total += compare_times(setup5, expr6)
-    print
-    total += compare_times(setup5, expr7)
-    print
-    total += compare_times(setup5, expr8)
-    print
-    total += compare_times(setup5, expr9)
-    print
-    total += compare_times(setup5, expr10)
-    print
-    total += compare_times(setup5, expr11)
-    print
-    total += compare_times(setup5, expr12)
-    print
-    print "Average =", total / 11.0
-    return total
-
-if __name__ == '__main__':
-    averages = []
-    for i in range(10):
-        averages.append(compare())
-    print "Averages:", ', '.join("%.2f" % x for x in averages)

Modified: branches/scipy.scons/scipy/sandbox/timeseries/dates.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/dates.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/dates.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -36,17 +36,21 @@
 cseries.set_callback_DateFromString(DateFromString)
 cseries.set_callback_DateTimeFromString(DateTimeFromString)
 
-from cseries import Date, thisday, check_freq, check_freq_str, get_freq_group,\
+from cseries import Date, now, check_freq, check_freq_str, get_freq_group,\
                     DateCalc_Error, DateCalc_RangeError
-today = thisday
 
+# aliases for `now` function. These are deprecated
+today = now
+thisday = now
+
 __all__ = [
 'Date', 'DateArray','isDate','isDateArray',
 'DateError', 'ArithmeticDateError', 'FrequencyDateError','InsufficientDateError',
 'datearray','date_array', 'date_array_fromlist', 'date_array_fromrange',
-'day_of_week','day_of_year','day','month','quarter','year','hour','minute',
-'second','thisday','today','prevbusday','period_break', 'check_freq',
-'check_freq_str','get_freq_group', 'DateCalc_Error', 'DateCalc_RangeError'
+'day_of_week','weekday','day_of_year','day','month','quarter','year','hour',
+'minute','second','now','thisday','today','prevbusday','period_break',
+'check_freq','check_freq_str','get_freq_group', 'DateCalc_Error',
+'DateCalc_RangeError'
            ]
 
 
@@ -93,22 +97,23 @@
 def prevbusday(day_end_hour=18, day_end_min=0):
     """Returns the previous business day (Monday-Friday) at business frequency.
 
-:Parameters:
-    - day_end_hour : (int, *[18]* )
-    - day_end_min : (int, *[0]*)
+*Parameters*:
+    day_end_hour : {18, int} (optional)
+    day_end_min : {0, int} (optional)
 
-:Return values:
+*Return values*:
     If it is currently Saturday or Sunday, then the preceding Friday will be
     returned. If it is later than the specified day_end_hour and day_end_min,
-    thisday('b') will be returned. Otherwise, thisday('b')-1 will be returned.
+    now('Business') will be returned. Otherwise, now('Business')-1 will be
+    returned.
 """
     tempDate = dt.datetime.now()
     dateNum = tempDate.hour + float(tempDate.minute)/60
     checkNum = day_end_hour + float(day_end_min)/60
     if dateNum < checkNum:
-        return thisday(_c.FR_BUS) - 1
+        return now(_c.FR_BUS) - 1
     else:
-        return thisday(_c.FR_BUS)
+        return now(_c.FR_BUS)
 
 
 def isDate(data):
@@ -283,9 +288,11 @@
         "Returns the day of month."
         return self.__getdateinfo__('D')
     @property
-    def day_of_week(self):
+    def weekday(self):
         "Returns the day of week."
         return self.__getdateinfo__('W')
+    # deprecated alias for weekday
+    day_of_week = weekday
     @property
     def day_of_year(self):
         "Returns the day of year."
@@ -329,7 +336,7 @@
         return self.__getdateinfo__('I')
 
     days = day
-    weekdays = day_of_week
+    weekdays = weekday
     yeardays = day_of_year
     months = month
     quarters = quarter
@@ -355,7 +362,6 @@
         "Converts the dates from values to ordinals."
         # Note: we better try to cache the result
         if self._cachedinfo['toord'] is None:
-#            diter = (Date(self.freq, value=d).toordinal() for d in self)
             if self.freq == _c.FR_UND:
                 diter = (d.value for d in self)
             else:
@@ -364,6 +370,14 @@
             self._cachedinfo['toord'] = toord
         return self._cachedinfo['toord']
     #
+    def tolist(self):
+        """Returns a hierarchical python list of standard datetime objects."""
+        _result = numpy.empty(self.shape, dtype=numpy.object_)
+        _result.flat = [d.datetime for d in self.ravel()]
+#        for idx, val in numpy.ndenumerate(self):
+#            operator.setitem(_result, idx, Date(freq=self.freq, value=val).datetime)
+        return _result.tolist()
+    #
     def tostring(self):
         "Converts the dates to strings."
         # Note: we better cache the result
@@ -571,10 +585,10 @@
             dates = [Date(freq, datetime=m) for m in dlist]
         #...as datetime objects
         elif hasattr(template, 'toordinal'):
-            ords = numpy.fromiter((d.toordinal() for d in dlist), float_)
             if freq == _c.FR_UND:
+                ords = numpy.fromiter((d.toordinal() for d in dlist), float_)
                 freq = guess_freq(ords)
-            dates = [Date(freq, datetime=dt.datetime.fromordinal(a)) for a in ords]
+            dates = [Date(freq, datetime=d) for d in dlist]
     #
     result = DateArray(dates, freq)
     result._unsorted = idx
@@ -674,7 +688,9 @@
         except SystemError:
             return getattr(numpy,self._methodname).__call__(caller, *args, **params)
 #............................
-day_of_week = _frommethod('day_of_week')
+weekday = _frommethod('day_of_week')
+# deprecated alias for weekday
+day_of_week = weekday
 day_of_year = _frommethod('day_of_year')
 year = _frommethod('year')
 quarter = _frommethod('quarter')
@@ -705,10 +721,20 @@
     import maskedarray.testutils
     from maskedarray.testutils import assert_equal
 
-    if 1:
+    if 0:
         dlist = ['2007-%02i' % i for i in range(1,5)+range(7,13)]
         mdates = date_array_fromlist(dlist, 'M')
-        
-    if 2:
+    #    
+    if 0:
         dlist = ['2007-01','2007-03','2007-04','2007-02']
         mdates = date_array_fromlist(dlist, 'M')
+    #
+    if 1:
+        import datetime
+        dlist = [dt.datetime(2001,1,1,0), 
+                 dt.datetime(2001,1,2,1),
+                 dt.datetime(2001,1,3,2)]
+        _dates = date_array(dlist,freq='H')
+        #
+        assert_equal(_dates.hour, [0,1,2])
+        assert_equal(_dates.day, [1,2,3])

Modified: branches/scipy.scons/scipy/sandbox/timeseries/include/c_dates.h
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/include/c_dates.h	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/include/c_dates.h	2007-11-24 10:53:58 UTC (rev 3583)
@@ -110,7 +110,7 @@
 PyObject *DateArray_getDateInfo(PyObject *, PyObject *);
 
 
-PyObject *c_dates_thisday(PyObject *, PyObject *);
+PyObject *c_dates_now(PyObject *, PyObject *);
 PyObject *c_dates_check_freq(PyObject *, PyObject *);
 PyObject *c_dates_check_freq_str(PyObject *, PyObject *);
 PyObject *c_dates_get_freq_group(PyObject *, PyObject *);

Modified: branches/scipy.scons/scipy/sandbox/timeseries/lib/moving_funcs.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/lib/moving_funcs.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/lib/moving_funcs.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -366,10 +366,10 @@
 
 ###############################################################################
 if __name__ == '__main__':
-    from timeseries import time_series, today
+    from timeseries import time_series, now
     from maskedarray.testutils import assert_equal, assert_almost_equal
     #
-    series = time_series(N.arange(10),start_date=today('D'))
+    series = time_series(N.arange(10),start_date=now('D'))
     #
     filtered = mov_sum(series,3)
     assert_equal(filtered, [0,1,3,6,9,12,15,18,21,24])

Modified: branches/scipy.scons/scipy/sandbox/timeseries/plotlib.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/plotlib.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/plotlib.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -30,6 +30,7 @@
 #from matplotlib.transforms import nonsingular
 
 import numpy
+from numpy import int_, bool_
 import maskedarray as MA
 
 import timeseries
@@ -47,16 +48,18 @@
 The specific Subplot object class to add is given through the keywords
 `SubplotClass` or `class`.
 
-:Parameters:
-    `figure_instance` : Figure object
+*:Parameters*:
+    figure_instance : {Figure object}
         Figure to which the generic subplot should be attached.
-    `args` : Misc
+    args : {var}
         Miscellaneous arguments to the subplot.
-    `kwargs` : Dictionary
+    kwargs : {Dictionary}
         Keywords. Same keywords as `Subplot`, with the addition of
-        - `SubplotClass` : Type of subplot
-        - `subclass` : Shortcut to `SubplotClass`.
-        - any keyword required by the `SubplotClass` subclass.
+        * SubplotClass* : {string}
+            Type of subplot
+        *subclass* : {string}
+            Shortcut to SubplotClass.
+        * any keyword required by the `SubplotClass` subclass.
     """
 
     key = figure_instance._make_key(*args, **kwargs)
@@ -171,7 +174,7 @@
     else:
         return True
 
-def _daily_finder(vmin, vmax, freq, aslocator):
+def _daily_finder(vmin, vmax, freq, asformatter):
 
     if freq == _c.FR_BUS:
         periodsperyear = 261
@@ -187,13 +190,13 @@
 
     (vmin, vmax) = (int(vmin), int(vmax))
     span = vmax - vmin + 1
-    dates = date_array(start_date=Date(freq,vmin),
-                       end_date=Date(freq, vmax))
-    default = numpy.arange(vmin, vmax+1)
+    dates_ = date_array(start_date=Date(freq,vmin),
+                        end_date=Date(freq, vmax))
     # Initialize the output
-    if not aslocator:
-        format = numpy.empty(default.shape, dtype="|S10")
-        format.flat = ''
+    info = numpy.zeros(span,
+                       dtype=[('val',int_),('maj',bool_),('min',bool_),('fmt','|S10')])
+    info['val'] = numpy.arange(vmin, vmax+1)
+    info['fmt'] = ''
 
     def first_label(label_flags):
         if label_flags[0] == 0: return label_flags[1]
@@ -201,115 +204,103 @@
 
     # Case 1. Less than a month
     if span <= periodspermonth:
-        month_start = period_break(dates,'month')
-        if aslocator:
-            major = default[month_start]
-            minor = default
-        else:
-            year_start = period_break(dates,'year')
-            format[:] = '%d'
-            format[month_start] = '%d\n%b'
-            format[year_start] = '%d\n%b\n%Y'
+        month_start = period_break(dates_,'month')
+        info['maj'][month_start] = True
+        info['min'] = True
+        if asformatter:
+            year_start = period_break(dates_,'year')
+            info['fmt'][:] = '%d'
+            info['fmt'][month_start] = '%d\n%b'
+            info['fmt'][year_start] = '%d\n%b\n%Y'
             if not has_level_label(year_start):
                 if not has_level_label(month_start):
-                    if dates.size > 1:
+                    if dates_.size > 1:
                         idx = 1
                     else:
                         idx = 0
-                    format[idx] = '%d\n%b\n%Y'
+                    info['fmt'][idx] = '%d\n%b\n%Y'
                 else:
-                    format[first_label(month_start)] = '%d\n%b\n%Y'
+                    info['fmt'][first_label(month_start)] = '%d\n%b\n%Y'
     # Case 2. Less than three months
     elif span <= periodsperyear//4:
         month_start = period_break(dates,'month')
-        if aslocator:
-            major = default[month_start]
-            minor = default
-        else:
-            week_start = period_break(dates,'week')
-            year_start = period_break(dates,'year')
+        info['maj'][month_start] = True
+        info['min'] = True
+        if asformatter:
+            week_start = period_break(dates_,'week')
+            year_start = period_break(dates_,'year')
 
-            format[week_start] = '%d'
-            format[month_start] = '\n\n%b'
-            format[year_start] = '\n\n%b\n%Y'
+            info['fmt'][week_start] = '%d'
+            info['fmt'][month_start] = '\n\n%b'
+            info['fmt'][year_start] = '\n\n%b\n%Y'
             if not has_level_label(year_start):
                 if not has_level_label(month_start):
-                    format[first_label(week_start)] = '\n\n%b\n%Y'
+                    info['fmt'][first_label(week_start)] = '\n\n%b\n%Y'
                 else:
-                    format[first_label(month_start)] = '\n\n%b\n%Y'
+                    info['fmt'][first_label(month_start)] = '\n\n%b\n%Y'
     # Case 3. Less than 14 months ...............
     elif span <= 1.15 * periodsperyear:
+        d_minus_1 = dates_-1
 
-        if aslocator:
-            d_minus_1 = dates-1
+        month_diff = numpy.abs(dates_.month - d_minus_1.month)
+        week_diff = numpy.abs(dates_.week - d_minus_1.week)
+        minor_idx = (month_diff + week_diff).nonzero()[0]
 
-            month_diff = numpy.abs(dates.month - d_minus_1.month)
-            week_diff = numpy.abs(dates.week - d_minus_1.week)
-            minor_idx = (month_diff + week_diff).nonzero()[0]
+        info['maj'][month_diff != 0] = True
+        info['min'][minor_idx] = True
+        if asformatter:
+            year_start = period_break(dates_,'year')
+            month_start = period_break(dates_,'month')
 
-            major = default[month_diff != 0]
-            minor = default[minor_idx]
-        else:
-            year_start = period_break(dates,'year')
-            month_start = period_break(dates,'month')
-
-            format[month_start] = '%b'
-            format[year_start] = '%b\n%Y'
+            info['fmt'][month_start] = '%b'
+            info['fmt'][year_start] = '%b\n%Y'
             if not has_level_label(year_start):
-                format[first_label(month_start)] = '%b\n%Y'
+                info['fmt'][first_label(month_start)] = '%b\n%Y'
     # Case 4. Less than 2.5 years ...............
     elif span <= 2.5 * periodsperyear:
-        year_start = period_break(dates,'year')
-        if aslocator:
-            month_start = period_break(dates, 'quarter')
-            major = default[year_start]
-            minor = default[month_start]
-        else:
-            quarter_start = period_break(dates, 'quarter')
-            format[quarter_start] = '%b'
-            format[year_start] = '%b\n%Y'
+        year_start = period_break(dates_,'year')
+        month_start = period_break(dates_, 'quarter')
+        info['maj'][year_start] = True
+        info['min'][month_start] = True
+        if asformatter:
+            quarter_start = period_break(dates_, 'quarter')
+            info['fmt'][quarter_start] = '%b'
+            info['fmt'][year_start] = '%b\n%Y'
     # Case 4. Less than 4 years .................
     elif span <= 4 * periodsperyear:
-        year_start = period_break(dates,'year')
-        month_start = period_break(dates, 'month')
-        if aslocator:
-            major = default[year_start]
-            minor = default[month_start]
-        else:
-            month_break = dates[month_start].month
+        year_start = period_break(dates_,'year')
+        month_start = period_break(dates_, 'month')
+        info['maj'][year_start] = True
+        info['min'][month_start] = True
+        if asformatter:
+            month_break = dates_[month_start].month
             jan_or_jul = month_start[(month_break == 1) | (month_break == 7)]
-            format[jan_or_jul] = '%b'
-            format[year_start] = '%b\n%Y'
+            info['fmt'][jan_or_jul] = '%b'
+            info['fmt'][year_start] = '%b\n%Y'
     # Case 5. Less than 11 years ................
     elif span <= 11 * periodsperyear:
-        year_start = period_break(dates,'year')
-        if aslocator:
-            quarter_start = period_break(dates, 'quarter')
-            major = default[year_start]
-            minor = default[quarter_start]
-        else:
-            format[year_start] = '%Y'
+        year_start = period_break(dates_,'year')
+        quarter_start = period_break(dates_, 'quarter')
+        info['maj'][year_start] = True
+        info['min'][quarter_start] = True
+        if asformatter:
+            info['fmt'][year_start] = '%Y'
     # Case 6. More than 12 years ................
     else:
         year_start = period_break(dates,'year')
-        year_break = dates[year_start].years
+        year_break = dates_[year_start].years
         nyears = span/periodsperyear
         (min_anndef, maj_anndef) = _get_default_annual_spacing(nyears)
         major_idx = year_start[(year_break % maj_anndef == 0)]
-        if aslocator:
-            major = default[major_idx]
-            minor_idx = year_start[(year_break % min_anndef == 0)]
-            minor = default[minor_idx]
-        else:
-            format[major_idx] = '%Y'
+        info['maj'][major_idx] = True
+        minor_idx = year_start[(year_break % min_anndef == 0)]
+        info['min'][minor_idx] = True
+        if asformatter:
+            info['fmt'][major_idx] = '%Y'
     #............................................
-    if aslocator:
-        return minor, major
-    else:
-        formatted = (format != '')
-        return dict([(d,f) for (d,f) in zip(default[formatted],format[formatted])])
+    return info
 #...............................................................................
-def _monthly_finder(vmin, vmax, freq, aslocator):
+def _monthly_finder(vmin, vmax, freq, asformatter):
     if freq != _c.FR_MTH:
         raise ValueError("Unexpected frequency")
     periodsperyear = 12
@@ -317,143 +308,128 @@
     (vmin, vmax) = (int(vmin), int(vmax))
     span = vmax - vmin + 1
     #............................................
-    dates = numpy.arange(vmin, vmax+1)
-    format = numpy.empty(span, dtype="|S8")
-    format.flat = ''
-    year_start = (dates % 12 == 1).nonzero()[0]
+    # Initialize the output
+    info = numpy.zeros(span,
+                       dtype=[('val',int_),('maj',bool_),('min',bool_),('fmt','|S8')])
+    info['val'] = numpy.arange(vmin, vmax+1)
+    dates_ = info['val']
+    info['fmt'] = ''
+    year_start = (dates_ % 12 == 1).nonzero()[0]
     #............................................
     if span <= 1.15 * periodsperyear:
-        if aslocator:
-            major = dates[year_start]
-            minor = dates
-        else:
+        info['maj'][year_start] = True
+        info['min'] = True
+        if asformatter:
+            info['fmt'][:] = '%b'
+            info['fmt'][year_start] = '%b\n%Y'
 
-            format[:] = '%b'
-            format[year_start] = '%b\n%Y'
-
             if not has_level_label(year_start):
-                if dates.size > 1:
+                if dates_.size > 1:
                     idx = 1
                 else:
                     idx = 0
-                format[idx] = '%b\n%Y'
+                info['fmt'][idx] = '%b\n%Y'
     #........................
     elif span <= 2.5 * periodsperyear:
-        if aslocator:
-            major = dates[year_start]
-            minor = dates
-        else:
-            quarter_start = (dates % 3 == 1).nonzero()
-            format[quarter_start] = '%b'
-            format[year_start] = '%b\n%Y'
+        info['maj'][year_start] = True
+        info['min'] = True
+        if asformatter:
+            quarter_start = (dates_ % 3 == 1).nonzero()
+            info['fmt'][quarter_start] = '%b'
+            info['fmt'][year_start] = '%b\n%Y'
     #.......................
     elif span <= 4 * periodsperyear:
-        if aslocator:
-            major = dates[year_start]
-            minor = dates
-        else:
-            jan_or_jul = (dates % 12 == 1) | (dates % 12 == 7)
-            format[jan_or_jul] = '%b'
-            format[year_start] = '%b\n%Y'
+        info['maj'][year_start] = True
+        info['min'] = True
+        if asformatter:
+            jan_or_jul = (dates_ % 12 == 1) | (dates_ % 12 == 7)
+            info['fmt'][jan_or_jul] = '%b'
+            info['fmt'][year_start] = '%b\n%Y'
     #........................
     elif span <= 11 * periodsperyear:
-        if aslocator:
-            quarter_start = (dates % 3 == 1).nonzero()
-            major = dates[year_start]
-            minor = dates[quarter_start]
-        else:
-            format[year_start] = '%Y'
+        quarter_start = (dates_ % 3 == 1).nonzero()
+        info['maj'][year_start] = True
+        info['min'][quarter_start] = True
+        if asformatter:
+            info['fmt'][year_start] = '%Y'
    #.........................
     else:
         nyears = span/periodsperyear
         (min_anndef, maj_anndef) = _get_default_annual_spacing(nyears)
-        years = dates[year_start]//12 + 1
+        years = dates_[year_start]//12 + 1
         major_idx = year_start[(years % maj_anndef == 0)]
-        if aslocator:
-            major = dates[major_idx]
-            minor = dates[year_start[(years % min_anndef == 0)]]
-        else:
-            format[major_idx] = '%Y'
+        info['maj'][major_idx] = True
+        info['min'][year_start[(years % min_anndef == 0)]] = True
+        if asformatter:
+            info['fmt'][major_idx] = '%Y'
     #........................
-    if aslocator:
-        return minor, major
-    else:
-        formatted = (format != '')
-        return dict([(d,f) for (d,f) in zip(dates[formatted],format[formatted])])
+    return info
 #...............................................................................
-def _quarterly_finder(vmin, vmax, freq, aslocator):
+def _quarterly_finder(vmin, vmax, freq, asformatter):
     if get_freq_group(freq) != _c.FR_QTR:
         raise ValueError("Unexpected frequency")
     periodsperyear = 4
     (vmin, vmax) = (int(vmin), int(vmax))
     span = vmax - vmin + 1
     #............................................
-    dates = numpy.arange(vmin, vmax+1)
-    format = numpy.empty(span, dtype="|S8")
-    format.flat = ''
-    year_start = (dates % 4 == 1).nonzero()[0]
+    info = numpy.zeros(span,
+                       dtype=[('val',int_),('maj',bool_),('min',bool_),('fmt','|S8')])
+    info['val'] = numpy.arange(vmin, vmax+1)
+    info['fmt'] = ''
+    dates_ = info['val']
+    year_start = (dates_ % 4 == 1).nonzero()[0]
     #............................................
     if span <= 3.5 * periodsperyear:
-        if aslocator:
-            major = dates[year_start]
-            minor = dates
-        else:
-            format[:] = 'Q%q'
-            format[year_start] = 'Q%q\n%F'
+        info['maj'][year_start] = True
+        info['min'] = True
+        if asformatter:
+            info['fmt'][:] = 'Q%q'
+            info['fmt'][year_start] = 'Q%q\n%F'
             if not has_level_label(year_start):
-                if dates.size > 1:
+                if dates_.size > 1:
                     idx = 1
                 else:
                     idx = 0
-                format[idx] = 'Q%q\n%F'
+                info['fmt'][idx] = 'Q%q\n%F'
     #............................................
     elif span <= 11 * periodsperyear:
-        if aslocator:
-            major = dates[year_start]
-            minor = dates
-        else:
-            format[year_start] = '%F'
+        info['maj'][year_start] = True
+        info['min'] = True
+        if asformatter:
+            info['fmt'][year_start] = '%F'
     #............................................
     else:
-        years = dates[year_start]//4 + 1
+        years = dates_[year_start]//4 + 1
         nyears = span/periodsperyear
         (min_anndef, maj_anndef) = _get_default_annual_spacing(nyears)
         major_idx = year_start[(years % maj_anndef == 0)]
-        if aslocator:
-            major = dates[major_idx]
-            minor = dates[year_start[(years % min_anndef == 0)]]
-        else:
-            format[major_idx] = '%F'
+        info['maj'][major_idx] = True
+        info['min'][year_start[(years % min_anndef == 0)]] = True
+        if asformatter:
+            info['fmt'][major_idx] = '%F'
     #............................................
-    if aslocator:
-        return minor, major
-    else:
-        formatted = (format != '')
-        return dict([(d,f) for (d,f) in zip(dates[formatted],format[formatted])])
+    return info
 #...............................................................................
-def _annual_finder(vmin, vmax, freq, aslocator):
+def _annual_finder(vmin, vmax, freq, asformatter):
     if get_freq_group(freq) != _c.FR_ANN:
         raise ValueError("Unexpected frequency")
     (vmin, vmax) = (int(vmin), int(vmax+1))
     span = vmax - vmin + 1
     #............................................
-    dates = numpy.arange(vmin, vmax+1)
-    format = numpy.empty(span, dtype="|S8")
-    format.flat = ''
+    info = numpy.zeros(span,
+                       dtype=[('val',int_),('maj',bool_),('min',bool_),('fmt','|S8')])
+    info['val'] = numpy.arange(vmin, vmax+1)
+    info['fmt'] = ''
+    dates_ = info['val']
     #............................................
     (min_anndef, maj_anndef) = _get_default_annual_spacing(span)
-    major_idx = dates % maj_anndef == 0
-    if aslocator:
-        major = dates[major_idx]
-        minor = dates[(dates % min_anndef == 0)]
-    else:
-        format[major_idx] = '%Y'
+    major_idx = dates_ % maj_anndef == 0
+    info['maj'][major_idx] = True
+    info['min'][(dates_ % min_anndef == 0)] = True
+    if asformatter:
+        info['fmt'][major_idx] = '%Y'
     #............................................
-    if aslocator:
-        return minor, major
-    else:
-        formatted = (format != '')
-        return dict([(d,f) for (d,f) in zip(dates[formatted],format[formatted])])
+    return info
 
 #...............................................................................
 class TimeSeries_DateLocator(Locator):
@@ -490,10 +466,10 @@
 
     def _get_default_locs(self, vmin, vmax):
         "Returns the default locations of ticks."
-        (minor, major) = self.finder(vmin, vmax, self.freq, True)
+        locator = self.finder(vmin, vmax, self.freq, False)
         if self.isminor:
-            return minor
-        return major
+            return numpy.compress(locator['min'], locator['val'])
+        return numpy.compress(locator['maj'], locator['val'])
 
     def __call__(self):
         'Return the locations of the ticks.'
@@ -560,7 +536,13 @@
 
     def _set_default_format(self, vmin, vmax):
         "Returns the default ticks spacing."
-        self.formatdict = self.finder(vmin, vmax, self.freq, False)
+        info = self.finder(vmin, vmax, self.freq, True)
+        if self.isminor:
+            format = numpy.compress(info['min'] & numpy.logical_not(info['maj']),
+                                    info)
+        else:
+            format = numpy.compress(info['maj'], info)
+        self.formatdict = dict([(x,f) for (x,_,_,f) in format])
         return self.formatdict
 
     def set_locs(self, locs):
@@ -571,15 +553,8 @@
             self._set_default_format(locs[0], locs[-1])
     #
     def __call__(self, x, pos=0):
-        if self.isminor:
-            fmt = self.formatdict.pop(x, '')
-            if fmt is not '':
-                retval = Date(self.freq, value=int(x)).strfmt(fmt)
-            else:
-                retval = ''
-        else:
-            retval = ''
-        return retval
+        fmt = self.formatdict.pop(x, '')
+        return Date(self.freq, value=int(x)).strftime(fmt)
 
 
 
@@ -593,12 +568,10 @@
         """
 Accepts the same keywords as a standard subplot, plus a specific `series` keyword.
 
-:Parameters:
-    `fig` : Figure
+*Parameters*:
+    fig : {Figure}
         Base figure.
-
-:Keywords:
-    `series` : TimeSeries
+    series : {TimeSeries}, optional
         Data to plot
 
         """
@@ -719,26 +692,18 @@
     #......................................................
     def tsplot(self,*parms,**kwargs):
         """Plots the data parsed in argument.
-This command accepts the same keywords as `matplotlib.plot`."""
+This command accepts the same keywords as matplotlib.plot."""
 #        parms = tuple(list(parms) + kwargs.pop('series',None))
 #        print "Parameters: %s - %i" % (parms, len(parms))
 #        print "OPtions: %s - %i" % (kwargs, len(kwargs))
         parms = self._check_plot_params(*parms)
         self.legendlabels.append(kwargs.get('label',None))
-        Subplot.plot(self, *parms,**kwargs)
+        plotted = Subplot.plot(self, *parms,**kwargs)
         self.format_dateaxis()
+        return plotted
     #......................................................
-    def format_dateaxis(self,maj_spacing=None, min_spacing=None,
-                        strformat="%Y", rotate=True):
+    def format_dateaxis(self):
         """Pretty-formats the date axis (x-axis).
-
-:Parameters:
-    `major` : Integer *[5]*
-        Major tick locator, in years (major tick every `major` years).
-    `minor` : Integer *[12]*
-        Minor tick locator, in months (minor ticks every `minor` months).
-    `strformat` : String *['%Y']*
-        String format for major ticks ("%Y").
         """
         # Get the locator class .................
         majlocator = TimeSeries_DateLocator(self.freq, dynamic_mode=True,
@@ -754,6 +719,7 @@
                                                 minor_locator=True)
         self.xaxis.set_major_formatter(majformatter)
         self.xaxis.set_minor_formatter(minformatter)
+        pylab.draw_if_interactive()
         #........................................
 #        if rcParams['backend'] == 'PS':
 #            rotate = False
@@ -766,10 +732,10 @@
         """Sets the date limits of the plot to start_date and end_date.
     The dates can be given as timeseries.Date objects, strings or integers.
 
-:Inputs:
-    start_date : var *[None]*
+*Parameters*:
+    start_date : {var}
         Starting date of the plot. If None, the current left limit is used.
-    end_date : var *[None]*
+    end_date : {var}
         Ending date of the plot. If None, the current right limit is used.
         """
         freq = self.freq
@@ -806,23 +772,23 @@
               **kwargs):
     """Adds a second y-axis to a plot.
 
-:Parameters:
-    `fsp` : Subplot *[None]*
-        Subplot to which the secondary y-axis is added. If *None*, the current
-        subplot is selected
-    `position` : String in `('left','right')` *['right']*
-        Position of the new axis.
-    `yscale` : String, in `('log', 'linear')` *[None]*
-        Scale of the new axis. If None, uses the same scale as the first y
-axis
-    `basey` : Integer *[10]*
+*Parameters*:
+    fsp : {Subplot}
+        Subplot to which the secondary y-axis is added. 
+        If None, the current subplot is selected
+    position : {string}
+        Position of the new axis, as either 'left' or 'right'.
+    yscale : {string}
+        Scale of the new axis, as either 'log', 'linear' or None. 
+        If None, uses the same scale as the first y axis
+    basey : {integer}
         Base of the logarithm for the new axis (if needed).
-    `subsy` : sequence *[None]*
+    subsy : {sequence}
         Sequence of the location of the minor ticks;
         None defaults to autosubs, which depend on the number of decades in
-the plot.
+        the plot.
         Eg for base 10, subsy=(1,2,5) will  put minor ticks on 1,2,5,11,12,15,
-21, ....
+        21, ....
         To turn off minor ticking, set subsy=[]
 
     """
@@ -888,10 +854,10 @@
 def tsfigure(series=None, **figargs):
     """Creates a new `TimeSeriesFigure` object.
 
-:Parameters:
-    `series` : TimeSeries object
+*Parameters*:
+    series : {TimeSeries object}
         Input data.
-    `figargs` : Dictionary
+    figargs : {dictionary}
         Figure options [`figsize`, `dpi`, `facecolor`, `edgecolor`, `frameon`].
     """
     figargs.update(FigureClass=TSFigure)

Modified: branches/scipy.scons/scipy/sandbox/timeseries/report.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/report.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/report.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -328,7 +328,7 @@
         if datefmt is None:
             def datefmt_func(date): return str(date)
         else:
-            def datefmt_func(date): return date.strfmt(datefmt)
+            def datefmt_func(date): return date.strftime(datefmt)
 
         if dates is None:
             tseries = ts.align_series(*tseries)

Modified: branches/scipy.scons/scipy/sandbox/timeseries/src/c_dates.c
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/src/c_dates.c	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/src/c_dates.c	2007-11-24 10:53:58 UTC (rev 3583)
@@ -1649,9 +1649,12 @@
 }
 
 static char DateObject_strfmt_doc[] =
+"Deprecated alias for strftime method";
+
+static char DateObject_strftime_doc[] =
 "Returns string representation of Date object according to format specified.\n\n"
-":Parameters:\n"
-"   - fmt : string\n"
+"*Parameters*:\n"
+"   fmt : {str}\n"
 "       Formatting string. Uses the same directives as in the time.strftime\n"
 "       function in the standard Python time module. In addition, a few other\n"
 "       directives are supported:\n"
@@ -1665,7 +1668,7 @@
 "                 the current quarter. This is the same as %Y unless the\n"
 "                 Date is one of the 'qtr-s' frequencies\n";
 static PyObject *
-DateObject_strfmt(DateObject *self, PyObject *args)
+DateObject_strftime(DateObject *self, PyObject *args)
 {
 
     char *orig_fmt_str, *fmt_str;
@@ -1689,7 +1692,7 @@
     long (*toDaily)(long, char, asfreq_info*) = NULL;
     asfreq_info af_info;
 
-    if (!PyArg_ParseTuple(args, "s:strfmt(fmt)", &orig_fmt_str)) return NULL;
+    if (!PyArg_ParseTuple(args, "s:strftime(fmt)", &orig_fmt_str)) return NULL;
 
     toDaily = get_asfreq_func(self->freq, FR_DAY, 0);
     get_asfreq_info(self->freq, FR_DAY, &af_info);
@@ -1821,7 +1824,7 @@
 
     if (string_arg == NULL) { return NULL; }
 
-    retval = DateObject_strfmt(self, string_arg);
+    retval = DateObject_strftime(self, string_arg);
     Py_DECREF(string_arg);
 
     return retval;
@@ -2098,7 +2101,7 @@
 }
 
 static PyObject *
-DateObject_day_of_week(DateObject *self, void *closure) {
+DateObject_weekday(DateObject *self, void *closure) {
     struct date_info dinfo;
     if(DateObject_set_date_info(self, &dinfo) == -1) return NULL;
     return PyInt_FromLong(dinfo.day_of_week);
@@ -2173,8 +2176,11 @@
             "Returns the week.", NULL},
     {"day", (getter)DateObject_day, (setter)DateObject_ReadOnlyErr,
             "Returns the day of month.", NULL},
-    {"day_of_week", (getter)DateObject_day_of_week, (setter)DateObject_ReadOnlyErr,
+    {"weekday", (getter)DateObject_weekday, (setter)DateObject_ReadOnlyErr,
             "Returns the day of week.", NULL},
+	// deprecated alias for weekday property
+    {"day_of_week", (getter)DateObject_weekday, (setter)DateObject_ReadOnlyErr,
+            "Returns the day of week.", NULL},
     {"day_of_year", (getter)DateObject_day_of_year, (setter)DateObject_ReadOnlyErr,
             "Returns the day of year.", NULL},
     {"second", (getter)DateObject_second, (setter)DateObject_ReadOnlyErr,
@@ -2223,7 +2229,10 @@
 static PyMethodDef DateObject_methods[] = {
     {"toordinal", (PyCFunction)DateObject_toordinal, METH_NOARGS,
      DateObject_toordinal_doc},
-    {"strfmt", (PyCFunction)DateObject_strfmt, METH_VARARGS,
+    {"strftime", (PyCFunction)DateObject_strftime, METH_VARARGS,
+     DateObject_strftime_doc},
+    // deprecated alias for strftime
+    {"strfmt", (PyCFunction)DateObject_strftime, METH_VARARGS,
      DateObject_strfmt_doc},
     {"asfreq", (PyCFunction)DateObject_asfreq, METH_VARARGS | METH_KEYWORDS,
      DateObject_asfreq_doc},
@@ -2331,7 +2340,7 @@
 }
 
 PyObject *
-c_dates_thisday(PyObject *self, PyObject *args) {
+c_dates_now(PyObject *self, PyObject *args) {
 
     PyObject *freq, *init_args, *init_kwargs;
     time_t rawtime;
@@ -2340,7 +2349,7 @@
 
     DateObject *secondly_date;
 
-    if (!PyArg_ParseTuple(args, "O:thisday(freq)", &freq)) return NULL;
+    if (!PyArg_ParseTuple(args, "O:now(freq)", &freq)) return NULL;
 
     if ((freq_val = check_freq(freq)) == INT_ERR_CODE) return NULL;
 
@@ -2635,7 +2644,7 @@
             skip_periods = __skip_periods_day(freq);
             break;
         case 'W': //day of week
-            getDateInfo = &DateObject_day_of_week;
+            getDateInfo = &DateObject_weekday;
             skip_periods = __skip_periods_day(freq);
             break;
         case 'I': //week of year

Modified: branches/scipy.scons/scipy/sandbox/timeseries/src/cseries.c
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/src/cseries.c	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/src/cseries.c	2007-11-24 10:53:58 UTC (rev 3583)
@@ -26,11 +26,11 @@
      METH_VARARGS, ""},
 
 
-    {"thisday", (PyCFunction)c_dates_thisday,
+    {"now", (PyCFunction)c_dates_now,
      METH_VARARGS,
-        "Returns today's date, at the given frequency\n\n"
-        ":Parameters:\n"
-        "   - freq : string/int\n"
+        "Returns the current date/time, at the given frequency\n\n"
+        "*Parameters*:\n"
+        "   freq : {freq_spec}\n"
         "       Frequency to convert the Date to. Accepts any valid frequency\n"
         "       specification (string or integer)\n"},
 

Modified: branches/scipy.scons/scipy/sandbox/timeseries/tests/test_dates.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/tests/test_dates.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/tests/test_dates.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -29,7 +29,7 @@
 from timeseries import const as C
 from timeseries.parser import DateFromString, DateTimeFromString
 from timeseries import Date, DateArray,\
-    thisday, today, date_array, date_array_fromlist
+    now, date_array, date_array_fromlist
 from timeseries.cseries import freq_dict
 
 
@@ -122,8 +122,8 @@
         freqs = [x[0] for x in freq_dict.values() if x[0] != 'U']
 
         for f in freqs:
-            today = thisday(f)
-            assert_equal(Date(freq=f, value=today.value), today)
+            _now = now(f)
+            assert_equal(Date(freq=f, value=_now.value), _now)
         print "finished test_consistent_value"
 
     def test_shortcuts(self):
@@ -134,14 +134,14 @@
         assert_equal(Date('D','2007-01'), Date('D', value=732677))
         assert_equal(Date('D',732677), Date('D', value=732677))
         # DateArray shortcuts
-        n = today('M')
+        n = now('M')
         d = date_array(start_date=n, length=3)
         assert_equal(date_array(n,length=3), d)
         assert_equal(date_array(n, n+2), d)
         print "finished test_shortcuts"
 
 class TestDateProperties(NumpyTestCase):
-    "Test properties such as year, month, day_of_week, etc...."
+    "Test properties such as year, month, weekday, etc...."
 
     def __init__(self, *args, **kwds):
         NumpyTestCase.__init__(self, *args, **kwds)
@@ -201,21 +201,21 @@
         assert_equal(b_date.quarter, 1)
         assert_equal(b_date.month, 1)
         assert_equal(b_date.day, 1)
-        assert_equal(b_date.day_of_week, 0)
+        assert_equal(b_date.weekday, 0)
         assert_equal(b_date.day_of_year, 1)
 
         assert_equal(d_date.year, 2007)
         assert_equal(d_date.quarter, 1)
         assert_equal(d_date.month, 1)
         assert_equal(d_date.day, 1)
-        assert_equal(d_date.day_of_week, 0)
+        assert_equal(d_date.weekday, 0)
         assert_equal(d_date.day_of_year, 1)
 
         assert_equal(h_date.year, 2007)
         assert_equal(h_date.quarter, 1)
         assert_equal(h_date.month, 1)
         assert_equal(h_date.day, 1)
-        assert_equal(h_date.day_of_week, 0)
+        assert_equal(h_date.weekday, 0)
         assert_equal(h_date.day_of_year, 1)
         assert_equal(h_date.hour, 0)
 
@@ -223,7 +223,7 @@
         assert_equal(t_date.quarter, 1)
         assert_equal(t_date.month, 1)
         assert_equal(t_date.day, 1)
-        assert_equal(t_date.day_of_week, 0)
+        assert_equal(t_date.weekday, 0)
         assert_equal(t_date.day_of_year, 1)
         assert_equal(t_date.hour, 0)
         assert_equal(t_date.minute, 0)
@@ -232,7 +232,7 @@
         assert_equal(s_date.quarter, 1)
         assert_equal(s_date.month, 1)
         assert_equal(s_date.day, 1)
-        assert_equal(s_date.day_of_week, 0)
+        assert_equal(s_date.weekday, 0)
         assert_equal(s_date.day_of_year, 1)
         assert_equal(s_date.hour, 0)
         assert_equal(s_date.minute, 0)
@@ -483,17 +483,17 @@
             date_W_to_Q = dWrap(Date(freq='Q', year=2007, quarter=1))
             date_W_to_M = dWrap(Date(freq='M', year=2007, month=1))
 
-            if Date(freq='D', year=2007, month=12, day=31).day_of_week == 6:
+            if Date(freq='D', year=2007, month=12, day=31).weekday == 6:
                 date_W_to_A_end_of_year = dWrap(Date(freq='A', year=2007))
             else:
                 date_W_to_A_end_of_year = dWrap(Date(freq='A', year=2008))
 
-            if Date(freq='D', year=2007, month=3, day=31).day_of_week == 6:
+            if Date(freq='D', year=2007, month=3, day=31).weekday == 6:
                 date_W_to_Q_end_of_quarter = dWrap(Date(freq='Q', year=2007, quarter=1))
             else:
                 date_W_to_Q_end_of_quarter = dWrap(Date(freq='Q', year=2007, quarter=2))
 
-            if Date(freq='D', year=2007, month=1, day=31).day_of_week == 6:
+            if Date(freq='D', year=2007, month=1, day=31).weekday == 6:
                 date_W_to_M_end_of_month = dWrap(Date(freq='M', year=2007, month=1))
             else:
                 date_W_to_M_end_of_month = dWrap(Date(freq='M', year=2007, month=2))
@@ -877,7 +877,7 @@
         assert_equal(empty_darray.get_steps(), None)
 
     def test_cachedinfo(self):
-        D = date_array(start_date=thisday('D'), length=5)
+        D = date_array(start_date=now('D'), length=5)
         Dstr = D.tostring()
         assert_equal(D.tostring(), Dstr)
         DL = D[[0,-1]]

Modified: branches/scipy.scons/scipy/sandbox/timeseries/tseries.py
===================================================================
--- branches/scipy.scons/scipy/sandbox/timeseries/tseries.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/sandbox/timeseries/tseries.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -35,7 +35,7 @@
 import dates
 from dates import DateError, InsufficientDateError
 from dates import Date, isDate, DateArray, isDateArray, \
-    date_array, date_array_fromlist, date_array_fromrange, thisday, today, \
+    date_array, date_array_fromlist, date_array_fromrange, now, \
     check_freq, check_freq_str
 
 import cseries
@@ -56,6 +56,7 @@
 'quarter',
 'second','split', 'stack',
 'tofile','tshift',
+'week',
 'year',
 ]
 
@@ -595,9 +596,11 @@
         """Returns the day of month for each date in self._dates."""
         return self._dates.day
     @property
-    def day_of_week(self):
+    def weekday(self):
         """Returns the day of week for each date in self._dates."""
-        return self._dates.day_of_week
+        return self._dates.weekday
+    # deprecated alias for weekday
+    day_of_week = weekday
     @property
     def day_of_year(self):
         """Returns the day of year for each date in self._dates."""
@@ -632,7 +635,7 @@
         return self._dates.week
 
     days = day
-    weekdays = day_of_week
+    weekdays = weekday
     yeardays = day_of_year
     months = month
     quarters = quarter
@@ -873,8 +876,11 @@
         except SystemError:
             return getattr(numpy,self._methodname).__call__(caller, *args, **params)
 #............................
-day_of_week = _frommethod('day_of_week')
+weekday = _frommethod('weekday')
+# deprecated alias for weekday 
+day_of_week = weekday
 day_of_year = _frommethod('day_of_year')
+week = _frommethod('week')
 year = _frommethod('year')
 quarter = _frommethod('quarter')
 month = _frommethod('month')
@@ -1544,8 +1550,8 @@
 saved. Otherwise, only the first occurence of the date is conserved.
 
 Example
->>> a = time_series([1,2,3], start_date=today('D'))
->>> b = time_series([10,20,30], start_date=today('D')+1)
+>>> a = time_series([1,2,3], start_date=now('D'))
+>>> b = time_series([10,20,30], start_date=now('D')+1)
 >>> c = concatenate((a,b))
 >>> c._series
 masked_array(data = [ 1  2  3 30],

Modified: branches/scipy.scons/scipy/signal/signaltools.py
===================================================================
--- branches/scipy.scons/scipy/signal/signaltools.py	2007-11-24 10:49:51 UTC (rev 3582)
+++ branches/scipy.scons/scipy/signal/signaltools.py	2007-11-24 10:53:58 UTC (rev 3583)
@@ -12,7 +12,7 @@
      ravel, size, less_equal, sum, r_, iscomplexobj, take, \
      argsort, allclose, expand_dims, unique, prod, sort, reshape, c_, \
      transpose, dot, any, minimum, maximum, mean, cosh, arccosh, \
-     arccos
+     arccos, concatenate
 import numpy
 from scipy.fftpack import fftn, ifftn, fft
 from scipy.misc import factorial




More information about the Scipy-svn mailing list