diff options
author | pierregm <pierregmcode@gmail.com> | 2010-10-11 23:02:10 +0200 |
---|---|---|
committer | pierregm <pierregmcode@gmail.com> | 2010-10-11 23:02:10 +0200 |
commit | a14dd542532d383610c1b01c5698b137dd058fea (patch) | |
tree | 036f0452ee16fe1b9b74c13e6ad9bb9155310256 /numpy | |
parent | 61d945bdb5c9b2b3329e1b8468b5c7d0596dd9fc (diff) | |
parent | 11ee694744f2552d77652ed929fdc2b4ccca6843 (diff) | |
download | numpy-a14dd542532d383610c1b01c5698b137dd058fea.tar.gz |
merging refs/remotes/origin/master into HEAD
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/setup.py | 7 | ||||
-rw-r--r-- | numpy/core/src/multiarray/arrayobject.c | 28 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert_datatype.c | 16 | ||||
-rw-r--r-- | numpy/core/src/multiarray/descriptor.c | 27 | ||||
-rw-r--r-- | numpy/core/src/scalarmathmodule.c.src | 35 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.c.src | 6 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 1 | ||||
-rw-r--r-- | numpy/core/tests/test_regression.py | 18 | ||||
-rw-r--r-- | numpy/distutils/command/config.py | 16 | ||||
-rw-r--r-- | numpy/distutils/fcompiler/__init__.py | 4 | ||||
-rw-r--r-- | numpy/distutils/fcompiler/pg.py | 23 | ||||
-rw-r--r-- | numpy/f2py/capi_maps.py | 6 | ||||
-rw-r--r-- | numpy/lib/index_tricks.py | 11 | ||||
-rw-r--r-- | numpy/lib/npyio.py | 251 | ||||
-rw-r--r-- | numpy/lib/tests/test_index_tricks.py | 15 | ||||
-rw-r--r-- | numpy/linalg/linalg.py | 35 | ||||
-rw-r--r-- | numpy/linalg/tests/test_linalg.py | 83 |
17 files changed, 423 insertions, 159 deletions
diff --git a/numpy/core/setup.py b/numpy/core/setup.py index ad8d5cb3b..f71ec108a 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -215,10 +215,13 @@ def check_ieee_macros(config): _macros = ["isnan", "isinf", "signbit", "isfinite"] if sys.version_info[:2] >= (2, 6): for f in _macros: - already_declared = config.check_decl(fname2def("decl_%s" % f), + py_symbol = fname2def("decl_%s" % f) + already_declared = config.check_decl(py_symbol, headers=["Python.h", "math.h"]) if already_declared: - pub.append('NPY_%s' % fname2def("decl_%s" % f)) + if config.check_macro_true(py_symbol, + headers=["Python.h", "math.h"]): + pub.append('NPY_%s' % fname2def("decl_%s" % f)) else: macros.append(f) else: diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c index ab1e824be..587e45d26 100644 --- a/numpy/core/src/multiarray/arrayobject.c +++ b/numpy/core/src/multiarray/arrayobject.c @@ -907,16 +907,15 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) array_other = PyArray_FromObject(other, typenum, 0, 0); /* - * If not successful, then return False. This fixes code - * that used to allow equality comparisons between arrays - * and other objects which would give a result of False. + * If not successful, indicate that the items cannot be compared + * this way. */ if ((array_other == NULL) || (array_other == Py_None)) { Py_XDECREF(array_other); PyErr_Clear(); - Py_INCREF(Py_False); - return Py_False; + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } } else { @@ -952,14 +951,14 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) } /* * If the comparison results in NULL, then the - * two array objects can not be compared together so - * return zero + * two array objects can not be compared together; + * indicate that */ Py_DECREF(array_other); if (result == NULL) { PyErr_Clear(); - Py_INCREF(Py_False); - return Py_False; + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } break; case Py_NE: @@ -976,14 +975,13 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) array_other = PyArray_FromObject(other, typenum, 0, 0); /* * If not successful, then objects cannot be - * compared and cannot be equal, therefore, - * return True; + * compared this way */ if ((array_other == NULL) || (array_other == Py_None)) { Py_XDECREF(array_other); PyErr_Clear(); - Py_INCREF(Py_True); - return Py_True; + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } } else { @@ -1021,8 +1019,8 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) Py_DECREF(array_other); if (result == NULL) { PyErr_Clear(); - Py_INCREF(Py_True); - return Py_True; + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } break; case Py_GT: diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c index 37b0e5e18..5cb62b82f 100644 --- a/numpy/core/src/multiarray/convert_datatype.c +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -112,21 +112,25 @@ PyArray_GetCastFunc(PyArray_Descr *descr, int type_num) PyTypeNum_ISNUMBER(type_num) && !PyTypeNum_ISBOOL(type_num)) { PyObject *cls = NULL, *obj = NULL; + int ret; obj = PyImport_ImportModule("numpy.core"); if (obj) { cls = PyObject_GetAttrString(obj, "ComplexWarning"); Py_DECREF(obj); } #if PY_VERSION_HEX >= 0x02050000 - PyErr_WarnEx(cls, - "Casting complex values to real discards the imaginary " - "part", 0); + ret = PyErr_WarnEx(cls, + "Casting complex values to real discards the imaginary " + "part", 0); #else - PyErr_Warn(cls, - "Casting complex values to real discards the imaginary " - "part"); + ret = PyErr_Warn(cls, + "Casting complex values to real discards the imaginary " + "part"); #endif Py_XDECREF(cls); + if (ret < 0) { + return NULL; + } } if (castfunc) { return castfunc; diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c index 74cb7da7a..f635e1c48 100644 --- a/numpy/core/src/multiarray/descriptor.c +++ b/numpy/core/src/multiarray/descriptor.c @@ -1828,6 +1828,7 @@ arraydescr_names_set(PyArray_Descr *self, PyObject *val) int N = 0; int i; PyObject *new_names; + PyObject *new_fields; if (self->names == NULL) { PyErr_SetString(PyExc_ValueError, "there are no fields defined"); @@ -1857,26 +1858,38 @@ arraydescr_names_set(PyArray_Descr *self, PyObject *val) } /* Update dictionary keys in fields */ new_names = PySequence_Tuple(val); + new_fields = PyDict_New(); for (i = 0; i < N; i++) { PyObject *key; PyObject *item; PyObject *new_key; + int ret; key = PyTuple_GET_ITEM(self->names, i); - /* Borrowed reference to item */ + /* Borrowed references to item and new_key */ item = PyDict_GetItem(self->fields, key); - /* Hold on to it even through DelItem */ - Py_INCREF(item); new_key = PyTuple_GET_ITEM(new_names, i); - PyDict_DelItem(self->fields, key); - PyDict_SetItem(self->fields, new_key, item); - /* self->fields now holds reference */ - Py_DECREF(item); + /* Check for duplicates */ + ret = PyDict_Contains(new_fields, new_key); + if (ret != 0) { + if (ret < 0) { + PyErr_Clear(); + } + PyErr_SetString(PyExc_ValueError, "Duplicate field names given."); + Py_DECREF(new_names); + Py_DECREF(new_fields); + return -1; + } + PyDict_SetItem(new_fields, new_key, item); } /* Replace names */ Py_DECREF(self->names); self->names = new_names; + /* Replace fields */ + Py_DECREF(self->fields); + self->fields = new_fields; + return 0; } diff --git a/numpy/core/src/scalarmathmodule.c.src b/numpy/core/src/scalarmathmodule.c.src index f3ee6724e..6261c4c73 100644 --- a/numpy/core/src/scalarmathmodule.c.src +++ b/numpy/core/src/scalarmathmodule.c.src @@ -974,10 +974,11 @@ NONZERO_NAME(@name@_,)(PyObject *a) /**end repeat**/ -static void +static int emit_complexwarning() { static PyObject *cls = NULL; + int ret; if (cls == NULL) { PyObject *mod; mod = PyImport_ImportModule("numpy.core"); @@ -987,13 +988,13 @@ emit_complexwarning() Py_DECREF(mod); } #if PY_VERSION_HEX >= 0x02050000 - PyErr_WarnEx(cls, - "Casting complex values to real discards the imaginary " - "part", 0); + return PyErr_WarnEx(cls, + "Casting complex values to real discards the imaginary " + "part", 0); #else - PyErr_Warn(cls, - "Casting complex values to real discards the imaginary " - "part"); + return PyErr_Warn(cls, + "Casting complex values to real discards the imaginary " + "part"); #endif } @@ -1003,7 +1004,7 @@ emit_complexwarning() * #Name=Byte,UByte,Short,UShort,Int,UInt,Long,ULong,LongLong,ULongLong,Float,Double,LongDouble,CFloat,CDouble,CLongDouble# * #cmplx=0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1# * #sign=(signed,unsigned)*5,,,,,,# - * #unsigntyp=0,1,0,1,0,1,0,1,0,1,1*6# + * #unsigntyp=0,1,0,1,0,1,0,1,0,1,0*6# * #ctype=long*8,PY_LONG_LONG*2,double*6# * #realtyp=0*10,1*6# * #func=(PyLong_FromLong,PyLong_FromUnsignedLong)*4,PyLong_FromLongLong,PyLong_FromUnsignedLongLong,PyLong_FromDouble*6# @@ -1013,6 +1014,7 @@ static PyObject * { #if @cmplx@ @sign@ @ctype@ x= PyArrayScalar_VAL(obj, @Name@).real; + int ret; #else @sign@ @ctype@ x= PyArrayScalar_VAL(obj, @Name@); #endif @@ -1022,15 +1024,14 @@ static PyObject * x = ix; #endif #if @cmplx@ - emit_complexwarning(); + ret = emit_complexwarning(); + if (ret < 0) { + return NULL; + } #endif -/* - * For unsigned type, the (@ctype@) cast just does what is implicitely done by - * the compiler. - */ #if @unsigntyp@ - if(LONG_MIN < (@ctype@)x && (@ctype@)x < LONG_MAX) + if(x < LONG_MAX) return PyInt_FromLong(x); #else if(LONG_MIN < x && x < LONG_MAX) @@ -1052,7 +1053,11 @@ static PyObject * @name@_@which@(PyObject *obj) { #if @cmplx@ - emit_complexwarning(); + int ret; + ret = emit_complexwarning(); + if (ret < 0) { + return NULL; + } return @func@((PyArrayScalar_VAL(obj, @Name@)).real); #else return @func@((PyArrayScalar_VAL(obj, @Name@))); diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index e77da0691..850126482 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -1546,9 +1546,9 @@ C@TYPE@_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) UNARY_LOOP { const @type@ in1r = ((@type@ *)ip1)[0]; const @type@ in1i = ((@type@ *)ip1)[1]; - ((@type@ *)op1)[0] = CGT(in1r, in1i, 0, 0) ? 1 : - (CLT(in1r, in1i, 0, 0) ? -1 : - (CEQ(in1r, in1i, 0, 0) ? 0 : NPY_NAN@C@)); + ((@type@ *)op1)[0] = CGT(in1r, in1i, 0.0, 0.0) ? 1 : + (CLT(in1r, in1i, 0.0, 0.0) ? -1 : + (CEQ(in1r, in1i, 0.0, 0.0) ? 0 : NPY_NAN@C@)); ((@type@ *)op1)[1] = 0; } } diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 45cc1c858..7c38fcf56 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1512,6 +1512,7 @@ class TestWarnings(object): warnings.simplefilter("error", np.ComplexWarning) assert_raises(np.ComplexWarning, x.__setitem__, slice(None), y) + assert_equal(x, [1,2]) warnings.simplefilter("default", np.ComplexWarning) if sys.version_info >= (2, 6): diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 49490c05a..12fe089e6 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -1416,5 +1416,23 @@ class TestRegression(TestCase): x = tp(1+2j) assert_equal(complex(x), 1+2j) + def test_uint_int_conversion(self): + x = 2**64 - 1 + assert_equal(int(np.uint64(x)), x) + + def test_duplicate_field_names_assign(self): + ra = np.fromiter(((i*3, i*2) for i in xrange(10)), dtype='i8,f8') + ra.dtype.names = ('f1', 'f2') + rep = repr(ra) # should not cause a segmentation fault + assert_raises(ValueError, setattr, ra.dtype, 'names', ('f1', 'f1')) + + def test_eq_string_and_object_array(self): + # From e-mail thread "__eq__ with str and object" (Keith Goodman) + a1 = np.array(['a', 'b'], dtype=object) + a2 = np.array(['a', 'c']) + assert_array_equal(a1 == a2, [True, False]) + assert_array_equal(a2 == a1, [True, False]) + + if __name__ == "__main__": run_module_suite() diff --git a/numpy/distutils/command/config.py b/numpy/distutils/command/config.py index dafc7002f..85a86990f 100644 --- a/numpy/distutils/command/config.py +++ b/numpy/distutils/command/config.py @@ -169,6 +169,22 @@ int main() return self.try_compile(body, headers, include_dirs) + def check_macro_true(self, symbol, + headers=None, include_dirs=None): + self._check_compiler() + body = """ +int main() +{ +#if %s +#else +#error false or undefined macro +#endif + ; + return 0; +}""" % (symbol,) + + return self.try_compile(body, headers, include_dirs) + def check_type(self, type_name, headers=None, include_dirs=None, library_dirs=None): """Check type availability. Return True if the type can be compiled, diff --git a/numpy/distutils/fcompiler/__init__.py b/numpy/distutils/fcompiler/__init__.py index 3fd3f22dc..5c9395869 100644 --- a/numpy/distutils/fcompiler/__init__.py +++ b/numpy/distutils/fcompiler/__init__.py @@ -695,14 +695,14 @@ _default_compilers = ( ('cygwin.*', ('gnu','intelv','absoft','compaqv','intelev','gnu95','g95')), ('linux.*', ('gnu','intel','lahey','pg','absoft','nag','vast','compaq', 'intele','intelem','gnu95','g95')), - ('darwin.*', ('nag', 'absoft', 'ibm', 'intel', 'gnu', 'gnu95', 'g95')), + ('darwin.*', ('nag', 'absoft', 'ibm', 'intel', 'gnu', 'gnu95', 'g95', 'pg')), ('sunos.*', ('sun','gnu','gnu95','g95')), ('irix.*', ('mips','gnu','gnu95',)), ('aix.*', ('ibm','gnu','gnu95',)), # os.name mappings ('posix', ('gnu','gnu95',)), ('nt', ('gnu','gnu95',)), - ('mac', ('gnu','gnu95',)), + ('mac', ('gnu','gnu95','pg')), ) fcompiler_class = None diff --git a/numpy/distutils/fcompiler/pg.py b/numpy/distutils/fcompiler/pg.py index 60c7f4e4b..a34669c36 100644 --- a/numpy/distutils/fcompiler/pg.py +++ b/numpy/distutils/fcompiler/pg.py @@ -2,6 +2,7 @@ # http://www.pgroup.com from numpy.distutils.fcompiler import FCompiler +from sys import platform compilers = ['PGroupFCompiler'] @@ -11,7 +12,19 @@ class PGroupFCompiler(FCompiler): description = 'Portland Group Fortran Compiler' version_pattern = r'\s*pg(f77|f90|hpf) (?P<version>[\d.-]+).*' - executables = { + if platform == 'darwin': + executables = { + 'version_cmd' : ["<F77>", "-V 2>/dev/null"], + 'compiler_f77' : ["pgf77", "-dynamiclib"], + 'compiler_fix' : ["pgf90", "-Mfixed", "-dynamiclib"], + 'compiler_f90' : ["pgf90", "-dynamiclib"], + 'linker_so' : ["libtool"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + pic_flags = [''] + else: + executables = { 'version_cmd' : ["<F77>", "-V 2>/dev/null"], 'compiler_f77' : ["pgf77"], 'compiler_fix' : ["pgf90", "-Mfixed"], @@ -20,7 +33,9 @@ class PGroupFCompiler(FCompiler): 'archiver' : ["ar", "-cr"], 'ranlib' : ["ranlib"] } - pic_flags = ['-fpic'] + pic_flags = ['-fpic'] + + module_dir_switch = '-module ' module_include_switch = '-I' @@ -31,6 +46,10 @@ class PGroupFCompiler(FCompiler): return ['-fast'] def get_flags_debug(self): return ['-g'] + + if platform == 'darwin': + def get_flags_linker_so(self): + return ["-dynamic", '-undefined', 'dynamic_lookup'] if __name__ == '__main__': from distutils import log diff --git a/numpy/f2py/capi_maps.py b/numpy/f2py/capi_maps.py index cba98af2b..c10e3ee84 100644 --- a/numpy/f2py/capi_maps.py +++ b/numpy/f2py/capi_maps.py @@ -643,8 +643,10 @@ def modsign2map(m): else: ret['interface_usercode'] = '' ret['pymethoddef'] = getpymethoddef(m) or '' - ret['coutput'] = m['coutput'] - ret['f2py_wrapper_output'] = m['f2py_wrapper_output'] + if 'coutput' in m: + ret['coutput'] = m['coutput'] + if 'f2py_wrapper_output' in m: + ret['f2py_wrapper_output'] = m['f2py_wrapper_output'] return ret def cb_sign2map(a,var,index=None): diff --git a/numpy/lib/index_tricks.py b/numpy/lib/index_tricks.py index eb1ab22e9..264ebaad0 100644 --- a/numpy/lib/index_tricks.py +++ b/numpy/lib/index_tricks.py @@ -700,24 +700,15 @@ class IndexExpression(object): array([2, 4]) """ - maxint = sys.maxint def __init__(self, maketuple): self.maketuple = maketuple def __getitem__(self, item): - if self.maketuple and type(item) != type(()): + if self.maketuple and type(item) != tuple: return (item,) else: return item - def __len__(self): - return self.maxint - - def __getslice__(self, start, stop): - if stop == self.maxint: - stop = None - return self[start:stop:None] - index_exp = IndexExpression(maketuple=True) s_ = IndexExpression(maketuple=False) diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py index 8c4a1a823..2668357bc 100644 --- a/numpy/lib/npyio.py +++ b/numpy/lib/npyio.py @@ -1,6 +1,6 @@ __all__ = ['savetxt', 'loadtxt', 'genfromtxt', 'ndfromtxt', 'mafromtxt', - 'recfromtxt', 'recfromcsv', 'load', 'loads', 'save', 'savez', - 'packbits', 'unpackbits', 'fromregex', 'DataSource'] + 'recfromtxt', 'recfromcsv', 'load', 'loads', 'save', 'savez', + 'savez_compressed', 'packbits', 'unpackbits', 'fromregex', 'DataSource'] import numpy as np import format @@ -108,7 +108,11 @@ class BagObj(object): except KeyError: raise AttributeError, key - +def zipfile_factory(*args, **kwargs): + import zipfile + if sys.version_info >= (2, 5): + kwargs['allowZip64'] = True + return zipfile.ZipFile(*args, **kwargs) class NpzFile(object): """ @@ -142,6 +146,9 @@ class NpzFile(object): fid : file or str The zipped archive to open. This is either a file-like object or a string containing the path to the archive. + own_fid : bool, optional + Whether NpzFile should close the file handle. + Requires that `fid` is a file-like object. Examples -------- @@ -163,11 +170,10 @@ class NpzFile(object): array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) """ - def __init__(self, fid): + def __init__(self, fid, own_fid=False): # Import is postponed to here since zipfile depends on gzip, an optional # component of the so-called standard library. - import zipfile - _zip = zipfile.ZipFile(fid) + _zip = zipfile_factory(fid) self._files = _zip.namelist() self.files = [] for x in self._files: @@ -177,6 +183,25 @@ class NpzFile(object): self.files.append(x) self.zip = _zip self.f = BagObj(self) + if own_fid: + self.fid = fid + else: + self.fid = None + + def close(self): + """ + Close the file. + + """ + if self.zip is not None: + self.zip.close() + self.zip = None + if self.fid is not None: + self.fid.close() + self.fid = None + + def __del__(self): + self.close() def __getitem__(self, key): # FIXME: This seems like it will copy strings around @@ -293,31 +318,39 @@ def load(file, mmap_mode=None): """ import gzip + own_fid = False if isinstance(file, basestring): fid = open(file, "rb") + own_fid = True elif isinstance(file, gzip.GzipFile): fid = seek_gzip_factory(file) + own_fid = True else: fid = file - # Code to distinguish from NumPy binary files and pickles. - _ZIP_PREFIX = asbytes('PK\x03\x04') - N = len(format.MAGIC_PREFIX) - magic = fid.read(N) - fid.seek(-N, 1) # back-up - if magic.startswith(_ZIP_PREFIX): # zip-file (assume .npz) - return NpzFile(fid) - elif magic == format.MAGIC_PREFIX: # .npy file - if mmap_mode: - return format.open_memmap(file, mode=mmap_mode) - else: - return format.read_array(fid) - else: # Try a pickle - try: - return _cload(fid) - except: - raise IOError, \ - "Failed to interpret file %s as a pickle" % repr(file) + try: + # Code to distinguish from NumPy binary files and pickles. + _ZIP_PREFIX = asbytes('PK\x03\x04') + N = len(format.MAGIC_PREFIX) + magic = fid.read(N) + fid.seek(-N, 1) # back-up + if magic.startswith(_ZIP_PREFIX): # zip-file (assume .npz) + own_fid = False + return NpzFile(fid, own_fid=True) + elif magic == format.MAGIC_PREFIX: # .npy file + if mmap_mode: + return format.open_memmap(file, mode=mmap_mode) + else: + return format.read_array(fid) + else: # Try a pickle + try: + return _cload(fid) + except: + raise IOError, \ + "Failed to interpret file %s as a pickle" % repr(file) + finally: + if own_fid: + fid.close() def save(file, arr): """ @@ -335,7 +368,7 @@ def save(file, arr): See Also -------- - savez : Save several arrays into a ``.npz`` compressed archive + savez : Save several arrays into a ``.npz`` archive savetxt, load Notes @@ -355,19 +388,25 @@ def save(file, arr): array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) """ + own_fid = False if isinstance(file, basestring): if not file.endswith('.npy'): file = file + '.npy' fid = open(file, "wb") + own_fid = True else: fid = file - arr = np.asanyarray(arr) - format.write_array(fid, arr) + try: + arr = np.asanyarray(arr) + format.write_array(fid, arr) + finally: + if own_fid: + fid.close() def savez(file, *args, **kwds): """ - Save several arrays into a single, archive file in ``.npz`` format. + Save several arrays into a single file in uncompressed ``.npz`` format. If arguments are passed in with no keywords, the corresponding variable names, in the .npz file, are 'arr_0', 'arr_1', etc. If keyword arguments @@ -380,12 +419,12 @@ def savez(file, *args, **kwds): Either the file name (string) or an open file (file-like object) where the data will be saved. If file is a string, the ``.npz`` extension will be appended to the file name if it is not already there. - \\*args : Arguments, optional + *args : Arguments, optional Arrays to save to the file. Since it is not possible for Python to know the names of the arrays outside `savez`, the arrays will be saved with names "arr_0", "arr_1", and so on. These arguments can be any expression. - \\*\\*kwds : Keyword arguments, optional + **kwds : Keyword arguments, optional Arrays to save to the file. Arrays will be saved in the file with the keyword names. @@ -417,7 +456,7 @@ def savez(file, *args, **kwds): >>> x = np.arange(10) >>> y = np.sin(x) - Using `savez` with \\*args, the arrays are saved with default names. + Using `savez` with *args, the arrays are saved with default names. >>> np.savez(outfile, x, y) >>> outfile.seek(0) # Only needed here to simulate closing & reopening file @@ -427,7 +466,7 @@ def savez(file, *args, **kwds): >>> npzfile['arr_0'] array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) - Using `savez` with \\*\\*kwds, the arrays are saved with the keyword names. + Using `savez` with **kwds, the arrays are saved with the keyword names. >>> outfile = TemporaryFile() >>> np.savez(outfile, x=x, y=y) @@ -438,8 +477,38 @@ def savez(file, *args, **kwds): >>> npzfile['x'] array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + See Also + -------- + numpy.savez_compressed : Save several arrays into a compressed .npz file format + + """ + _savez(file, args, kwds, False) + +def savez_compressed(file, *args, **kwds): """ + Save several arrays into a single file in compressed ``.npz`` format. + + If keyword arguments are given, then filenames are taken from the keywords. + If arguments are passed in with no keywords, then stored file names are + arr_0, arr_1, etc. + Parameters + ---------- + file : string + File name of .npz file. + args : Arguments + Function arguments. + kwds : Keyword arguments + Keywords. + + See Also + -------- + numpy.savez : Save several arrays into an uncompressed .npz file format + + """ + _savez(file, args, kwds, True) + +def _savez(file, args, kwds, compress): # Import is postponed to here since zipfile depends on gzip, an optional # component of the so-called standard library. import zipfile @@ -457,7 +526,12 @@ def savez(file, *args, **kwds): raise ValueError, "Cannot use un-named variables and keyword %s" % key namedict[key] = val - zip = zipfile.ZipFile(file, mode="w") + if compress: + compression = zipfile.ZIP_DEFLATED + else: + compression = zipfile.ZIP_STORED + + zip = zipfile_factory(file, mode="w", compression=compression) # Stage arrays in a temporary file on disk, before writing to zip. fd, tmpfile = tempfile.mkstemp(suffix='-numpy.npy') @@ -586,9 +660,9 @@ def loadtxt(fname, dtype=float, comments='#', delimiter=None, if usecols is not None: usecols = list(usecols) - isstring = False + own_fh = False if _is_string_like(fname): - isstring = True + own_fh = True if fname.endswith('.gz'): import gzip fh = seek_gzip_factory(fname) @@ -676,7 +750,7 @@ def loadtxt(fname, dtype=float, comments='#', delimiter=None, # Convert each value according to its column and store X.append(tuple([conv(val) for (conv, val) in zip(converters, vals)])) finally: - if isstring: + if own_fh: fh.close() if len(dtype_types) > 1: @@ -798,7 +872,9 @@ def savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n'): fmt = asstr(fmt) delimiter = asstr(delimiter) + own_fh = False if _is_string_like(fname): + own_fh = True if fname.endswith('.gz'): import gzip fh = gzip.open(fname, 'wb') @@ -812,39 +888,43 @@ def savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n'): else: raise ValueError('fname must be a string or file handle') - X = np.asarray(X) + try: + X = np.asarray(X) - # Handle 1-dimensional arrays - if X.ndim == 1: - # Common case -- 1d array of numbers - if X.dtype.names is None: - X = np.atleast_2d(X).T - ncol = 1 + # Handle 1-dimensional arrays + if X.ndim == 1: + # Common case -- 1d array of numbers + if X.dtype.names is None: + X = np.atleast_2d(X).T + ncol = 1 - # Complex dtype -- each field indicates a separate column - else: - ncol = len(X.dtype.descr) - else: - ncol = X.shape[1] - - # `fmt` can be a string with multiple insertion points or a list of formats. - # E.g. '%10.5f\t%10d' or ('%10.5f', '$10d') - if type(fmt) in (list, tuple): - if len(fmt) != ncol: - raise AttributeError('fmt has wrong shape. %s' % str(fmt)) - format = asstr(delimiter).join(map(asstr, fmt)) - elif type(fmt) is str: - if fmt.count('%') == 1: - fmt = [fmt, ]*ncol - format = delimiter.join(fmt) - elif fmt.count('%') != ncol: - raise AttributeError('fmt has wrong number of %% formats. %s' - % fmt) + # Complex dtype -- each field indicates a separate column + else: + ncol = len(X.dtype.descr) else: - format = fmt + ncol = X.shape[1] + + # `fmt` can be a string with multiple insertion points or a + # list of formats. E.g. '%10.5f\t%10d' or ('%10.5f', '$10d') + if type(fmt) in (list, tuple): + if len(fmt) != ncol: + raise AttributeError('fmt has wrong shape. %s' % str(fmt)) + format = asstr(delimiter).join(map(asstr, fmt)) + elif type(fmt) is str: + if fmt.count('%') == 1: + fmt = [fmt, ]*ncol + format = delimiter.join(fmt) + elif fmt.count('%') != ncol: + raise AttributeError('fmt has wrong number of %% formats. %s' + % fmt) + else: + format = fmt - for row in X: - fh.write(asbytes(format % tuple(row) + newline)) + for row in X: + fh.write(asbytes(format % tuple(row) + newline)) + finally: + if own_fh: + fh.close() import re def fromregex(file, regexp, dtype): @@ -902,25 +982,32 @@ def fromregex(file, regexp, dtype): array([1312, 1534, 444], dtype=int64) """ + own_fh = False if not hasattr(file, "read"): file = open(file, 'rb') - if not hasattr(regexp, 'match'): - regexp = re.compile(asbytes(regexp)) - if not isinstance(dtype, np.dtype): - dtype = np.dtype(dtype) + own_fh = True - seq = regexp.findall(file.read()) - if seq and not isinstance(seq[0], tuple): - # Only one group is in the regexp. - # Create the new array as a single data-type and then - # re-interpret as a single-field structured array. - newdtype = np.dtype(dtype[dtype.names[0]]) - output = np.array(seq, dtype=newdtype) - output.dtype = dtype - else: - output = np.array(seq, dtype=dtype) + try: + if not hasattr(regexp, 'match'): + regexp = re.compile(asbytes(regexp)) + if not isinstance(dtype, np.dtype): + dtype = np.dtype(dtype) + + seq = regexp.findall(file.read()) + if seq and not isinstance(seq[0], tuple): + # Only one group is in the regexp. + # Create the new array as a single data-type and then + # re-interpret as a single-field structured array. + newdtype = np.dtype(dtype[dtype.names[0]]) + output = np.array(seq, dtype=newdtype) + output.dtype = dtype + else: + output = np.array(seq, dtype=dtype) - return output + return output + finally: + if own_fh: + fh.close() @@ -1092,8 +1179,10 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None, raise TypeError(errmsg % type(user_converters)) # Initialize the filehandle, the LineSplitter and the NameValidator + own_fhd = False if isinstance(fname, basestring): fhd = np.lib._datasource.open(fname, 'U') + own_fhd = True elif not hasattr(fname, 'read'): raise TypeError("The input should be a string or a filehandle. "\ "(got %s instead)" % type(fname)) @@ -1354,6 +1443,8 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None, append_to_masks(tuple([v.strip() in m for (v, m) in zip(values, missing_values)])) + if own_fhd: + fhd.close() # Upgrade the converters (if needed) if dtype is None: diff --git a/numpy/lib/tests/test_index_tricks.py b/numpy/lib/tests/test_index_tricks.py index 3307cef3e..c17ee5d6a 100644 --- a/numpy/lib/tests/test_index_tricks.py +++ b/numpy/lib/tests/test_index_tricks.py @@ -2,7 +2,7 @@ from numpy.testing import * import numpy as np from numpy import ( array, ones, r_, mgrid, unravel_index, zeros, where, ndenumerate, fill_diagonal, diag_indices, - diag_indices_from ) + diag_indices_from, s_, index_exp ) class TestUnravelIndex(TestCase): def test_basic(self): @@ -77,6 +77,19 @@ class TestNdenumerate(TestCase): [((0,0), 1), ((0,1), 2), ((1,0), 3), ((1,1), 4)]) +class TestIndexExpression(TestCase): + def test_regression_1(self): + # ticket #1196 + a = np.arange(2) + assert_equal(a[:-1], a[s_[:-1]]) + assert_equal(a[:-1], a[index_exp[:-1]]) + + def test_simple_1(self): + a = np.random.rand(4,5,6) + + assert_equal(a[:,:3,[1,2]], a[index_exp[:,:3,[1,2]]]) + assert_equal(a[:,:3,[1,2]], a[s_[:,:3,[1,2]]]) + def test_fill_diagonal(): a = zeros((3, 3),int) fill_diagonal(a, 5) diff --git a/numpy/linalg/linalg.py b/numpy/linalg/linalg.py index eb8c8379a..c044176cf 100644 --- a/numpy/linalg/linalg.py +++ b/numpy/linalg/linalg.py @@ -1680,12 +1680,13 @@ def lstsq(a, b, rcond=-1): """ Return the least-squares solution to a linear matrix equation. - Solves the equation `a x = b` by computing a vector `x` that minimizes - the norm `|| b - a x ||`. The equation may be under-, well-, or over- - determined (i.e., the number of linearly independent rows of `a` can be - less than, equal to, or greater than its number of linearly independent - columns). If `a` is square and of full rank, then `x` (but for round-off - error) is the "exact" solution of the equation. + Solves the equation `a x = b` by computing a vector `x` that + minimizes the Euclidean 2-norm `|| b - a x ||^2`. The equation may + be under-, well-, or over- determined (i.e., the number of + linearly independent rows of `a` can be less than, equal to, or + greater than its number of linearly independent columns). If `a` + is square and of full rank, then `x` (but for round-off error) is + the "exact" solution of the equation. Parameters ---------- @@ -1706,7 +1707,7 @@ def lstsq(a, b, rcond=-1): Least-squares solution. The shape of `x` depends on the shape of `b`. residues : ndarray, shape (), (1,), or (K,) - Sums of residues; squared Euclidean norm for each column in + Sums of residues; squared Euclidean 2-norm for each column in ``b - a*x``. If the rank of `a` is < N or > M, this is an empty array. If `b` is 1-dimensional, this is a (1,) shape array. @@ -1772,6 +1773,7 @@ def lstsq(a, b, rcond=-1): if m != b.shape[0]: raise LinAlgError, 'Incompatible dimensions' t, result_t = _commonType(a, b) + result_real_t = _realType(result_t) real_t = _linalgRealType(t) bstar = zeros((ldb, n_rhs), t) bstar[:b.shape[0],:n_rhs] = b.copy() @@ -1811,16 +1813,27 @@ def lstsq(a, b, rcond=-1): 0, work, lwork, iwork, 0) if results['info'] > 0: raise LinAlgError, 'SVD did not converge in Linear Least Squares' - resids = array([], t) + resids = array([], result_real_t) if is_1d: x = array(ravel(bstar)[:n], dtype=result_t, copy=True) if results['rank'] == n and m > n: - resids = array([sum((ravel(bstar)[n:])**2)], dtype=result_t) + if isComplexType(t): + resids = array([sum(abs(ravel(bstar)[n:])**2)], + dtype=result_real_t) + else: + resids = array([sum((ravel(bstar)[n:])**2)], + dtype=result_real_t) else: x = array(transpose(bstar)[:n,:], dtype=result_t, copy=True) if results['rank'] == n and m > n: - resids = sum((transpose(bstar)[n:,:])**2, axis=0).astype(result_t) - st = s[:min(n, m)].copy().astype(_realType(result_t)) + if isComplexType(t): + resids = sum(abs(transpose(bstar)[n:,:])**2, axis=0).astype( + result_real_t) + else: + resids = sum((transpose(bstar)[n:,:])**2, axis=0).astype( + result_real_t) + + st = s[:min(n, m)].copy().astype(result_real_t) return wrap(x), wrap(resids), results['rank'], st def norm(x, ord=None): diff --git a/numpy/linalg/tests/test_linalg.py b/numpy/linalg/tests/test_linalg.py index 3a9584dd6..a672ed08a 100644 --- a/numpy/linalg/tests/test_linalg.py +++ b/numpy/linalg/tests/test_linalg.py @@ -33,6 +33,11 @@ class LinalgTestCase: b = array([2., 1.], dtype=double) self.do(a, b) + def test_double_2(self): + a = array([[1.,2.], [3.,4.]], dtype=double) + b = array([[2., 1., 4.], [3., 4., 6.]], dtype=double) + self.do(a, b) + def test_csingle(self): a = array([[1.+2j,2+3j], [3+4j,4+5j]], dtype=csingle) b = array([2.+1j, 1.+2j], dtype=csingle) @@ -43,6 +48,11 @@ class LinalgTestCase: b = array([2.+1j, 1.+2j], dtype=cdouble) self.do(a, b) + def test_cdouble_2(self): + a = array([[1.+2j,2+3j], [3+4j,4+5j]], dtype=cdouble) + b = array([[2.+1j, 1.+2j, 1+3j], [1-2j, 1-3j, 1-6j]], dtype=cdouble) + self.do(a, b) + def test_empty(self): a = atleast_2d(array([], dtype = double)) b = atleast_2d(array([], dtype = double)) @@ -70,6 +80,58 @@ class LinalgTestCase: self.do(a, b) +class LinalgNonsquareTestCase: + def test_single_nsq_1(self): + a = array([[1.,2.,3.], [3.,4.,6.]], dtype=single) + b = array([2., 1.], dtype=single) + self.do(a, b) + + def test_single_nsq_2(self): + a = array([[1.,2.], [3.,4.], [5.,6.]], dtype=single) + b = array([2., 1., 3.], dtype=single) + self.do(a, b) + + def test_double_nsq_1(self): + a = array([[1.,2.,3.], [3.,4.,6.]], dtype=double) + b = array([2., 1.], dtype=double) + self.do(a, b) + + def test_double_nsq_2(self): + a = array([[1.,2.], [3.,4.], [5.,6.]], dtype=double) + b = array([2., 1., 3.], dtype=double) + self.do(a, b) + + def test_csingle_nsq_1(self): + a = array([[1.+1j,2.+2j,3.-3j], [3.-5j,4.+9j,6.+2j]], dtype=csingle) + b = array([2.+1j, 1.+2j], dtype=csingle) + self.do(a, b) + + def test_csingle_nsq_2(self): + a = array([[1.+1j,2.+2j], [3.-3j,4.-9j], [5.-4j,6.+8j]], dtype=csingle) + b = array([2.+1j, 1.+2j, 3.-3j], dtype=csingle) + self.do(a, b) + + def test_cdouble_nsq_1(self): + a = array([[1.+1j,2.+2j,3.-3j], [3.-5j,4.+9j,6.+2j]], dtype=cdouble) + b = array([2.+1j, 1.+2j], dtype=cdouble) + self.do(a, b) + + def test_cdouble_nsq_2(self): + a = array([[1.+1j,2.+2j], [3.-3j,4.-9j], [5.-4j,6.+8j]], dtype=cdouble) + b = array([2.+1j, 1.+2j, 3.-3j], dtype=cdouble) + self.do(a, b) + + def test_cdouble_nsq_1_2(self): + a = array([[1.+1j,2.+2j,3.-3j], [3.-5j,4.+9j,6.+2j]], dtype=cdouble) + b = array([[2.+1j, 1.+2j], [1-1j, 2-2j]], dtype=cdouble) + self.do(a, b) + + def test_cdouble_nsq_2_2(self): + a = array([[1.+1j,2.+2j], [3.-3j,4.-9j], [5.-4j,6.+8j]], dtype=cdouble) + b = array([[2.+1j, 1.+2j], [1-1j, 2-2j], [1-1j, 2-2j]], dtype=cdouble) + self.do(a, b) + + class TestSolve(LinalgTestCase, TestCase): def do(self, a, b): x = linalg.solve(a, b) @@ -153,13 +215,28 @@ class TestDet(LinalgTestCase, TestCase): assert_equal(type(linalg.slogdet([[0.0j]])[0]), cdouble) assert_equal(type(linalg.slogdet([[0.0j]])[1]), double) -class TestLstsq(LinalgTestCase, TestCase): +class TestLstsq(LinalgTestCase, LinalgNonsquareTestCase, TestCase): def do(self, a, b): + arr = np.asarray(a) + m, n = arr.shape u, s, vt = linalg.svd(a, 0) x, residuals, rank, sv = linalg.lstsq(a, b) - assert_almost_equal(b, dot(a, x)) - assert_equal(rank, asarray(a).shape[0]) + if m <= n: + assert_almost_equal(b, dot(a, x)) + assert_equal(rank, m) + else: + assert_equal(rank, n) assert_almost_equal(sv, sv.__array_wrap__(s)) + if rank == n and m > n: + expect_resids = (np.asarray(abs(np.dot(a, x) - b))**2).sum(axis=0) + expect_resids = np.asarray(expect_resids) + if len(np.asarray(b).shape) == 1: + expect_resids.shape = (1,) + assert_equal(residuals.shape, expect_resids.shape) + else: + expect_resids = type(x)([]) + assert_almost_equal(residuals, expect_resids) + assert_(np.issubdtype(residuals.dtype, np.floating)) assert imply(isinstance(b, matrix), isinstance(x, matrix)) assert imply(isinstance(b, matrix), isinstance(residuals, matrix)) |