| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996 | 
							- """
 
-   Matrix Market I/O in Python.
 
-   See http://math.nist.gov/MatrixMarket/formats.html
 
-   for information about the Matrix Market format.
 
- """
 
- #
 
- # Author: Pearu Peterson <pearu@cens.ioc.ee>
 
- # Created: October, 2004
 
- #
 
- # References:
 
- #  http://math.nist.gov/MatrixMarket/
 
- #
 
- import os
 
- import numpy as np
 
- from numpy import (asarray, real, imag, conj, zeros, ndarray, concatenate,
 
-                    ones, can_cast)
 
- from scipy.sparse import coo_matrix, isspmatrix
 
- __all__ = ['mminfo', 'mmread', 'mmwrite', 'MMFile']
 
- # -----------------------------------------------------------------------------
 
- def asstr(s):
 
-     if isinstance(s, bytes):
 
-         return s.decode('latin1')
 
-     return str(s)
 
- def mminfo(source):
 
-     """
 
-     Return size and storage parameters from Matrix Market file-like 'source'.
 
-     Parameters
 
-     ----------
 
-     source : str or file-like
 
-         Matrix Market filename (extension .mtx) or open file-like object
 
-     Returns
 
-     -------
 
-     rows : int
 
-         Number of matrix rows.
 
-     cols : int
 
-         Number of matrix columns.
 
-     entries : int
 
-         Number of non-zero entries of a sparse matrix
 
-         or rows*cols for a dense matrix.
 
-     format : str
 
-         Either 'coordinate' or 'array'.
 
-     field : str
 
-         Either 'real', 'complex', 'pattern', or 'integer'.
 
-     symmetry : str
 
-         Either 'general', 'symmetric', 'skew-symmetric', or 'hermitian'.
 
-     Examples
 
-     --------
 
-     >>> from io import StringIO
 
-     >>> from scipy.io import mminfo
 
-     >>> text = '''%%MatrixMarket matrix coordinate real general
 
-     ...  5 5 7
 
-     ...  2 3 1.0
 
-     ...  3 4 2.0
 
-     ...  3 5 3.0
 
-     ...  4 1 4.0
 
-     ...  4 2 5.0
 
-     ...  4 3 6.0
 
-     ...  4 4 7.0
 
-     ... '''
 
-     ``mminfo(source)`` returns the number of rows, number of columns,
 
-     format, field type and symmetry attribute of the source file.
 
-     >>> mminfo(StringIO(text))
 
-     (5, 5, 7, 'coordinate', 'real', 'general')
 
-     """
 
-     return MMFile.info(source)
 
- # -----------------------------------------------------------------------------
 
- def mmread(source):
 
-     """
 
-     Reads the contents of a Matrix Market file-like 'source' into a matrix.
 
-     Parameters
 
-     ----------
 
-     source : str or file-like
 
-         Matrix Market filename (extensions .mtx, .mtz.gz)
 
-         or open file-like object.
 
-     Returns
 
-     -------
 
-     a : ndarray or coo_matrix
 
-         Dense or sparse matrix depending on the matrix format in the
 
-         Matrix Market file.
 
-     Examples
 
-     --------
 
-     >>> from io import StringIO
 
-     >>> from scipy.io import mmread
 
-     >>> text = '''%%MatrixMarket matrix coordinate real general
 
-     ...  5 5 7
 
-     ...  2 3 1.0
 
-     ...  3 4 2.0
 
-     ...  3 5 3.0
 
-     ...  4 1 4.0
 
-     ...  4 2 5.0
 
-     ...  4 3 6.0
 
-     ...  4 4 7.0
 
-     ... '''
 
-     ``mmread(source)`` returns the data as sparse matrix in COO format.
 
-     >>> m = mmread(StringIO(text))
 
-     >>> m
 
-     <5x5 sparse matrix of type '<class 'numpy.float64'>'
 
-     with 7 stored elements in COOrdinate format>
 
-     >>> m.A
 
-     array([[0., 0., 0., 0., 0.],
 
-            [0., 0., 1., 0., 0.],
 
-            [0., 0., 0., 2., 3.],
 
-            [4., 5., 6., 7., 0.],
 
-            [0., 0., 0., 0., 0.]])
 
-     """
 
-     return MMFile().read(source)
 
- # -----------------------------------------------------------------------------
 
- def mmwrite(target, a, comment='', field=None, precision=None, symmetry=None):
 
