MAGIKS  1.1
Manipulator General Inverse Kinematic Solver
 All Classes Namespaces Files Functions Variables Pages
vectors_and_matrices.py
Go to the documentation of this file.
1 ## @file vectors_and_matrices.py
2 # @brief This module provides some useful functions dealing with numpy vectors and matrices
3 # @author Nima Ramezani Taghiabadi
4 #
5 # PhD Researcher
6 # Faculty of Engineering and Information Technology
7 # University of Technology Sydney (UTS)
8 # Broadway, Ultimo, NSW 2007, Australia
9 # Phone No. : 04 5027 4611
10 # Email(1) : nima.ramezani@gmail.com
11 # Email(2) : Nima.RamezaniTaghiabadi@uts.edu.au
12 # @version 5.0
13 #
14 # Last Revision: 03 January 2015
15 
16 import sys, math, numpy as np
17 
18 import general_python as genpy
19 from math_tools import general_math as gen
20 from math_tools.geometry import trigonometry as trig
21 import matplotlib.pyplot as plt
22 
23 def colmax(M):
24  '''
25  returns the maximums of each column in a vector
26  '''
27  (m,n) = M.shape
28  cm = []
29 
30  for j in range(n):
31  cm = []
32  cm.append(max(M[:,j]))
33 
34  return cm
35 
36 def colmin(M):
37  '''
38  returns the minimums of each column in a vector
39  '''
40  (m,n) = M.shape
41  cm = []
42 
43  for j in range(n):
44  cm = []
45  cm.append(min(M[:,j]))
46 
47  return cm
48 
49 def plot_matrix(M, xlabel = None, ylabels = None, annotate = False, legend = True, annx = None, anny = None):
50  (m,n) = M.shape
51 
52  if annotate and (annx == None):
53  max_x = max(M[:,0])
54  min_x = min(M[:,0])
55  hx = max_x - min_x
56 
57  max_y = max(colmax(M[:,1:n]))
58  min_y = min(colmin(M[:,1:n]))
59  hy = max_y - min_y
60 
61  annx = []
62  anny = []
63  for j in range (n-1):
64  i = (j+1)*m*9/(n*10)
65  annx.append(M[i,0])
66  anny.append(M[i,j+1])
67  print 'Annotate ', i, ylabels[j] , ' at: ', annx[j], anny[j]
68 
69  for j in range(n - 1):
70  plt.plot(M[:,0], M[:,j+1])
71  if annotate:
72  plt.annotate(ylabels[j], xy=(annx[j], anny[j]), xytext=(annx[j]+0.1*hx, anny[j]+0.1*hy), arrowprops=dict(facecolor='black', shrink=0.2), )
73  plt.plot(annx, anny, 'x', color = 'black')
74  if legend:
75  '''
76  I should work on that ...
77  '''
78  plt.legend()
79  plt.show()
80 
81 '''
82 use mgv
83 # global variables:
84 f0 = float(0)
85 f1 = float(1)
86 '''
87 err_code = 0
88 
89 def rep(a, n):
90  '''
91  returns a numpy vector of length n containing a (all elements of the vector will be a)
92  '''
93  v = np.zeros(n)
94  for i in range(n):
95  v[i] = a
96  return v
97 
98 def as_matrix(v):
99  '''
100  gets vector v with n^2 elements and returns n*n matrix
101  '''
102  n_2 = len(v)
103  n = int(math.sqrt(n_2))
104  R = np.zeros((n,n))
105  for i in range(n):
106  for j in range(n):
107  print "n*i + j = ", n*i + j
108  print "R = ", v, n_2, n, R
109 
110  R[i,j] = v[n*i + j]
111  return R
112 
113 
114 def value_to_str( value, format="%.3f" ):
115  if int(value) == value :
116  return str(value)
117  else :
118  return str(format%value)
119 
120 def values_to_str( list_of_vals, format="%.3f" ) :
121  '''
122  parametrized usage of sprintf
123  '''
124  formatted = []
125  for v in list_of_vals :
126  formatted.append(value_to_str(v, format))
127  return formatted
128 
129 def vector_to_str( vector, format="%.3f" ) :
130  '''
131  previous name: format_vector
132  parametrized usage of sprintf
133  '''
134  n = len(vector)
135  formatted = np.zeros((n))
136 
137  for i in range(n):
138  formatted[i] = format%vector[i]
139  return str(formatted)
140 
141 def matrix_to_str( matrix, format="%.3f" ) :
142  '''
143  parametrized usage of sprintf
144  '''
145  m = matrix.shape[0]
146  n = matrix.shape[1]
147  formatted = np.zeros((m,n))
148 
149  for i in range(m):
150  for j in range(n):
151  formatted[i,j] = format%matrix[i,j]
152  return str(formatted)
153 
154 def which(v, condition, value):
155  '''
156  Returns the positions of those elements of vector v which satisfy the given condition with the given value
157  condition is a string and must be in: '>', '>=', '<', '=='
158 
159  '''
160  s = []
161  for i in range(len(v)):
162  if condition == '<':
163  flag = (v[i] < value)
164  elif condition == '>':
165  flag = (v[i] > value)
166  elif condition == '==':
167  flag = (v[i] == value)
168  elif condition == '<=':
169  flag = (v[i] <= value)
170  elif condition == '>=':
171  flag = (v[i] >= value)
172  else:
173  assert False, "Error from vectors_and_matrices.which(): "+ condition+ " is an unknown condition."
174  if flag:
175  s.append(i)
176 
177  return s
178 
179 def remove(v, positions):
180  '''
181  Removes the items from v whose positions are specified in given array "positions" and returns the filtered vector
182  '''
183  w = []
184  for i in range(len(v)):
185  if not (i in positions):
186  w.append(v[i])
187  return w
188 
190  '''
191  equivalent to np.dot( A, np.diag(v) )
192 
193  multiplies each column of matrix A by the corresponding element in vector v.
194  This is equivalent to A*diag(v) but requires less calculations
195 
196  return np.dot( A, np.diag(v) )
197  '''
198  m = A.shape[0]
199  n = A.shape[1]
200  assert n == len(v)
201  Adiagv = np.zeros((m,n))
202  for i in range(0,m):
203  for j in range(0,n):
204  Adiagv[i,j] = A[i,j]*v[j]
205  return Adiagv
206 
207 def normalize(v):
208  '''
209  Returns the unit vector parallel to the given vector.
210  '''
211  l = np.linalg.norm(v)
212  if gen.equal(l, 0.0):
213  return(v)
214  else:
215  return(v/l)
216 
217 def linear_map(q, f, g):
218  '''
219  return the linear mapping of vector q by coefficients f and g
220 
221  u = (q - g) / f
222 
223  This code should be implemented before:
224 
225  for i in range(0,len(f[i])):
226  if abs(f[i]) < mgvlib.epsilon:
227  print 'Error 01: Division by zero occured'
228  print 'Something is wrong with the joint limits or the joint limit multipliers'
229  print 'Make sure that the joint limits are well defined, and method "initialize" of the manipulator configuration has been implemented'
230  assert False
231  '''
232 
233  u = (q - g) / f
234  return u
235 
236 def inner_product(v1, v2):
237  '''
238  returns the inner product of the two vectors v1 and v2
239  '''
240  return np.sum(v1*v2)
241 
242 def as_vector(v):
243  '''
244  Returns a numpy array equal to v. Input argument v must be a normal array of numbers
245  '''
246  return(np.array(v))
247 
248 def vectors_angle(v1, v2, in_degrees = False, positive_direction = np.zeros(3)):
249  '''
250  Returns the angle between two vectors. The positive direction, specifies which halfspace is used as positive vectors for the cross product of u and v
251  if not specified, the returned angle will be always positive.
252  If specified, then if the sign of the returned angle is the same as the inner product of positive_direction and crossproduct(v1,v2)
253  '''
254 
255  l_v1 = np.linalg.norm(v1)
256  l_v2 = np.linalg.norm(v2)
257  assert not general.equal(l_v1, 0.0)
258  assert not general.equal(l_v2, 0.0)
259 
260  cos_theta = inner_product(v1, v2)/(l_v1*l_v2)
261 
262  theta = trigonometry.arccos(cos_theta)
263  if general.equal(np.linalg.norm(positive_direction), 0.0):
264  return(theta)
265  else:
266  return math.copysign(theta, inner_product(np.cross(v1, v2), positive_direction))
267 
268 def linear_map_inv(u,f,g):
269  '''
270  return the inverse linear mapping of vector u by coefficients f and g
271 
272  q = f * u + g
273  '''
274  q = f * u + g
275  return q
276 
277 def diag_old(v):
278  '''
279  return an square diagonal matrix whose diagonal elements are elements of vector v
280  '''
281  # np.diag : Use k>0 for diagonals above the main diagonal, and k<0 for diagonals below the main diagonal.
282  return np.diag(v, k = 0 )
283 
284 
286  '''
287  elementwise multiplication of two vectors.
288 
289  !!! http://www.scipy.org/NumPy_for_Matlab_Users !!!
290  '''
291  return v1 * v2
292 
293 
295  '''
296  returns a three element vector containing the first three elements of v4
297  '''
298  return v4[0:3]
299 
301  '''
302  get a three element vector and add one element to its end. Return a four element vector
303  '''
304  v4 = np.zeros((4))
305  for i in range(0,3):
306  v4[i] = v3[i]
307  v4[3] = 1
308  return v4
309 
310 def equal(v1,v2, epsilon = gen.epsilon):
311  '''
312  Returns 1 if two vectors or matrices are equal otherwise returns 0
313  '''
314  return (np.linalg.norm(v1-v2) < epsilon)
315 
316 def uvect(TRM,m):
317  '''
318  uvect is a shorted phrase of "unit vector"
319 
320  Returns a vector (3 X 1) containing the first three elements of the m-th column of transformation matrix TRM.
321  (TRM is the 4*4 transformation matrix or a 3X3 rotation matrix)
322  If m is in [0,1,2] the m-th unit vector is returned. If m is 3, then the function returns the position vector
323  '''
324  return TRM[ 0:3,m ]
325 
327  '''
328  Returns the rotation matrix (3 X 3) extracted from transformation matrix TRM. TRM is a 4*4 matrix
329  '''
330  return TRM[ 0:3, 0:3 ]
331 
332 def cross_old(u,v):
333  '''
334  Return the cross product of two vectors u and v. u and v are (3 element) vectors
335  '''
336  return np.cross(u,v)
337 
338 def extended_matrix( R, p ):
339  '''
340  Convert a (3 X 3) rotation matrix into a (4 X 4) transformation matrix. The added elements will be zero
341  '''
342  em = np.zeros((4,4))
343  for i in range(0,3):
344  em[i,3] = p[i]
345  em[3,i] = 0
346  for j in range(0,3):
347  em[i,j] = R[i,j]
348  return em;
349 
351  '''
352  Return the right pseudo-inverse of matrix J
353  J^T*(J*J^T)^(-1)
354  --> take a look at ! np.linalg.pinv(a) !
355  '''
356  A = np.dot(J,J.T);
357  Jinv = np.dot(J.T,np.linalg.inv(A))
358  return Jinv
359 
361  '''
362  Return the left pseudo-inverse of matrix J
363  (J^T*J)^(-1)*J^T
364  '''
365  A = np.dot(J.T,J);
366  Jinv = np.dot(np.linalg.inv(A), J.T)
367  return Jinv
368 
370  '''
371  returns the right side damped least square inverse of matrix M. k is the damping factor:
372 
373  M^T * [M*M^T + (k^2)*I]^(-1)
374 
375  '''
376  m = M.shape[0]
377  A = np.dot(M, M.T);
378 
379  Minv = np.dot(M.T, np.linalg.inv(A + k*k*np.eye(m)))
380  return Minv
381 
383  '''
384  returns the left side damped least square inverse of matrix M. k is the damping factor:
385 
386  [M^T*M + (k^2)*I]^(-1) * M^T
387 
388  --> take a look at ! np.linalg.pinv(a, rcond=1.0000000000000001e-15) !
389  '''
390  m = M.shape[1]
391  A = np.dot(M.T, M);
392 
393  Minv = np.dot(np.linalg.inv(A + k*k*np.eye(m)), M.T)
394  return Minv
395 
397  return np.dot(np.dot(W,M.T),np.linalg.inv(np.dot(np.dot(M,W),M.T)))
398 
399 def weighted_dls_inverse(M, W = None, k = 0.0):
400  m = M.shape[0]
401  n = M.shape[1]
402  if W == None:
403  W = np.eye(n)
404  return np.dot(np.dot(W,M.T),np.linalg.inv(k*k*np.eye(m) + np.dot(np.dot(M,W),M.T)))
405 
406 
407 def clamp(v, max_norm):
408  '''
409  if the magnitude(norm) of the given vector is smaller than max_norm, the given vctor is returned
410  otherwise a vector parallel to v with norm max_norm is returned
411  '''
412  l = np.linalg.norm(v)
413  if l > max_norm:
414  return v*max_norm/l
415  else:
416  return v
417 
418 ## Use this function to check if all elements of a given vector are positive
419 def positive(v, non_zero = False):
420  permit = True
421  n = len(v)
422  i = 0
423  while permit and (i < n):
424  permit = permit and (v[i] >= 0) and (not (non_zero and gen.equal(v[i], 0.0)))
425  i += 1
426  return permit
427 
428 def feasible_stepsize(direction, x, x_min, x_max):
429  '''
430  when the correction of vector x is restricted by limits
431  If you want to change vector x in a desired direction, and there are lower and upper bounds for x,
432  how much are you allowed to change?
433  This function returns a feasible stepsize for the given direction.
434  The direction of change must be multiplied by a scalar value lower or equal to this feasible stepsize
435  so that the applied changes are feasible.
436  '''
437  valtyp = [np.ndarray, list, tuple]
438  direction = genpy.check_type(direction, valtyp, __name__, function_name = sys._getframe().f_code.co_name, var_name = 'direction', shape_length = 1)
439  n = len(direction)
440  [x, x_min, x_max] = genpy.check_types(variables = [x,x_min,x_max], type_lists = [valtyp,valtyp,valtyp],
441  file_path = __name__, function_name = sys._getframe().f_code.co_name,
442  var_names = ['x', 'x_min', 'x_max'], shape_lengths = [1,1,1], array_lengths = [n,n,n])
443 
444  etta = []
445  for i in range(n):
446  if not gen.equal(direction[i], 0.0, epsilon = 0.000000001):
447  if x_min[i] == None:
448  x_min[i] = - np.inf
449  if x_max[i] == None:
450  x_max[i] = np.inf
451 
452  a = (x_min[i] - x[i])/direction[i]
453  b = (x_max[i] - x[i])/direction[i]
454  etta.append(gen.sign_choice(b, a, direction[i]))
455  else:
456  etta.append(np.inf)
457 
458  if etta[len(etta)-1] < 0:
459  print 'x_min: ', x_min
460  print 'x_max: ', x_max
461  print 'x: ', x
462  print 'dir: ', direction
463 
464  if etta == []:
465  return 0.0
466  else:
467  return min(etta)
468 
469 def va_mean(vectarray):
470  n = len(vectarray)
471  s = vectarray[0]
472  for i in range(n - 1):
473  s += vectarray[i + 1]
474  return s/n
475 
476 def va_shiftappend(vectarray, v_new):
477  n = len(vectarray)
478  for i in range(n - 1):
479  vectarray[i] = vectarray[i+1]
480  vectarray[n - 1] = v_new
481  return vectarray
482 
def positive
Use this function to check if all elements of a given vector are positive.