Skip to content

Commit

Permalink
Trac #17341: visualize_structure for sparse matrices over GF(p) is br…
Browse files Browse the repository at this point in the history
…oken

{{{
sage: random_matrix(GF(2), 8, 586, sparse=True).visualize_structure()
IndexError: image index out of range
}}}

Solution: remove this specialized implementation, since the general one
from `Matrix` works just fine.

In the generic `visualize_structure()` method, we change `int` ->
`Py_ssize_t` to support matrices larger than 2^31.

URL: http://trac.sagemath.org/17341
Reported by: jhpalmieri
Ticket author(s): Jeroen Demeyer
Reviewer(s): John Palmieri
  • Loading branch information
Release Manager authored and vbraun committed Mar 9, 2016
2 parents 33519b6 + 2110b6a commit b5b6eca
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 84 deletions.
29 changes: 18 additions & 11 deletions src/sage/matrix/matrix2.pyx
Expand Up @@ -8504,10 +8504,17 @@ explicitly setting the argument to `True` or `False` will avoid this message."""
sage: img.save(filename)
sage: open(filename).read().startswith('\x89PNG')
True

TESTS:

Test :trac:`17341`::

sage: random_matrix(GF(2), 8, 586, sparse=True).visualize_structure()
512x6px 24-bit RGB image
"""
cdef int x, y, _x, _y, v, bi, bisq
cdef int ir,ic
cdef float b, fct
cdef Py_ssize_t x, y, _x, _y, v, bi, bisq
cdef Py_ssize_t ir, ic
cdef double b, fct
mr, mc = self.nrows(), self.ncols()
if maxsize is None:
ir = mc
Expand All @@ -8522,20 +8529,20 @@ explicitly setting the argument to `True` or `False` will avoid this message."""
ir = mc
ic = mr
b = 1.0
bi = round(b)
bi = int(round(b))
bisq = bi*bi
fct = 255.0/bisq
from sage.repl.image import Image
img = Image('RGB', (ir, ic))
pixel = img.pixels()
for x from 0 <= x < ic:
for y from 0 <= y < ir:
for x in range(ic):
for y in range(ir):
v = bisq
for _x from 0 <= _x < bi:
for _y from 0 <= _y < bi:
if not self.get_unsafe(<int>(x*b + _x), <int>(y*b + _y)).is_zero():
v-=1 #increase darkness
v = round(v*fct)
for _x in range(bi):
for _y in range(bi):
if not self.get_unsafe(<Py_ssize_t>(x*b + _x), <Py_ssize_t>(y*b + _y)).is_zero():
v -= 1 #increase darkness
v = <Py_ssize_t>(v * fct + 0.5)
pixel[y, x] = (v, v, v)
return img

Expand Down
73 changes: 0 additions & 73 deletions src/sage/matrix/matrix_modn_sparse.pyx
Expand Up @@ -560,79 +560,6 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse):
return list(nzp)
return nzp

def visualize_structure(self, filename=None, maxsize=512):
r"""
Write a PNG image to 'filename' which visualizes self by putting
black pixels in those positions which have nonzero entries.
White pixels are put at positions with zero entries. If 'maxsize'
is given, then the maximal dimension in either x or y direction is
set to 'maxsize' depending on which is bigger. If the image is
scaled, the darkness of the pixel reflects how many of the
represented entries are nonzero. So if e.g. one image pixel
actually represents a 2x2 submatrix, the dot is darker the more of
the four values are nonzero.
INPUT:
- ``filename`` -- String. Name of the filename to save the
resulting image.
- ``maxsize`` - integer (default: ``512``). Maximal dimension
in either x or y direction of the resulting image. If
``None`` or a maxsize larger than
``max(self.nrows(),self.ncols())`` is given the image will
have the same pixelsize as the matrix dimensions.
EXAMPLES::
sage: M = Matrix(GF(7), [[0,0,0,1,0,0,0,0],[0,1,0,0,0,0,1,0]], sparse=True); M
[0 0 0 1 0 0 0 0]
[0 1 0 0 0 0 1 0]
sage: img = M.visualize_structure(); img
8x2px 24-bit RGB image
You can use :meth:`~sage.repl.image.Image.save` to save the
resulting image::
sage: filename = tmp_filename(ext='.png')
sage: img.save(filename)
sage: open(filename).read().startswith('\x89PNG')
True
"""
cdef Py_ssize_t i, j, k
cdef float blk,invblk
cdef int delta
cdef int x,y,r,g,b
mr, mc = self.nrows(), self.ncols()
if maxsize is None:
ir = mc
ic = mr
blk = 1.0
invblk = 1.0
elif max(mr,mc) > maxsize:
maxsize = float(maxsize)
ir = int(mc * maxsize/max(mr,mc))
ic = int(mr * maxsize/max(mr,mc))
blk = max(mr,mc)/maxsize
invblk = maxsize/max(mr,mc)
else:
ir = mc
ic = mr
blk = 1.0
invblk = 1.0
delta = <int>(255.0 / blk*blk)
from sage.repl.image import Image
img = Image('RGB', (ir, ic), (255, 255, 255))
pixel = img.pixels()
for i from 0 <= i < self._nrows:
for j from 0 <= j < self.rows[i].num_nonzero:
x = <int>(invblk * self.rows[i].positions[j])
y = <int>(invblk * i)
r, g, b = pixel[x, y]
pixel[x, y] = (r-delta, g-delta, b-delta)
return img

def density(self):
"""
Return the density of self, i.e., the ratio of the number of
Expand Down

0 comments on commit b5b6eca

Please sign in to comment.