-     r"""
 
-     Writes the sparse or dense array `a` to Matrix Market file-like `target`.
 
-     Parameters
 
-     ----------
 
-     target : str or file-like
 
-         Matrix Market filename (extension .mtx) or open file-like object.
 
-     a : array like
 
-         Sparse or dense 2-D array.
 
-     comment : str, optional
 
-         Comments to be prepended to the Matrix Market file.
 
-     field : None or str, optional
 
-         Either 'real', 'complex', 'pattern', or 'integer'.
 
-     precision : None or int, optional
 
-         Number of digits to display for real or complex values.
 
-     symmetry : None or str, optional
 
-         Either 'general', 'symmetric', 'skew-symmetric', or 'hermitian'.
 
-         If symmetry is None the symmetry type of 'a' is determined by its
 
-         values.
 
-     Returns
 
-     -------
 
-     None
 
-     Examples
 
-     --------
 
-     >>> from io import BytesIO
 
-     >>> import numpy as np
 
-     >>> from scipy.sparse import coo_matrix
 
-     >>> from scipy.io import mmwrite
 
-     Write a small NumPy array to a matrix market file.  The file will be
 
-     written in the ``'array'`` format.
 
-     >>> a = np.array([[1.0, 0, 0, 0], [0, 2.5, 0, 6.25]])
 
-     >>> target = BytesIO()
 
-     >>> mmwrite(target, a)
 
-     >>> print(target.getvalue().decode('latin1'))
 
-     %%MatrixMarket matrix array real general
 
-     %
 
-     2 4
 
-     1.0000000000000000e+00
 
-     0.0000000000000000e+00
 
-     0.0000000000000000e+00
 
-     2.5000000000000000e+00
 
-     0.0000000000000000e+00
 
-     0.0000000000000000e+00
 
-     0.0000000000000000e+00
 
-     6.2500000000000000e+00
 
-     Add a comment to the output file, and set the precision to 3.
 
-     >>> target = BytesIO()
 
-     >>> mmwrite(target, a, comment='\n Some test data.\n', precision=3)
 
-     >>> print(target.getvalue().decode('latin1'))
 
-     %%MatrixMarket matrix array real general
 
-     %
 
-     % Some test data.
 
-     %
 
-     2 4
 
-     1.000e+00
 
-     0.000e+00
 
-     0.000e+00
 
-     2.500e+00
 
-     0.000e+00
 
-     0.000e+00
 
-     0.000e+00
 
-     6.250e+00
 
-     Convert to a sparse matrix before calling ``mmwrite``.  This will
 
-     result in the output format being ``'coordinate'`` rather than
 
-     ``'array'``.
 
-     >>> target = BytesIO()
 
-     >>> mmwrite(target, coo_matrix(a), precision=3)
 
-     >>> print(target.getvalue().decode('latin1'))
 
-     %%MatrixMarket matrix coordinate real general
 
-     %
 
-     2 4 3
 
-     1 1 1.00e+00
 
-     2 2 2.50e+00
 
-     2 4 6.25e+00
 
-     Write a complex Hermitian array to a matrix market file.  Note that
 
-     only six values are actually written to the file; the other values
 
-     are implied by the symmetry.
 
-     >>> z = np.array([[3, 1+2j, 4-3j], [1-2j, 1, -5j], [4+3j, 5j, 2.5]])
 
-     >>> z
 
-     array([[ 3. +0.j,  1. +2.j,  4. -3.j],
 
-            [ 1. -2.j,  1. +0.j, -0. -5.j],
 
-            [ 4. +3.j,  0. +5.j,  2.5+0.j]])
 
-     >>> target = BytesIO()
 
-     >>> mmwrite(target, z, precision=2)
 
-     >>> print(target.getvalue().decode('latin1'))
 
-     %%MatrixMarket matrix array complex hermitian
 
-     %
 
-     3 3
 
-     3.00e+00 0.00e+00
 
-     1.00e+00 -2.00e+00
 
-     4.00e+00 3.00e+00
 
-     1.00e+00 0.00e+00
 
-     0.00e+00 5.00e+00
 
-     2.50e+00 0.00e+00
 
-     """
 
-     MMFile().write(target, a, comment, field, precision, symmetry)
 
- ###############################################################################
 
- class MMFile:
 
-     __slots__ = ('_rows',
 
-                  '_cols',
 
-                  '_entries',
 
-                  '_format',
 
-                  '_field',
 
-                  '_symmetry')
 
-     @property
 
-     def rows(self):
 
-         return self._rows
 
-     @property
 
-     def cols(self):
 
-         return self._cols
 
-     @property
 
-     def entries(self):
 
-         return self._entries
 
-     @property
 
-     def format(self):
 
-         return self._format
 
-     @property
 
