[MATRIX-SIG] Re: Printing BUG?

Janko Hauser jhauser@ifm.uni-kiel.de
Tue, 7 Oct 1997 09:22:57 +0200 (CEST)


Here another addition to ArrayPrinter. There is the option to change
the seperator between numbers in ArrayPrinter.array2string. I have
added the option bracket=[1/0] to change the output in this way, that
there are no surrounding brackets. This is sometimes useful for
ASCII-export. Are there any objections to this approach? 

__Janko

# ArrayPrinter

# Array printing function
#
# Written by Konrad Hinsen <hinsenk@ere.umontreal.ca>
# last revision: 1996-3-13
# modified by Jim Hugunin 1997-3-3 for repr's and str's (and other details)
# modified by Janko Hauser 1997-10-7 to exclude the brackets and added
# the path of Konrad Hinsen for printing of big numbers 
# 
import sys
from fast_umath import *
import Numeric

def array2string(a, max_line_width = None, precision = None,
					 suppress_small = None, separator=' ',
					 array_output=0, bracket = 1):
	if len(a.shape) == 0:
		return str(a[0])

	if multiply.reduce(a.shape) == 0:
		return "zeros(%s, '%s')" % (a.shape, a.typecode())

	if max_line_width is None:
		try:
			max_line_width = sys.output_line_width
		except AttributeError:
			max_line_width = 77
	if precision is None:
		try:
			precision = sys.float_output_precision
		except AttributeError:
			precision = 8
	if suppress_small is None:
		try:
			suppress_small = sys.float_output_suppress_small
		except AttributeError:
			suppress_small = 0
	data = Numeric.ravel(a)
	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'
		item_length = max_str_len
		format_function = lambda x, f = format: _formatInteger(x, f)
	elif type == 'f' or type == 'd':
		format, item_length = _floatFormat(data, precision, suppress_small)
		format_function = lambda x, f = format: _formatFloat(x, f)
	elif type == 'F' or type == 'D':
		real_format, real_item_length = _floatFormat(data.real, precision,
													 suppress_small, sign=0)
		imag_format, imag_item_length = _floatFormat(data.imaginary, precision,
													 suppress_small, sign=1)
		item_length = real_item_length + imag_item_length + 3
		format_function = lambda x, f1 = real_format, f2 = imag_format: \
						  _formatComplex(x, f1, f2)
	elif type == 'c':
		item_length = 1
		format_function = lambda x: x
	elif type == 'O':
		item_length = max(map(lambda x: len(str(x)), data))
		format_function = _formatGeneral
	else:
		return str(a)
	final_spaces = (type != 'c')
	item_length = item_length+len(separator)
	line_width = item_length*items_per_line - final_spaces
	if line_width > max_line_width:
		indent = 6
		if indent == item_length:
			indent = 8
		items_first = (max_line_width+final_spaces)/item_length
		if items_first < 1: items_first = 1
		items_continuation = (max_line_width+final_spaces-indent)/item_length
		if items_continuation < 1: items_continuation = 1
		line_width = max(item_length*items_first,
						 item_length*items_continuation+indent) - final_spaces
		number_of_lines = 1 + (items_per_line-items_first +
							   items_continuation-1)/items_continuation
		line_format = (number_of_lines, items_first, items_continuation,
					   indent, line_width, separator)
	else:
		line_format = (1, items_per_line, 0, 0, line_width, separator)
	lst = _arrayToString(a, format_function, len(a.shape), line_format, 6*array_output, 0, bracket=bracket)[:-1]
	if array_output:
		if a.typecode() in ['l', 'd', 'D']:
			return "array(%s)" % lst
		else:
			return "array(%s,'%s')" % (lst, a.typecode())
	else:
		return lst
		
