Skip to content

Commit

Permalink
Trac #29203: character art: line wrapping for matrices
Browse files Browse the repository at this point in the history
This ticket adds breakpoints to the ASCII and unicode art
representations of matrices, so that wide matrices are wrapped in a
readable way:

{{{
sage: %display unicode_art 80
sage: set_random_seed(0)
sage: matrix.random(RDF, 3, 8)
⎛ -0.27440062056807446    0.5031965950979831 -0.001975438590219314
⎜ -0.35104242112828943    0.5084492941557279   0.19906256610645512
⎝ -0.20282268041839324    0.0728476884470246   -0.9938082549986424

   -0.9467802263760512    0.5056889961514748  -0.05461130074681608
    0.3242250183948632    0.6026443545751128   -0.9541798283979341
  0.004239223023573491   -0.6670085876677831    -0.635743483594841

 -0.033673314214051286   -0.9401270875197381⎞
   -0.8948790563276592   -0.5763034867990717⎟
    0.5778937006648461   -0.9007365327499568⎠
}}}

Previously, the output was completely scrambled if the matrix was wider
than the window size:
{{{
⎛ -0.27440062056807446    0.5031965950979831 -0.001975438590219314
-0.94678022
63760512    0.5056889961514748  -0.05461130074681608
-0.033673314214051286   -0.
9401270875197381⎞
⎜ -0.35104242112828943    0.5084492941557279   0.19906256610645512
0.32422501
83948632    0.6026443545751128   -0.9541798283979341
-0.8948790563276592   -0.
5763034867990717⎟
⎝ -0.20282268041839324    0.0728476884470246   -0.9938082549986424
0.0042392230
23573491   -0.6670085876677831    -0.635743483594841
0.5778937006648461   -0.
9007365327499568⎠
}}}

URL: https://trac.sagemath.org/29203
Reported by: gh-mwageringel
Ticket author(s): Markus Wageringel
Reviewer(s): Vincent Delecroix
  • Loading branch information
Release Manager committed Feb 17, 2020
2 parents 7d455b1 + 448cdcd commit d3f8e71
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 22 deletions.
6 changes: 3 additions & 3 deletions build/pkgs/configure/checksums.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
tarball=configure-VERSION.tar.gz
sha1=5331e588682dfea9308e8308e510d47429500e76
md5=fe1a9a72f856549d946340703d20d791
cksum=888161184
sha1=4c919d52821c13ee1903b2a593b5fddc29f7d74d
md5=6106060e1dbbe881b8983441541bca83
cksum=2159293899
2 changes: 1 addition & 1 deletion build/pkgs/configure/package-version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
158b93057a44377a3dd8235795317aa0bd412ed9
3615fd94ca3a0f9000b975d34599b37285d34b2a
85 changes: 70 additions & 15 deletions src/sage/matrix/matrix0.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1755,7 +1755,7 @@ cdef class Matrix(sage.structure.element.Matrix):
return self.str()