-     def field(self):
 
-         return self._field
 
-     @property
 
-     def symmetry(self):
 
-         return self._symmetry
 
-     @property
 
-     def has_symmetry(self):
 
-         return self._symmetry in (self.SYMMETRY_SYMMETRIC,
 
-                                   self.SYMMETRY_SKEW_SYMMETRIC,
 
-                                   self.SYMMETRY_HERMITIAN)
 
-     # format values
 
-     FORMAT_COORDINATE = 'coordinate'
 
-     FORMAT_ARRAY = 'array'
 
-     FORMAT_VALUES = (FORMAT_COORDINATE, FORMAT_ARRAY)
 
-     @classmethod
 
-     def _validate_format(self, format):
 
-         if format not in self.FORMAT_VALUES:
 
-             raise ValueError('unknown format type %s, must be one of %s' %
 
-                              (format, self.FORMAT_VALUES))
 
-     # field values
 
-     FIELD_INTEGER = 'integer'
 
-     FIELD_UNSIGNED = 'unsigned-integer'
 
-     FIELD_REAL = 'real'
 
-     FIELD_COMPLEX = 'complex'
 
-     FIELD_PATTERN = 'pattern'
 
-     FIELD_VALUES = (FIELD_INTEGER, FIELD_UNSIGNED, FIELD_REAL, FIELD_COMPLEX,
 
-                     FIELD_PATTERN)
 
-     @classmethod
 
-     def _validate_field(self, field):
 
-         if field not in self.FIELD_VALUES:
 
-             raise ValueError('unknown field type %s, must be one of %s' %
 
-                              (field, self.FIELD_VALUES))
 
-     # symmetry values
 
-     SYMMETRY_GENERAL = 'general'
 
-     SYMMETRY_SYMMETRIC = 'symmetric'
 
-     SYMMETRY_SKEW_SYMMETRIC = 'skew-symmetric'
 
-     SYMMETRY_HERMITIAN = 'hermitian'
 
-     SYMMETRY_VALUES = (SYMMETRY_GENERAL, SYMMETRY_SYMMETRIC,
 
-                        SYMMETRY_SKEW_SYMMETRIC, SYMMETRY_HERMITIAN)
 
-     @classmethod
 
-     def _validate_symmetry(self, symmetry):
 
-         if symmetry not in self.SYMMETRY_VALUES:
 
-             raise ValueError('unknown symmetry type %s, must be one of %s' %
 
-                              (symmetry, self.SYMMETRY_VALUES))
 
-     DTYPES_BY_FIELD = {FIELD_INTEGER: 'intp',
 
-                        FIELD_UNSIGNED: 'uint64',
 
-                        FIELD_REAL: 'd',
 
-                        FIELD_COMPLEX: 'D',
 
-                        FIELD_PATTERN: 'd'}
 
-     # -------------------------------------------------------------------------
 
-     @staticmethod
 
-     def reader():
 
-         pass
 
-     # -------------------------------------------------------------------------
 
-     @staticmethod
 
-     def writer():
 
-         pass
 
-     # -------------------------------------------------------------------------
 
-     @classmethod
 
-     def info(self, source):
 
-         """
 
-         Return size, storage parameters from Matrix Market file-like 'source'.
 
-         Parameters
 
-         ----------
 
-         source : str or file-like
 
-             Matrix Market filename (extension .mtx) or open file-like object
 
-         Returns
 
-         -------
 
-         rows : int
 
-             Number of matrix rows.
 
-         cols : int
 
-             Number of matrix columns.
 
-         entries : int
 
-             Number of non-zero entries of a sparse matrix
 
-             or rows*cols for a dense matrix.
 
-         format : str
 
-             Either 'coordinate' or 'array'.
 
-         field : str
 
-             Either 'real', 'complex', 'pattern', or 'integer'.
 
-         symmetry : str
 
-             Either 'general', 'symmetric', 'skew-symmetric', or 'hermitian'.
 
-         """
 
-         stream, close_it = self._open(source)
 
-         try:
 
-             # read and validate header line
 
-             line = stream.readline()
 
-             mmid, matrix, format, field, symmetry = \
 
-                 [asstr(part.strip()) for part in line.split()]
 
-             if not mmid.startswith('%%MatrixMarket'):
 
-                 raise ValueError('source is not in Matrix Market format')
 
-             if not matrix.lower() == 'matrix':
 
-                 raise ValueError("Problem reading file header: " + line)
 
-             # http://math.nist.gov/MatrixMarket/formats.html
 
-             if format.lower() == 'array':
 
-                 format = self.FORMAT_ARRAY
 
