Search code examples
opencvprintinglispcommon-lispcffi

Need advice on how to print a matrix in lisp


I have a matrix defined so if I do this

(format t "~a" (get-real-2d 0 0))

it prints out the element in the first row first column

and if I do this

(format t "~a" (get-real-2d a 0 1))

it prints out the element in first row second column

and if I do this

(format t "~a" (get-real-2d a 1 0))

it prints out the element in second row first column.

The matrix a looks like this

a =
((0 1 2)
(3 4 5)
(6 7 8))

and I was hoping you can show me exactly how to write a dotimes loop or other loop that would in as few lines as possible would print out the matrix using the get-real-2d function so the output looks like this:

0 1 2 
3 4 5
6 7 8

I'm just hoping you can show me a slick loop that would be real small that I can use to print matrices that I can use in my lisp library something real professional looking, like one that would use only variables. Something like:

(format t "~a" (get-real-2d i j))

instead of a bunch of:

(format t "~a" (get-real-2d 0 0))
(format t "~a" (get-real-2d 0 1))
(format t "~a" (get-real-2d 0 2))

;;;;LATEST EDIT;;; to make this simple I call

(defparameter a (create-mat 3 3 +32fc1+))

to create a 3x3 matrix - create-mat is a wrapper for opencv's cvCreateMat

the output from that command at repl is

(defparameter a (create-mat 3 3 +32fc1+))
A
CL-OPENCV> a
#.(SB-SYS:INT-SAP #X7FFFD8000E00)

i/e the variable a is a pointer to the 3x3 matrix

then I run

(defparameter data (cffi:foreign-alloc :float :initial-contents 
          '(0.0f0 1.0f0 2.0f0 3.0f0 4.0f0 5.0f0 6.0f0 7.0f0 8.0f0)))

to create the data for the matrix - which I next will allocate to the matrix

the output from that command at repl is

CL-OPENCV> (defparameter data (cffi:foreign-alloc :float :initial-contents 
          '(0.0f0 1.0f0 2.0f0 3.0f0 4.0f0 5.0f0 6.0f0 7.0f0 8.0f0)))
DATA
CL-OPENCV> data
#.(SB-SYS:INT-SAP #X7FFFD8000E40)

i/e the variable a is data pointer to the data ill add to the matrix

then I call..

(set-data a data 12) to add the data to the matrix - set-data is a wrapper for opencv's cvSetData

so now when I run - (get-real-2d is a wrapper for opencv's cvGetReal2d)

(get-real-2d a 0 0)  it gets the element of matrix a at row 0 col 0 which is 0.0d0

the output from that command at repl is

CL-OPENCV> (get-real-2d a 0 0)
0.0d0

and now when I run

(get-real-2d a 0 1)  it gets the element of matrix a at row 0 col 1 which is is 0.0d0

the output from that command at repl is

CL-OPENCV> (get-real-2d a 0 1)
1.0d0

and when I run this loop

 (dotimes (i 3)
  (dotimes (j 3)
(format t "~a~%" (get-real-2d a i j))))

the output from that command at repl is

CL-OPENCV> (dotimes (i 3)
  (dotimes (j 3)
(format t "~a~%" (get-real-2d a i j))))
0.0d0
1.0d0
2.0d0
3.0d0
4.0d0
5.0d0
6.0d0
7.0d0
8.0d0
NIL

but when I try your method @Svante

(dotimes (i 3)
  (dotimes (j 3)
(format t "~{~{~a~^ ~}~%~}" (get-real-2d a i j))))

I get error:

The value 0.0d0 is not of type LIST.
    [Condition of type TYPE-ERROR]

because the output of 1 run of get-real-2d is just a 1 number float i/e

CL-OPENCV> (get-real-2d a 0 0)
0.0d0

with that info can you help me print the matrix so it looks like this

0.0d0 1.0d0 2.0d0 
3.0d0 4.0d0 5.0d0
6.0d0 7.0d0 8.0d0

Solution

  • Your question can be understood in two ways, and that is why it has two solutions:

    • Define method for printing object of type matrix (in this case it may use the knowledge about the internal structure of matrix):

      (defmethod print-object ((matrix matrix) stream)
          (format stream "~{~{~a~^ ~}~%~}" matrix))
      

      Using format as is shown in the answers.

    • Define client function that can use the only method of your object - get-real-2d:

      (defun print-matrix (matrix dimension-x dimension-y)
          (dotimes (x dimension-x)
              (dotimes (y dimension-y)
                  (princ (get-real-2d matrix x y))
                  (princ #\Space))
              (princ #\Newline)))
      

      Just using dotimes.