def str(self, rep_mapping=None, zero=None, plus_one=None, minus_one=None,
*, unicode=False, shape=None):
*, unicode=False, shape=None, character_art=False):
r"""
Return a nice string representation of the matrix.
Expand Down Expand Up @@ -1800,6 +1800,11 @@ cdef class Matrix(sage.structure.element.Matrix):
in accordance with the TeX rendering,
while the ASCII rendering defaults to square brackets.
- ``character_art`` -- boolean (default: ``False``); if ``True``, the
result will be of type :class:`~sage.typeset.ascii_art.AsciiArt` or
:class:`~sage.typeset.unicode_art.UnicodeArt` which support line
breaking of wide matrices that exceed the window width
EXAMPLES::
sage: R = PolynomialRing(QQ,6,'z')
Expand Down Expand Up @@ -1843,6 +1848,19 @@ cdef class Matrix(sage.structure.element.Matrix):
⎢│7 8│9││⎥
⎣┼───┼─┼┼⎦
If ``character_art`` is set, the lines of large matrices are wrapped in
a readable way::
sage: set_random_seed(0)
sage: matrix.random(RDF, 3, 5).str(unicode=True, character_art=True)
⎛ -0.27440062056807446 0.5031965950979831 -0.001975438590219314
⎜ -0.05461130074681608 -0.033673314214051286 -0.9401270875197381
⎝ 0.19906256610645512 0.3242250183948632 0.6026443545751128
<BLANKLINE>
-0.9467802263760512 0.5056889961514748⎞
-0.35104242112828943 0.5084492941557279⎟
-0.9541798283979341 -0.8948790563276592⎠
TESTS:
Prior to :trac:`11544` this could take a full minute to run (2011). ::
Expand Down Expand Up @@ -1927,8 +1945,15 @@ cdef class Matrix(sage.structure.element.Matrix):
brb = right.bottom # - bottom right bracket
srb = right.character # - single-row right bracket

if character_art:
if unicode:
from sage.typeset.unicode_art import UnicodeArt as CharacterArt
else:
from sage.typeset.ascii_art import AsciiArt as CharacterArt

if nr == 0 or nc == 0:
return slb + srb
result = slb + srb
return CharacterArt([result]) if character_art else result

row_divs, col_divs = self.subdivisions()
row_div_counts = [0] * (nr + 1)
Expand Down Expand Up @@ -1964,7 +1989,6 @@ cdef class Matrix(sage.structure.element.Matrix):

width = max(map(len, S))
rows = []
m = 0

hline = cl.join(hl * ((width + 1)*(b - a) - 1)
for a,b in zip([0] + col_divs, col_divs + [nc]))
Expand All @@ -1989,17 +2013,49 @@ cdef class Matrix(sage.structure.element.Matrix):

last_row = len(rows) - 1
if last_row == 0:
return slb + rows[0] + srb
rows[0] = tlb + rows[0] + trb
for r from 1 <= r < last_row:
rows[r] = mlb + rows[r] + mrb
rows[last_row] = blb + rows[last_row] + brb
s = "\n".join(rows)
return s
rows[0] = slb + rows[0] + srb
else:
rows[0] = tlb + rows[0] + trb
for r from 1 <= r < last_row:
rows[r] = mlb + rows[r] + mrb
rows[last_row] = blb + rows[last_row] + brb

if character_art:
breakpoints = []
idx = len(tlb) + (col_div_counts[0] if nc > 0 else 0) + width
for c from 1 <= c < nc:
breakpoints.append(idx)
len_sep = max(col_div_counts[c], 1)
idx += len_sep + width
return CharacterArt(rows, breakpoints=breakpoints)
else:
return "\n".join(rows)

def _ascii_art_(self):
"""
Return an ASCII art representation of this matrix.
EXAMPLES::
sage: set_random_seed(0)
sage: ascii_art(matrix.random(RDF, 3, 5)) # indirect doctest
[ -0.27440062056807446 0.5031965950979831 -0.001975438590219314
[ -0.05461130074681608 -0.033673314214051286 -0.9401270875197381
[ 0.19906256610645512 0.3242250183948632 0.6026443545751128
<BLANKLINE>
-0.9467802263760512 0.5056889961514748]
-0.35104242112828943 0.5084492941557279]
-0.9541798283979341 -0.8948790563276592]
"""
if self._nrows < max_rows and self._ncols < max_cols:
return self.str(character_art=True)
else:
from sage.typeset.ascii_art import AsciiArt
return AsciiArt(repr(self).splitlines())

def _unicode_art_(self):
"""
Unicode art representation of matrices
Return a unicode art representation of this matrix.
EXAMPLES::
Expand All @@ -2019,12 +2075,11 @@ cdef class Matrix(sage.structure.element.Matrix):
sage: unicode_art(A)
100 x 100 dense matrix over Integer Ring
"""
from sage.typeset.unicode_art import UnicodeArt
if self._nrows < max_rows and self._ncols < max_cols:
output = self.str(unicode=True)
return self.str(unicode=True, character_art=True)
else:
output = repr(self)
return UnicodeArt(output.splitlines())
from sage.typeset.unicode_art import UnicodeArt
return UnicodeArt(repr(self).splitlines())

def _latex_(self):
r"""
Expand Down
12 changes: 9 additions & 3 deletions src/sage/matrix/matrix_mod2_dense.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse


def str(self, rep_mapping=None, zero=None, plus_one=None, minus_one=None,
*, unicode=False, shape=None):
*, unicode=False, shape=None, character_art=False):
r"""
Return a nice string representation of the matrix.
Expand Down Expand Up @@ -368,6 +368,11 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse
in accordance with the TeX rendering,
while the ASCII rendering defaults to square brackets.
- ``character_art`` -- boolean (default: ``False``); if ``True``, the
result will be of type :class:`~sage.typeset.ascii_art.AsciiArt` or
:class:`~sage.typeset.unicode_art.UnicodeArt` which support line
breaking of wide matrices that exceed the window width
EXAMPLES::
sage: B = random_matrix(GF(2),3,3)
Expand Down Expand Up @@ -400,12 +405,13 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse
# Set the mapping based on keyword arguments
# We ignore minus_one (it's only there for compatibility with Matrix)
if (rep_mapping is not None or zero is not None or plus_one is not None
or unicode or shape is not None):
or unicode or shape is not None or character_art):
# Shunt mappings off to the generic code since they might not be
# single characters
return matrix_dense.Matrix_dense.str(self, rep_mapping=rep_mapping,
zero=zero, plus_one=plus_one,
unicode=unicode, shape=shape)
unicode=unicode, shape=shape,
character_art=character_art)

if self._nrows == 0 or self._ncols == 0:
return "[]"
Expand Down

0 comments on commit d3f8e71

Please sign in to comment.