-             elif format.lower() == 'coordinate':
 
-                 format = self.FORMAT_COORDINATE
 
-             # skip comments
 
-             # line.startswith('%')
 
-             while line and line[0] in ['%', 37]:
 
-                 line = stream.readline()
 
-             # skip empty lines
 
-             while not line.strip():
 
-                 line = stream.readline()
 
-             split_line = line.split()
 
-             if format == self.FORMAT_ARRAY:
 
-                 if not len(split_line) == 2:
 
-                     raise ValueError("Header line not of length 2: " +
 
-                                      line.decode('ascii'))
 
-                 rows, cols = map(int, split_line)
 
-                 entries = rows * cols
 
-             else:
 
-                 if not len(split_line) == 3:
 
-                     raise ValueError("Header line not of length 3: " +
 
-                                      line.decode('ascii'))
 
-                 rows, cols, entries = map(int, split_line)
 
-             return (rows, cols, entries, format, field.lower(),
 
-                     symmetry.lower())
 
-         finally:
 
-             if close_it:
 
-                 stream.close()
 
-     # -------------------------------------------------------------------------
 
-     @staticmethod
 
-     def _open(filespec, mode='rb'):
 
-         """ Return an open file stream for reading based on source.
 
-         If source is a file name, open it (after trying to find it with mtx and
 
-         gzipped mtx extensions). Otherwise, just return source.
 
-         Parameters
 
-         ----------
 
-         filespec : str or file-like
 
-             String giving file name or file-like object
 
-         mode : str, optional
 
-             Mode with which to open file, if `filespec` is a file name.
 
-         Returns
 
-         -------
 
-         fobj : file-like
 
-             Open file-like object.
 
-         close_it : bool
 
-             True if the calling function should close this file when done,
 
-             false otherwise.
 
-         """
 
-         # If 'filespec' is path-like (str, pathlib.Path, os.DirEntry, other class
 
-         # implementing a '__fspath__' method), try to convert it to str. If this
 
-         # fails by throwing a 'TypeError', assume it's an open file handle and
 
-         # return it as-is.
 
-         try:
 
-             filespec = os.fspath(filespec)
 
-         except TypeError:
 
-             return filespec, False
 
-         # 'filespec' is definitely a str now
 
-         # open for reading
 
-         if mode[0] == 'r':
 
-             # determine filename plus extension
 
-             if not os.path.isfile(filespec):
 
-                 if os.path.isfile(filespec+'.mtx'):
 
-                     filespec = filespec + '.mtx'
 
-                 elif os.path.isfile(filespec+'.mtx.gz'):
 
-                     filespec = filespec + '.mtx.gz'
 
-                 elif os.path.isfile(filespec+'.mtx.bz2'):
 
-                     filespec = filespec + '.mtx.bz2'
 
-             # open filename
 
-             if filespec.endswith('.gz'):
 
-                 import gzip
 
-                 stream = gzip.open(filespec, mode)
 
-             elif filespec.endswith('.bz2'):
 
-                 import bz2
 
-                 stream = bz2.BZ2File(filespec, 'rb')
 
-             else:
 
-                 stream = open(filespec, mode)
 
-         # open for writing
 
-         else:
 
-             if filespec[-4:] != '.mtx':
 
-                 filespec = filespec + '.mtx'
 
-             stream = open(filespec, mode)
 
-         return stream, True
 
-     # -------------------------------------------------------------------------
 
-     @staticmethod
 
-     def _get_symmetry(a):
 
-         m, n = a.shape
 
-         if m != n:
 
-             return MMFile.SYMMETRY_GENERAL
 
-         issymm = True
 
-         isskew = True
 
-         isherm = a.dtype.char in 'FD'
 
-         # sparse input
 
-         if isspmatrix(a):
 
-             # check if number of nonzero entries of lower and upper triangle
 
-             # matrix are equal
 
-             a = a.tocoo()
 
-             (row, col) = a.nonzero()
 
-             if (row < col).sum() != (row > col).sum():
 
-                 return MMFile.SYMMETRY_GENERAL
 
-             # define iterator over symmetric pair entries
 
-             a = a.todok()
 
-             def symm_iterator():
 
-                 for ((i, j), aij) in a.items():
 
-                     if i > j:
 
-                         aji = a[j, i]
 
-                         yield (aij, aji, False)
 
-                     elif i == j:
 
-                         yield (aij, aij, True)
 
-         # non-sparse input
 
-         else:
 
-             # define iterator over symmetric pair entries
 
-             def symm_iterator():
 
-                 for j in range(n):
 
-                     for i in range(j, n):
 