def _floatFormat(data, precision, suppress_small, sign = 0):
	exp_format = 0
	non_zero = abs(Numeric.compress(not_equal(data, 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:
			exp_format = 1
		if not suppress_small and (min_val < 0.0001 or max_val/min_val > 1000.):
			exp_format = 1
	if exp_format:
		large_exponent = 0 < min_val < 1e-99 or max_val >= 1e100
		max_str_len = 8 + precision + large_exponent
		if sign: format = '%+'
		else: format = '%'
		format = format + str(max_str_len) + '.' + str(precision) + 'e'
		if large_exponent: format = format + '3'
		item_length = max_str_len 
	else:
		format = '%.' + str(precision) + 'f'
		precision = min(precision, max(tuple(map(lambda x, p=precision,
												 f=format: _digits(x,p,f),
												 data))))
		max_str_len = len(str(int(max_val))) + precision + 2
		if sign: format = '%#+'
		else: format = '%#'
		format = format + str(max_str_len) + '.' + str(precision) + 'f'
		item_length = max_str_len 
	return (format, item_length)

def _digits(x, precision, format):
	s = format % x
	zeros = len(s)
	while s[zeros-1] == '0': zeros = zeros-1
	return precision-len(s)+zeros

def _arrayToString(a, format_function, rank, line_format, base_indent=0, indent_first=1, bracket):
    
        if bracket:
                l_br = '['
                r_br = ']'
        else:
                l_br = ''
                r_br = ''

        if rank == 0:
		return str(a[0])
	elif rank == 1:
		s = ''
		s0 = l_br
		items = line_format[1]
		if indent_first:
			indent = base_indent
		else:
			indent = 0
		index = 0
		for j in range(line_format[0]):
			s = s + indent * ' '+s0
			for i in range(items):
				s = s + format_function(a[index])+line_format[-1]
				index = index + 1
				if index == a.shape[0]: break
			if s[-1] == ' ': s = s[:-1]
			s = s + '\n'
			items = line_format[2]
			indent = line_format[3]+base_indent
			s0 = ''
		s = s[:-len(line_format[-1])]+r_br+'\n'
	else:
		if indent_first:
			s = ' '*base_indent+l_br
		else:
			s = l_br
		for i in range(a.shape[0]-1):
			s = s + _arrayToString(a[i], format_function, rank-1, line_format, base_indent+1, indent_first=i!=0)
			s = s[:-1]+line_format[-1][:-1]+'\n'
		s = s + _arrayToString(a[a.shape[0]-1], format_function,
							   rank-1, line_format, base_indent+1)
		s = s[:-1]+r_br+'\n'
	return s

def _formatInteger(x, format):
	return format % x

def _formatFloat(x, format, strip_zeros = 1):
	if format[-1] == '3':
		format = format[:-1]
		s = format % x
		third = s[-3]
		if third == '+' or third == '-':
			s = s[1:-2] + '0' + s[-2:]
	elif format[-1] == 'f':
		s = format % x
		if strip_zeros:
			zeros = len(s)
			while s[zeros-1] == '0': zeros = zeros-1
			s = s[:zeros] + (len(s)-zeros)*' '
	else:
		s = format % x
	return s

def _formatComplex(x, real_format, imag_format):
	r = _formatFloat(x.real, real_format)
	i = _formatFloat(x.imag, imag_format, 0)
	if imag_format[-1] == 'f':
		zeros = len(i)
		while zeros > 2 and i[zeros-1] == '0': zeros = zeros-1
		i = i[:zeros] + 'j' + (len(i)-zeros)*' '
	else:
		i = i + 'j'
	return r + i

def _formatGeneral(x):
	return str(x) + ' '

if __name__ == '__main__':
	a = Numeric.arange(10)
	b = Numeric.array([a, a+10, a+20])
	c = Numeric.array([b,b+100, b+200])
	print array2string(a)
	print array2string(b)
	print array2string(sin(c), separator=', ', array_output=1)
	print array2string(sin(c)+1j*cos(c), separator=', ', array_output=1)
	print array2string(Numeric.array([[],[]]))

_______________
MATRIX-SIG  - SIG on Matrix Math for Python

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