[PYTHON MATRIX-SIG] New pretty printer

Konrad HINSEN hinsenk@ere.umontreal.ca
Fri, 2 Feb 1996 18:11:57 -0500


My pretty printer has made some progress, and I'll include the latest
version below. Just put it into your copy of Numeric.py. Line wrapping
is still missing. (BTW, what would be a good default line width? In the
VT100 days that would have been 80 characters, but does this still
make sense?) I can't say that I am satisfied with float formatting,
but anything better than now will be difficult to do and, most of
all, slow. The two problems are

1) Trailing zeros in non-exponential format. Right now there are
   always eight digits after the decimal point. It would be better
   to replace trailing zeros by spaces (easy) and reduce the width
   of the output fields to match the longest remaining number.
   But that requires a scan of the string representations of all
   the elements in an array, which is an expensive operation.

2) In exponential notation, numbers with three-digit exponents will
   not line up correctly with others. It would be necessary to
   have three-digit exponents for all numbers when at least
   one element requires it, but there is no formatting option
   to specify the number of exponent digits. The only solution
   would be cosmetic surgery on the final string, but that again
   is slow.

There are currently some problems with complex number output due to a
remaining bug in the array module. Normally it will only lead to a
wrong format selection, so it's not fatal.

And now the code:

def arrayToString(a, max_line_length = 80):
    if a.contiguous():
	data = a.reshape(None)
    else:
	data = a.copy().reshape(None)
    type = a.typecode()
    items_per_line = a.shape[-1]
    if type == 'b' or type == '1' or type == 's' or type == 'i' \
       or type == 'l':
	max_str_len = max(len(str(maximum.reduce(data))),
			  len(str(minimum.reduce(data))))
	format = '%' + str(max_str_len) + 'd'
	type = 'l'
	item_length = max_str_len+1
    elif type == 'f' or type == 'd':
	format, item_length = _floatFormat(data)
	type = 'd'
    elif type == 'F' or type == 'D':
	real_format, real_item_length = _floatFormat(data.real, sign=0)
	imag_format, imag_item_length = _floatFormat(data.imaginary, sign=1)
	format = '(' + real_format + imag_format + 'j)'
	item_length = real_item_length + imag_item_length + 2
	type = 'D'
    elif type == 'c':
	format = '%s'
	item_length = 1
    else:  # nothing for 'O'
	return str(a)
    line_length = item_length*items_per_line - (type != 'c')
    if line_length > max_line_length:
	pass
    return _arrayToString(a, type, format, len(a.shape), line_length)[:-1]

def _floatFormat(data, sign = 0):
    exp_format = 0
    non_zero = abs(compress(data.notEqual(0), data))
    print str(data), str(data.notEqual(0)), str(compress(data.notEqual(0), data))
    if len(non_zero) == 0:
	max_val = 0.
	min_val = 0.
    else:
	max_val = maximum.reduce(non_zero)
	min_val = minimum.reduce(non_zero)
	if max_val >= 1.e12 or min_val < 0.0001 or max_val/min_val > 1000.:
	    exp_format = 1
    if exp_format:
	max_str_len = 16 + (0 < min_val < 1e-99 or max_val >= 1e100)
	if sign: format = '%+'
	else: format = '%'
	format = format + str(max_str_len) + '.8e'
	item_length = max_str_len + 1
    else:
	max_str_len = len(str(int(max_val))) + 10
	if sign: format = '%+'
	else: format = '%'
	format = format + str(max_str_len) + '.8f'
	item_length = max_str_len + 1
    return (format, item_length)

def _arrayToString(a, type, format, rank, line_length):
    if rank == 0:
	return str(a[0])
    elif rank == 1:
	s = ''
	if type == 'c':
	    for i in range(a.shape[0]):
		s = s + (format % a[i])
	    s = s + '\n'
	elif type == 'D':
	    for i in range(a.shape[0]):
		s = s + (format % (a[i].real, a[i].imag)) + ' '
	    s = s[:-1] + '\n'
	else:
	    for i in range(a.shape[0]):
		s = s + (format % a[i]) + ' '
	    s = s[:-1] + '\n'
    else:
	s = ''
	for i in range(a.shape[0]-1):
	    s = s + _arrayToString(a[i], type, format, rank-1, line_length)
	    if rank == 3:
		s = s + '\n'
	    elif rank > 3:
		s = s + (rank-3)*(line_length*'-'+'\n')
	s = s + _arrayToString(a[a.shape[0]-1], type, format, rank-1, line_length)
    return s

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

send messages to: matrix-sig@python.org
administrivia to: matrix-sig-request@python.org
=================