-                         aij, aji = a[i][j], a[j][i]
 
-                         yield (aij, aji, i == j)
 
-         # check for symmetry
 
-         # yields aij, aji, is_diagonal
 
-         for (aij, aji, is_diagonal) in symm_iterator():
 
-             if isskew and is_diagonal and aij != 0:
 
-                 isskew = False
 
-             else:
 
-                 if issymm and aij != aji:
 
-                     issymm = False
 
-                 with np.errstate(over="ignore"):
 
-                     # This can give a warning for uint dtypes, so silence that
 
-                     if isskew and aij != -aji:
 
-                         isskew = False
 
-                 if isherm and aij != conj(aji):
 
-                     isherm = False
 
-             if not (issymm or isskew or isherm):
 
-                 break
 
-         # return symmetry value
 
-         if issymm:
 
-             return MMFile.SYMMETRY_SYMMETRIC
 
-         if isskew:
 
-             return MMFile.SYMMETRY_SKEW_SYMMETRIC
 
-         if isherm:
 
-             return MMFile.SYMMETRY_HERMITIAN
 
-         return MMFile.SYMMETRY_GENERAL
 
-     # -------------------------------------------------------------------------
 
-     @staticmethod
 
-     def _field_template(field, precision):
 
-         return {MMFile.FIELD_REAL: '%%.%ie\n' % precision,
 
-                 MMFile.FIELD_INTEGER: '%i\n',
 
-                 MMFile.FIELD_UNSIGNED: '%u\n',
 
-                 MMFile.FIELD_COMPLEX: '%%.%ie %%.%ie\n' %
 
-                     (precision, precision)
 
-                 }.get(field, None)
 
-     # -------------------------------------------------------------------------
 
-     def __init__(self, **kwargs):
 
-         self._init_attrs(**kwargs)
 
-     # -------------------------------------------------------------------------
 
-     def read(self, source):
 
-         """
 
-         Reads the contents of a Matrix Market file-like 'source' into a matrix.
 
-         Parameters
 
-         ----------
 
-         source : str or file-like
 
-             Matrix Market filename (extensions .mtx, .mtz.gz)
 
-             or open file object.
 
-         Returns
 
-         -------
 
-         a : ndarray or coo_matrix
 
-             Dense or sparse matrix depending on the matrix format in the
 
-             Matrix Market file.
 
-         """
 
-         stream, close_it = self._open(source)
 
-         try:
 
-             self._parse_header(stream)
 
-             return self._parse_body(stream)
 
-         finally:
 
-             if close_it:
 
-                 stream.close()
 
-     # -------------------------------------------------------------------------
 
-     def write(self, target, a, comment='', field=None, precision=None,
 
-               symmetry=None):
 
-         """
 
-         Writes sparse or dense array `a` to Matrix Market file-like `target`.
 
-         Parameters
 
-         ----------
 
-         target : str or file-like
 
-             Matrix Market filename (extension .mtx) or open file-like object.
 
-         a : array like
 
-             Sparse or dense 2-D array.
 
-         comment : str, optional
 
-             Comments to be prepended to the Matrix Market file.
 
-         field : None or str, optional
 
-             Either 'real', 'complex', 'pattern', or 'integer'.
 
-         precision : None or int, optional
 
-             Number of digits to display for real or complex values.
 
-         symmetry : None or str, optional
 
-             Either 'general', 'symmetric', 'skew-symmetric', or 'hermitian'.
 
-             If symmetry is None the symmetry type of 'a' is determined by its
 
-             values.
 
-         """
 
-         stream, close_it = self._open(target, 'wb')
 
-         try:
 
-             self._write(stream, a, comment, field, precision, symmetry)
 
-         finally:
 
-             if close_it:
 
-                 stream.close()
 
-             else:
 
-                 stream.flush()
 
-     # -------------------------------------------------------------------------
 
-     def _init_attrs(self, **kwargs):
 
-         """
 
-         Initialize each attributes with the corresponding keyword arg value
 
-         or a default of None
 
-         """
 
-         attrs = self.__class__.__slots__
 
-         public_attrs = [attr[1:] for attr in attrs]
 
-         invalid_keys = set(kwargs.keys()) - set(public_attrs)
 
-         if invalid_keys:
 
-             raise ValueError('''found %s invalid keyword arguments, please only
 
-                                 use %s''' % (tuple(invalid_keys),
 
-                                              public_attrs))
 
-         for attr in attrs:
 
-             setattr(self, attr, kwargs.get(attr[1:], None))
 
-     # -------------------------------------------------------------------------
 
