File: wrap.lisp

package info (click to toggle)
clisp 1%3A2.41-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 49,804 kB
  • ctags: 16,291
  • sloc: lisp: 75,912; ansic: 49,247; xml: 24,289; asm: 21,993; sh: 11,234; fortran: 6,692; cpp: 2,660; objc: 2,481; makefile: 2,355; perl: 164; sed: 55
file content (101 lines) | stat: -rw-r--r-- 3,972 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
;;; Lisp wrappers for the Matlab API
;;; <http://www.mathworks.com/access/helpdesk/help/techdoc/apiref/apiref.shtml>

(require "matlab")

(in-package "MATLAB")

(pushnew :matlab *features*)

(defun matfile-content (mf)
  "return the vector of strings naming variables in MATfile"
  (multiple-value-bind (buf num) (matGetDir mf)
    (unwind-protect
         (with-c-var (names `(c-ptr (c-array c-string ,num)))
           (setf (cast names 'c-pointer) buf)
           names)
      (mxFree buf))))

(defvar *command* ""
  "The path to pass to engOpen().")
(defvar *engine* nil
  "The current matlab engine.")

(defmacro with-engine ((&optional (eng '*engine*) (cmd '*command*)) &body body)
  "open a matlab engine, do BODY, close the engine"
  `(let ((,eng (engOpen ,cmd)))
     (unwind-protect (progn ,@body)
       (when ,eng (engClose ,eng)))))

(defun engine (&optional (cmd *command*))
  "ensure that we have a working matlab engine"
  (or *engine* (setq *engine* (engOpen cmd))))

(defmacro with-MATfile ((file name &optional (mode "r")) &body body)
  "open a MAT file, do BODY, close the file"
  `(let ((,file (matOpen ,name ,mode)))
     (unwind-protect (progn ,@body)
       (when ,file (matClose ,file)))))

(defun copy-lisp-to-mxArray (lisp-mx &optional mx-array)
  "copy the data in the matrix into the matlab mxArray.
the dimensions should be compatible.
if the destination does not exist, it is created."
  (let ((d0 (array-dimension lisp-mx 0)) (d1 (array-dimension lisp-mx 1)))
    (if mx-array
        (assert (and (= d0 (mxGetM mx-array)) (= d1 (mxGetN mx-array)))
                (mx-array) "Incompatible dimensions: ~Dx~D vs ~Dx~D"
                d0 d1 (mxGetM mx-array) (mxGetN mx-array))
        (setq mx-array (mxCreateDoubleMatrix d0 d1 mxREAL)))
    (assert (mxGetData mx-array) (mx-array) "~S: there is no data in ~S"
            'copy-mxArray-to-lisp mx-array)
    (unless (mxGetData mx-array)
      (error "~S: there is no data in ~S" 'copy-mxArray-to-lisp mx-array))
    (loop :for i :from 0 :below d0 :do
      (loop :for j :from 0 :below d1 :do
        (setf (mx-aref-r mx-array i j d0)
              (coerce (aref lisp-mx i j) 'double-float))))
    mx-array))

(defun copy-lisp-to-matlab (lisp-mx var &key ((:engine *engine*) (engine)))
  "copy the lisp matrix to the matlab variable"
  (let ((mmx (copy-lisp-to-mxArray lisp-mx)))
    (engPutVariable *engine* var mmx)
    (mxDestroyArray mmx)))

(defun copy-mxArray-to-lisp (mx-array &optional lisp-mx)
  "copy the data from the matlab mxArray into the matrix.
the dimensions should be compatible.
if the destination does not exist, it is created."
  (let ((d0 (mxGetM mx-array)) (d1 (mxGetN mx-array)))
    (assert (mxGetData mx-array) (mx-array) "~S: there is no data in ~S"
            'copy-mxArray-to-lisp mx-array)
    (if lisp-mx
        (assert (and (= d0 (array-dimension lisp-mx 0))
                     (= d1 (array-dimension lisp-mx 1)))
                (mx-array) "Incompatible dimensions: ~Dx~D vs ~Dx~D"
                d0 d1 (array-dimension lisp-mx 0) (array-dimension lisp-mx 1))
        (setq lisp-mx (make-array (list d0 d1))))
    (loop :for i :from 0 :below d0 :do
      (loop :for j :from 0 :below d1 :do
        (setf (aref lisp-mx i j)
              (mx-aref-r mx-array i j d0))))
    lisp-mx))

(defun copy-matlab-to-lisp (var &optional lisp-mx
                            &key ((:engine *engine*) (engine)))
  "copy the matlab variable to the lisp matrix"
  (let ((mmx (engGetVariable *engine* var)))
    (setq lisp-mx (copy-mxArray-to-lisp mmx lisp-mx))
    (mxDestroyArray mmx)
    lisp-mx))

(defun invert-matrix (lisp-mx &key ((:engine *engine*) (engine)))
  "open an engine, compute the matrix inverse (in place), close engine"
  (copy-lisp-to-matlab lisp-mx "mx")
  (engEvalString *engine* "mx=inv(mx);")
  (copy-matlab-to-lisp "mx" lisp-mx)
  (engEvalString *engine* "clear mx;")
  lisp-mx)

(pushnew "MATLAB" custom:*system-package-list* :test #'string=)