from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import sys
try:
import System
except ImportError:
if 'ironpython' in sys.version.lower():
raise
__author__ = ['Tom Van Mele', ]
__copyright__ = 'Copyright 2016 - Block Research Group, ETH Zurich'
__license__ = 'MIT License'
__email__ = 'vanmelet@ethz.ch'
__all__ = ['MatlabClient']
[docs]class MatlabClient(object):
"""Communicate with Matlab through Windows' COM interface.
Parameters
----------
verbose : bool
If ``True``, all commands and results will be printed in the Python console.
Default is ``False``.
interactive : bool
If ``True``, a Matlab console window will be visible.
Default is ``False``.
workspace : str
The name of the Matlab workspace.
Default is ``'base'``.
Notes
-----
This implementation uses Windows' COM interface to communicate with Matlab.
Therefore, it is obviously only available on Windows.
When an instance of this class is created, it automatically connects to Matlab,
and initializes a lease that keeps the interface alive for at least 5 minutes
such that subsequent calls can be executed immediately.
After every call, the lease is renewed...
Examples
--------
>>> matlab = MatlabClient(interactive=True)
>>> A = matlab.matrix_from_list([[1, 0, 1, 3], [2, 3, 4, 7], [-1, -3, -3, -4]])
>>> matlab.put('A', A)
>>> matlab.eval('[R, jb] = rref(A);')
>>> R = matlab.get('R')
>>> jb = matlab.get('jb')
>>> print(R)
>>> print(jb)
See Also
--------
compas.com.mlab.MatlabEngine
compas.com.mlab.MatlabSession
compas.com.mlab.MatlabProcess
"""
[docs] def __init__(self, verbose=False, interactive=False, workspace='base'):
self._type = None
self._app = None
self._lease = None
self.verbose = verbose
self.interactive = interactive
self.workspace = workspace
self.init()
[docs] def init(self):
self._create_instance()
self._init_lease()
def _create_instance(self):
self._type = System.Type.GetTypeFromProgID('Matlab.Application')
self._app = System.Activator.CreateInstance(self._type)
self._app.Visible = self.interactive
def _init_lease(self):
self._lease = self._app.InitializeLifetimeService()
self._lease.InitialLeaseTime = System.TimeSpan.FromMinutes(5.0)
self._lease.RenewOnCallTime = System.TimeSpan.FromMinutes(5.0)
def _renew_lease(self):
self._lease.Renew(System.TimeSpan.FromMinutes(5.0))
def _get_vector(self, name):
_value = self._app.GetVariable(name, self.workspace)
try:
_value.Rank
except AttributeError:
value = _value
else:
value = MatlabClient.list_from_vector(_value)
self._renew_lease()
return value
def _get_matrix_size(self, name):
self._app.Execute('[m, n] = size({0});'.format(name))
m = self._app.GetVariable('m', self.workspace)
n = self._app.GetVariable('n', self.workspace)
return int(m), int(n)
# ==========================================================================
# static methods
# ==========================================================================
[docs] @staticmethod
def vector_from_list(a, dtype=float):
"""Make a Matlab-compatible vector from a list.
Parameters
----------
a : list
The input list.
dtype : object
The data type constructor function.
Default is ``float``.
Returns
-------
System.Array
The vector.
Examples
--------
>>> MatlabClient.vector_from_list([1, 2, 3], dtype=float)
"""
n = len(a)
vector = System.Array.CreateInstance(dtype, n)
for i in range(n):
vector[i] = a[i]
return vector
[docs] @staticmethod
def vector_from_array(a):
"""Make a Matlab-compatible vector from a (Numpy) array.
Parameters
----------
a : ndarray
The input array.
Returns
-------
System.Array
The vector.
Examples
--------
>>>
"""
raise NotImplementedError
[docs] @staticmethod
def matrix_from_list(A, dtype=float):
"""Make a Matlab-compatible matrix from a list of lists.
Parameters
----------
A : list of list
The input list.
dtype : object
The data type constructor function.
Default is ``float``.
Returns
-------
System.Array
The matrix.
Examples
--------
>>>
"""
m = len(A)
n = len(A[0])
if not all([len(row) == n for row in A]):
raise Exception('Matrix dimensions inconsistent.')
matrix = System.Array.CreateInstance(dtype, m, n)
for row in range(m):
for col in range(n):
matrix[row, col] = A[row][col]
return matrix
[docs] @staticmethod
def matrix_from_array(a):
"""Make a Matlab-compatible matrix from a (Numpy) array.
Parameters
----------
a : ndarray
The input array.
Returns
-------
System.Array
The matrix.
Examples
--------
>>>
"""
raise NotImplementedError
[docs] @staticmethod
def list_from_vector(a):
"""Convert a Matlab vector to a Python list."""
return list(a)
[docs] @staticmethod
def list_from_matrix(A, m, n):
"""Convert a Matlab matrix to a Python list."""
nlist = []
for row in range(m):
nlist.append([None] * n)
for col in range(n):
nlist[row][col] = A[row, col]
return nlist
[docs] @staticmethod
def double(a):
try:
len(a[0])
except TypeError:
return MatlabClient.vector_from_list(a, dtype=float)
else:
return MatlabClient.matrix_from_list(a, dtype=float)
# ==========================================================================
# methods
# ==========================================================================
[docs] def eval(self, cmd):
"""Evaluate a command from a string.
Parameters
----------
cmd : str
The command string.
Examples
--------
>>> matlab = MatlabClient(verbose=True)
>>> matlab.eval('isprime(13);')
True
"""
res = self._app.Execute(cmd)
if self.verbose:
print(res)
self._renew_lease()
[docs] def put(self, name, value):
"""Put a variable in the Matlab workspace.
Parameters
----------
name : str
The name of the variable.
value : ...
The value of the variable.
Examples
--------
>>> m = MatlabClient(verbose=True, interactive=True)
>>> m.put('A', m.matrix([[1, 0, 1, 3], [2, 3, 4, 7], [-1, -3, -3, -4]]))
>>> m.put()
>>> m.put()
"""
try:
res = self._app.PutFullMatrix(name, self.workspace, value, None)
except Exception:
res = self._app.PutWorkspaceData(name, self.workspace, value)
if self.verbose:
print(res)
self._renew_lease()
[docs] def get(self, name):
"""Get the value of a variable in the workspace.
Parameters
----------
name : str
The name of the variable.
Returns
-------
str, int, float, list
The value of the variable.
Examples
--------
>>> m = MatlabClient(verbose=True)
>>> m.get('A')
[[1, 0, 1, 3], [2, 3, 4, 7], [-1, -3, -3, -4]]
"""
_value = self._app.GetVariable(name, self.workspace)
try:
_value.Rank
except AttributeError:
value = _value
else:
value = []
if _value.Rank == 1:
value = MatlabClient.list_from_vector(_value)
elif _value.Rank == 2:
m, n = self._get_matrix_size(name)
value = MatlabClient.list_from_matrix(_value, m, n)
self._renew_lease()
return value
# ==============================================================================
# Main
# ==============================================================================
if __name__ == "__main__":
matlab = MatlabClient(interactive=True)
A = MatlabClient.matrix_from_list([[1, 0, 1, 3], [2, 3, 4, 7], [-1, -3, -3, -4]])
matlab.put('A', A)
matlab.eval('[R, jb] = rref(A);')
R = matlab.get('R')
jb = matlab.get('jb')
print(R)
print(jb)