-     def _parse_header(self, stream):
 
-         rows, cols, entries, format, field, symmetry = \
 
-             self.__class__.info(stream)
 
-         self._init_attrs(rows=rows, cols=cols, entries=entries, format=format,
 
-                          field=field, symmetry=symmetry)
 
-     # -------------------------------------------------------------------------
 
-     def _parse_body(self, stream):
 
-         rows, cols, entries, format, field, symm = (self.rows, self.cols,
 
-                                                     self.entries, self.format,
 
-                                                     self.field, self.symmetry)
 
-         try:
 
-             from scipy.sparse import coo_matrix
 
-         except ImportError:
 
-             coo_matrix = None
 
-         dtype = self.DTYPES_BY_FIELD.get(field, None)
 
-         has_symmetry = self.has_symmetry
 
-         is_integer = field == self.FIELD_INTEGER
 
-         is_unsigned_integer = field == self.FIELD_UNSIGNED
 
-         is_complex = field == self.FIELD_COMPLEX
 
-         is_skew = symm == self.SYMMETRY_SKEW_SYMMETRIC
 
-         is_herm = symm == self.SYMMETRY_HERMITIAN
 
-         is_pattern = field == self.FIELD_PATTERN
 
-         if format == self.FORMAT_ARRAY:
 
-             a = zeros((rows, cols), dtype=dtype)
 
-             line = 1
 
-             i, j = 0, 0
 
-             if is_skew:
 
-                 a[i, j] = 0
 
-                 if i < rows - 1:
 
-                     i += 1
 
-             while line:
 
-                 line = stream.readline()
 
-                 # line.startswith('%')
 
-                 if not line or line[0] in ['%', 37] or not line.strip():
 
-                     continue
 
-                 if is_integer:
 
-                     aij = int(line)
 
-                 elif is_unsigned_integer:
 
-                     aij = int(line)
 
-                 elif is_complex:
 
-                     aij = complex(*map(float, line.split()))
 
-                 else:
 
-                     aij = float(line)
 
-                 a[i, j] = aij
 
-                 if has_symmetry and i != j:
 
-                     if is_skew:
 
-                         a[j, i] = -aij
 
-                     elif is_herm:
 
-                         a[j, i] = conj(aij)
 
-                     else:
 
-                         a[j, i] = aij
 
-                 if i < rows-1:
 
-                     i = i + 1
 
-                 else:
 
-                     j = j + 1
 
-                     if not has_symmetry:
 
-                         i = 0
 
-                     else:
 
-                         i = j
 
-                         if is_skew:
 
-                             a[i, j] = 0
 
-                             if i < rows-1:
 
-                                 i += 1
 
-             if is_skew:
 
-                 if not (i in [0, j] and j == cols - 1):
 
-                     raise ValueError("Parse error, did not read all lines.")
 
-             else:
 
-                 if not (i in [0, j] and j == cols):
 
-                     raise ValueError("Parse error, did not read all lines.")
 
-         elif format == self.FORMAT_COORDINATE and coo_matrix is None:
 
-             # Read sparse matrix to dense when coo_matrix is not available.
 
-             a = zeros((rows, cols), dtype=dtype)
 
-             line = 1
 
-             k = 0
 
-             while line:
 
-                 line = stream.readline()
 
-                 # line.startswith('%')
 
-                 if not line or line[0] in ['%', 37] or not line.strip():
 
-                     continue
 
-                 l = line.split()
 
-                 i, j = map(int, l[:2])
 
-                 i, j = i-1, j-1
 
-                 if is_integer:
 
-                     aij = int(l[2])
 
-                 elif is_unsigned_integer:
 
-                     aij = int(l[2])
 
-                 elif is_complex:
 
-                     aij = complex(*map(float, l[2:]))
 
-                 else:
 
-                     aij = float(l[2])
 
-                 a[i, j] = aij
 
-                 if has_symmetry and i != j:
 
-                     if is_skew:
 
-                         a[j, i] = -aij
 
-                     elif is_herm:
 
-                         a[j, i] = conj(aij)
 
-                     else:
 
-                         a[j, i] = aij
 
-                 k = k + 1
 
-             if not k == entries:
 
-                 ValueError("Did not read all entries")
 
-         elif format == self.FORMAT_COORDINATE:
 
-             # Read sparse COOrdinate format
 
-             if entries == 0:
 
-                 # empty matrix
 
-                 return coo_matrix((rows, cols), dtype=dtype)
 
-             I = zeros(entries, dtype='intc')
 
-             J = zeros(entries, dtype='intc')
 
-             if is_pattern:
 
