/src/printing.lisp

http://github.com/tpapp/lla · Lisp · 88 lines · 66 code · 10 blank · 12 comment · 2 complexity · a0686f2a1ebe4986df76fe07ad927581 MD5 · raw file

  1. (in-package :lla)
  2. ;;;; Printing and formatting
  3. ;;;; General variables and utility functions
  4. (defun print-length-truncate (dimension)
  5. "Return values (min dimension *print-length*) and whether the
  6. constraint is binding."
  7. (if (or (not *print-length*) (<= dimension *print-length*))
  8. (values dimension nil)
  9. (values *print-length* t)))
  10. (defvar *lla-print-precision* 5
  11. "number of digits after the decimal point when printing numeric matrices")
  12. (defun standard-numeric-formatter (x)
  13. "Standard formatter for matrix printing. Respects
  14. *print-lla-precision*, and formats complex numbers as a+bi, eg
  15. 0.0+1.0i."
  16. ;; ?? do we want a complex numbers to be aligned on the +, like R? I
  17. ;; am not sure I like that very much, and for a lot of data, I would
  18. ;; visualize it graphically anyhow (I hate tables of 7+ numbers in
  19. ;; general). -- Tamas, 2009-sep-13
  20. (let ((precision *lla-print-precision*))
  21. (typecase x
  22. (integer (format nil "~d" x))
  23. (real (format nil "~,vf" precision x))
  24. (complex (format nil "~,vf+~,vfi"
  25. precision (realpart x)
  26. precision (imagpart x)))
  27. (t (format nil "~a" x)))))
  28. ;;;; matrices
  29. ;;; None of the code below assumes anything about classes, it just
  30. ;;; uses the mref interface to access elements.
  31. (defvar *lla-print-matrix-aligned* t
  32. "If non-nil, characters will be aligned.")
  33. (defvar *lla-print-matrix-paddig* 1
  34. "Number of spaces between columns.")
  35. (defun print-matrix (matrix stream masked-element
  36. &key (formatter #'standard-numeric-formatter))
  37. "Format and print the elements of matrix to stream, using
  38. *LLA-PRINT-MATRIX-PADDING* spaces between columns. If
  39. *LLA-PRINT-MATRIX-ALIGNED*, columns will be right-aligned. Prints at most
  40. *PRINT-LENGTH* rows and columns, indicating more with a ... Uses MREF for
  41. element access, printing MASKED-ELEMENT for masked elements.."
  42. ;; ?? maybe column & row labels, not a high priority at the moment
  43. (let+ (((&values nrow row-trunc?) (print-length-truncate (nrow matrix)))
  44. ((&values ncol col-trunc?) (print-length-truncate (ncol matrix)))
  45. (formatted-elements (make-array (list nrow ncol)))
  46. (column-widths (make-array ncol :element-type 'fixnum
  47. :initial-element 0))
  48. (padding (make-array *lla-print-matrix-paddig*
  49. :element-type 'character
  50. :initial-element #\space))
  51. (aligned? *lla-print-matrix-aligned*))
  52. ;; first pass - format elements, measure width
  53. (dotimes (col ncol)
  54. (dotimes (row nrow)
  55. (let+ (((&values element masked?) (mref matrix row col))
  56. (formatted-element (if masked?
  57. masked-element
  58. (funcall formatter element)))
  59. (width (length formatted-element)))
  60. (setf (aref column-widths col) (max (aref column-widths col) width)
  61. (aref formatted-elements row col) formatted-element))))
  62. ;; second pass - print
  63. (dotimes (row nrow)
  64. (when (plusp row)
  65. (fresh-line stream))
  66. (format stream " ")
  67. (dotimes (col ncol)
  68. (when (plusp col)
  69. (princ padding stream))
  70. (let ((elt (aref formatted-elements row col)))
  71. (if aligned?
  72. (format stream "~V@A" (aref column-widths col) elt)
  73. (princ elt stream))))
  74. (when col-trunc?
  75. (princ padding stream)
  76. (princ "..." stream)))
  77. (when row-trunc?
  78. (format stream "~&..."))))