-                 V = ones(entries, dtype='int8')
 
-             elif is_integer:
 
-                 V = zeros(entries, dtype='intp')
 
-             elif is_unsigned_integer:
 
-                 V = zeros(entries, dtype='uint64')
 
-             elif is_complex:
 
-                 V = zeros(entries, dtype='complex')
 
-             else:
 
-                 V = zeros(entries, dtype='float')
 
-             entry_number = 0
 
-             for line in stream:
 
-                 # line.startswith('%')
 
-                 if not line or line[0] in ['%', 37] or not line.strip():
 
-                     continue
 
-                 if entry_number+1 > entries:
 
-                     raise ValueError("'entries' in header is smaller than "
 
-                                      "number of entries")
 
-                 l = line.split()
 
-                 I[entry_number], J[entry_number] = map(int, l[:2])
 
-                 if not is_pattern:
 
-                     if is_integer:
 
-                         V[entry_number] = int(l[2])
 
-                     elif is_unsigned_integer:
 
-                         V[entry_number] = int(l[2])
 
-                     elif is_complex:
 
-                         V[entry_number] = complex(*map(float, l[2:]))
 
-                     else:
 
-                         V[entry_number] = float(l[2])
 
-                 entry_number += 1
 
-             if entry_number < entries:
 
-                 raise ValueError("'entries' in header is larger than "
 
-                                  "number of entries")
 
-             I -= 1  # adjust indices (base 1 -> base 0)
 
-             J -= 1
 
-             if has_symmetry:
 
-                 mask = (I != J)       # off diagonal mask
 
-                 od_I = I[mask]
 
-                 od_J = J[mask]
 
-                 od_V = V[mask]
 
-                 I = concatenate((I, od_J))
 
-                 J = concatenate((J, od_I))
 
-                 if is_skew:
 
-                     od_V *= -1
 
-                 elif is_herm:
 
-                     od_V = od_V.conjugate()
 
-                 V = concatenate((V, od_V))
 
-             a = coo_matrix((V, (I, J)), shape=(rows, cols), dtype=dtype)
 
-         else:
 
-             raise NotImplementedError(format)
 
-         return a
 
-     #  ------------------------------------------------------------------------
 
-     def _write(self, stream, a, comment='', field=None, precision=None,
 
-                symmetry=None):
 
-         if isinstance(a, list) or isinstance(a, ndarray) or \
 
-            isinstance(a, tuple) or hasattr(a, '__array__'):
 
-             rep = self.FORMAT_ARRAY
 
-             a = asarray(a)
 
-             if len(a.shape) != 2:
 
-                 raise ValueError('Expected 2 dimensional array')
 
-             rows, cols = a.shape
 
-             if field is not None:
 
-                 if field == self.FIELD_INTEGER:
 
-                     if not can_cast(a.dtype, 'intp'):
 
-                         raise OverflowError("mmwrite does not support integer "
 
-                                             "dtypes larger than native 'intp'.")
 
-                     a = a.astype('intp')
 
-                 elif field == self.FIELD_REAL:
 
-                     if a.dtype.char not in 'fd':
 
-                         a = a.astype('d')
 
-                 elif field == self.FIELD_COMPLEX:
 
-                     if a.dtype.char not in 'FD':
 
-                         a = a.astype('D')
 
-         else:
 
-             if not isspmatrix(a):
 
-                 raise ValueError('unknown matrix type: %s' % type(a))
 
-             rep = 'coordinate'
 
-             rows, cols = a.shape
 
-         typecode = a.dtype.char
 
-         if precision is None:
 
-             if typecode in 'fF':
 
-                 precision = 8
 
-             else:
 
-                 precision = 16
 
-         if field is None:
 
-             kind = a.dtype.kind
 
-             if kind == 'i':
 
-                 if not can_cast(a.dtype, 'intp'):
 
-                     raise OverflowError("mmwrite does not support integer "
 
-                                         "dtypes larger than native 'intp'.")
 
-                 field = 'integer'
 
-             elif kind == 'f':
 
-                 field = 'real'
 
-             elif kind == 'c':
 
-                 field = 'complex'
 
-             elif kind == 'u':
 
-                 field = 'unsigned-integer'
 
-             else:
 
-                 raise TypeError('unexpected dtype kind ' + kind)
 
-         if symmetry is None:
 
-             symmetry = self._get_symmetry(a)
 
-         # validate rep, field, and symmetry
 
-         self.__class__._validate_format(rep)
 
-         self.__class__._validate_field(field)
 
-         self.__class__._validate_symmetry(symmetry)
 
-         # write initial header line
 
-         data = f'%%MatrixMarket matrix {rep} {field} {symmetry}\n'
 
-         stream.write(data.encode('latin1'))
 
-         # write comments
 
-         for line in comment.split('\n'):
 
-             data = '%%%s\n' % (line)
 
-             stream.write(data.encode('latin1'))
 
-         template = self._field_template(field, precision)
 
-         # write dense format
 
-         if rep == self.FORMAT_ARRAY:
 
-             # write shape spec
 
-             data = '%i %i\n' % (rows, cols)
 
-             stream.write(data.encode('latin1'))
 
-             if field in (self.FIELD_INTEGER, self.FIELD_REAL,
 
-                          self.FIELD_UNSIGNED):
 
-                 if symmetry == self.SYMMETRY_GENERAL:
 
-                     for j in range(cols):
 
-                         for i in range(rows):
 
-                             data = template % a[i, j]
 
-                             stream.write(data.encode('latin1'))
 
-                 elif symmetry == self.SYMMETRY_SKEW_SYMMETRIC:
 
-                     for j in range(cols):
 
-                         for i in range(j + 1, rows):
 
-                             data = template % a[i, j]
 
-                             stream.write(data.encode('latin1'))
 
-                 else:
 
-                     for j in range(cols):
 
-                         for i in range(j, rows):
 
-                             data = template % a[i, j]
 
-                             stream.write(data.encode('latin1'))
 
-             elif field == self.FIELD_COMPLEX:
 
-                 if symmetry == self.SYMMETRY_GENERAL:
 
-                     for j in range(cols):
 
-                         for i in range(rows):
 
-                             aij = a[i, j]
 
-                             data = template % (real(aij), imag(aij))
 
-                             stream.write(data.encode('latin1'))
 
-                 else:
 
-                     for j in range(cols):
 
-                         for i in range(j, rows):
 
-                             aij = a[i, j]
 
-                             data = template % (real(aij), imag(aij))
 
-                             stream.write(data.encode('latin1'))
 
-             elif field == self.FIELD_PATTERN:
 
-                 raise ValueError('pattern type inconsisted with dense format')
 
-             else:
 
-                 raise TypeError('Unknown field type %s' % field)
 
-         # write sparse format
 
-         else:
 
-             coo = a.tocoo()  # convert to COOrdinate format
 
-             # if symmetry format used, remove values above main diagonal
 
-             if symmetry != self.SYMMETRY_GENERAL:
 
-                 lower_triangle_mask = coo.row >= coo.col
 
-                 coo = coo_matrix((coo.data[lower_triangle_mask],
 
-                                  (coo.row[lower_triangle_mask],
 
-                                   coo.col[lower_triangle_mask])),
 
-                                  shape=coo.shape)
 
-             # write shape spec
 
-             data = '%i %i %i\n' % (rows, cols, coo.nnz)
 
-             stream.write(data.encode('latin1'))
 
-             template = self._field_template(field, precision-1)
 
-             if field == self.FIELD_PATTERN:
 
-                 for r, c in zip(coo.row+1, coo.col+1):
 
-                     data = "%i %i\n" % (r, c)
 
-                     stream.write(data.encode('latin1'))
 
-             elif field in (self.FIELD_INTEGER, self.FIELD_REAL,
 
-                            self.FIELD_UNSIGNED):
 
-                 for r, c, d in zip(coo.row+1, coo.col+1, coo.data):
 
-                     data = ("%i %i " % (r, c)) + (template % d)
 
-                     stream.write(data.encode('latin1'))
 
-             elif field == self.FIELD_COMPLEX:
 
-                 for r, c, d in zip(coo.row+1, coo.col+1, coo.data):
 
-                     data = ("%i %i " % (r, c)) + (template % (d.real, d.imag))
 
-                     stream.write(data.encode('latin1'))
 
-             else:
 
-                 raise TypeError('Unknown field type %s' % field)
 
- def _is_fromfile_compatible(stream):
 
-     """
 
-     Check whether `stream` is compatible with numpy.fromfile.
 
-     Passing a gzipped file object to ``fromfile/fromstring`` doesn't work with
 
-     Python 3.
 
-     """
 
-     bad_cls = []
 
-     try:
 
-         import gzip
 
-         bad_cls.append(gzip.GzipFile)
 
-     except ImportError:
 
-         pass
 
-     try:
 
-         import bz2
 
-         bad_cls.append(bz2.BZ2File)
 
-     except ImportError:
 
-         pass
 
-     bad_cls = tuple(bad_cls)
 
-     return not isinstance(stream, bad_cls)
 
 
  |