MAGIKS  1.1
Manipulator General Inverse Kinematic Solver
 All Classes Namespaces Files Functions Variables Pages
log_manager.py
Go to the documentation of this file.
1 # HEADER
2 
3 ## @file log_manager.py
4 # @brief This module provides classes containing data structure for IK test log data
5 # @author Nima Ramezani Taghiabadi
6 #
7 # PhD Researcher
8 # Faculty of Engineering and Information Technology
9 # University of Technology Sydney (UTS)
10 # Broadway, Ultimo, NSW 2007, Australia
11 # Phone No. : 04 5027 4611
12 # Email(1) : nima.ramezani@gmail.com
13 # Email(2) : Nima.RamezaniTaghiabadi@uts.edu.au
14 # @version 3.0
15 #
16 # Last Revision: 03 January 2015
17 
18 # BODY
19 import math, pickle
20 
21 from math_tools.algebra import vectors_and_matrices as vecmat
22 from math_tools.statistics import statistics
23 
24 # \cond
25 key_dic = {
26  # Forward:
27  # For Test_Log_Data_Single_Run():
28 
29  'TPN' : 'Target Pose Number',
30  'S' : 'Success',
31  'CIR' : 'Configuration in Range',
32  'NSPT' : 'Number of Starting Point Trials',
33  'NI' : 'Number of Iterations',
34  'NS' : 'Number of Success',
35  'RT' : 'Running Time (ms)',
36  'TRT' : 'Total Running Time (ms)',
37  'ART' : 'Average Running Time (ms)',
38  'TNI' : 'Total Number of Iterations',
39  'ANI' : 'Average Number of Iterations',
40  'PS' : 'Percentage of Success', # percentage of success until now (This field exists in Test_Log_Data_Statistics() and contains per.Suc. for all runs
41  'IC' : 'Initial Configuration',
42  'FC' : 'Final Configuration',
43  'IP' : 'Initial Pose',
44  'FP' : 'Final Pose',
45 
46  # For Test_Log_Data_Statistics():
47  'PSIR' : 'Percentage of Success in Range', # percentage of successful runs in range
48  'NRun' : 'Number of Runs',
49  'NSRun' : 'Number of Successful Runs',
50  'NIR' : 'Number of Runs in Range',
51  'NSIR' : 'Number of Successful Runs in Range',
52  'NI-tot': 'Number of Iterations-Total',
53  'NI-max': 'Number of Iterations-Maximum',
54  'NI-min': 'Number of Iterations-Minimum',
55  'NI-avr': 'Number of Iterations-Average',
56  'NI-med': 'Number of Iterations-Median',
57  'NI-sdv': 'Number of Iterations-Standard Deviation',
58  'NI-mse': 'Number of Iterations-Mean Standard Error',
59  'NT-max': 'Number of Trials-Maximum',
60  'NT-min': 'Number of Trials-Minimum',
61  'NT-avr': 'Number of Trials-Average',
62  'RT-tot': 'Running Time-Total (ms)',
63  'RT-max': 'Running Time-Maximum (ms)',
64  'RT-min': 'Running Time-Minimum (ms)',
65  'RT-avr': 'Running Time-Average (ms)',
66  'RT-med': 'Running Time-Median (ms)',
67  'RT-sdv': 'Running Time-Standard Deviation (ms)',
68  'RT-mse': 'Running Time-Mean Standard Error',
69 
70  #Inverse:
71 
72  # For Test_Log_Data_Single_Run():
73  'Target Pose Number' : 'TPN',
74  'Success' : 'SUC',
75  'Number of Starting Point Trials' : 'NSPT',
76  'Number of Iterations' : 'NI',
77  'Number of Success' : 'NS',
78  'Running Time (ms)' : 'RT',
79  'Total Running Time (ms)' : 'TRT',
80  'Average Running Time (ms)' : 'ART',
81  'Total Number of Iterations' : 'TNI',
82  'Average Number of Iterations' : 'ANI',
83  'Percentage of Success' : 'PS',
84  'Initial Configuration' : 'IC',
85  'Final Configuration' : 'FC',
86  # For Test_Log_Data_Statistics():
87 
88  'Number of Iterations-Total' : 'NI-tot',
89  'Number of Iterations-Maximum' : 'NI-max',
90  'Number of Iterations-Minimum' : 'NI-min',
91  'Number of Iterations-Average' : 'NI-avr',
92  'Number of Iterations-Standard Deviation' : 'NI-sdv',
93  'Number of Iterations-Mean Standard Error' : 'NI-mse',
94  'Number of Trials-Maximum' : 'NT-max',
95  'Number of Trials-Minimum' : 'NT-min',
96  'Number of Trials-Average' : 'NT-avr',
97  'Running Time-Total (ms)' : 'RT-tot',
98  'Running Time-Maximum (ms)' : 'RT-max',
99  'Running Time-Minimum (ms)' : 'RT-min',
100  'Running Time-Average (ms)' : 'RT-avr',
101  'Running Time-Standard Deviation (ms)' : 'RT-sdv',
102  'Running Time-Mean Standard Error' : 'RT-mse'
103  }
104 
105 class Single_Run_Log():
106  '''
107  Contains data structure for evaluation test results for a single run associated with a target pose in PPS
108  Including:
109  Initial Status (Configuration, Endeffector Pose, Values of error functions)
110  Final Status (Configuration, Endeffector Pose, Values of error functions)
111 
112  '''
113 
114  def __init__(self, pose_number, success = False, config_in_range = False):
115 
116  # Index of target pose in the target pose workspace
117  self.target_pose_num = pose_number
118  # Number of starting point trials for this target pose
119  self.num_trial = 0
120  # Number of successful attempts until now
121  self.num_suc_til_now = 0
122  # Boolean property indicating if the implementation was successful or not
123  self.success = success
124  self.config_in_range = config_in_range
125 
126  # Number of iterations for this target pose
127  self.num_iter = 0
128  # Total number of iterations until now
129  self.num_iter_til_now = 0
130 
131  # Running time for this configuration
132  self.run_time = 0.0
133  # Total running time until now
134  self.run_time_til_now = 0.0
135  # Average running time for one iteration
136  self.mean_stp_time = 0.0
137 
138  self.start_config_str = ''
139  self.final_config_str = ''
140  self.start_pose_str = ''
141  self.final_pose_str = ''
142  self.str_parameter_set = ['TPN', 'S', 'CIR', 'NSPT', 'NI', 'RT','NS', 'TRT', 'ART', 'TNI', 'ANI','PS', 'IC', 'FC', 'IP', 'FP']
143  self.csv_parameter_set = ['TPN', 'S', 'CIR', 'NSPT', 'NI', 'RT','NS', 'TRT', 'ART', 'TNI', 'ANI', 'PS']
144 
145  def parameter_value(self, parameter):
146  if parameter == 'TPN':
147  return str(self.target_pose_num)
148  elif parameter == 'S':
149  return str(self.success)
150  elif parameter == 'CIR':
151  return str(self.config_in_range)
152  elif parameter == 'NSPT':
153  return str(self.num_trial)
154  elif parameter == 'NI':
155  return str(self.num_iter)
156  elif parameter == 'RT':
157  return str(1000*self.run_time)
158  elif parameter == 'NS':
159  return str(self.num_suc_til_now)
160  elif parameter == 'TRT':
161  return str(1000*self.run_time_til_now)
162  elif parameter == 'ART':
163  return str(1000*self.run_time_til_now/(self.target_pose_num + 1))
164  elif parameter == 'TNI':
165  return str(self.num_iter_til_now)
166  elif parameter == 'ANI':
167  return str(self.num_iter_til_now/(self.target_pose_num + 1))
168  elif parameter == 'PS':
169  return str(100.00*self.num_suc_til_now/(self.target_pose_num + 1))
170  elif parameter == 'IC':
171  return self.start_config_str
172  elif parameter == 'FC':
173  return self.final_config_str
174  elif parameter == 'IP':
175  return '\n' + '------------' + '\n' + self.start_pose_str
176  elif parameter == 'FP':
177  return '\n' + '------------' + '\n' + self.final_pose_str
178 
179  def __str__(self, parameter_set = None):
180  if parameter_set == None:
181  parameter_set = self.str_parameter_set
182  s = '\n'
183  s += 'Test Result:' + '\n\n'
184  for p in parameter_set:
185  value = self.parameter_value(p)
186  param = key_dic[p]
187  s += param + " "*(32-len(param)) +': ' + value + '\n'
188 
189  s += '\n' + '______________________________________________________________________________________________________________________________'
190 
191  return s
192 
193  def csv(self, header = True, parameter_set = None):
194  if parameter_set == None:
195  parameter_set = self.csv_parameter_set
196 
197  if header:
198  s = 'Parameter' + ',' + 'Value' +'\n'
199  else:
200  s = ''
201  for p in parameter_set:
202  value = self.parameter_value(p)
203  s += key_dic[p] + "," + value + '\n'
204  return s
205 
206  def csv_horizontal_header(self, parameter_set = None):
207  if parameter_set == None:
208  parameter_set = self.csv_parameter_set
209  s = ''
210  for p in parameter_set:
211  s += key_dic[p] + ","
212  s = s[0:len(s) - 1]
213  return s
214 
215  def csv_horizontal(self, parameter_set = None):
216  if parameter_set == None:
217  parameter_set = self.csv_parameter_set
218  s = ''
219  for p in parameter_set:
220  s += self.parameter_value(p) + ','
221  s = s[0:len(s) - 1]
222 
223  return s
224 
225  def write_csv(self, filename):
226  print 'Test_Log_Data_Single_Run(): Writing csv file started ...'
227  CSV_FILE_HANDLE = open(filename, "w")
228  CSV_FILE_HANDLE.write(self.csv())
229  print 'Test_Log_Data_Single_Run(): Writing csv file ended.'
230 
231 class Test_Statistics():
232  '''
233  Contains structure for statistical data of evaluation test results for a set of target poses
234  Including:
235  Initial Status (Configuration, Endeffector Pose, Values of error functions)
236  Final Status (Configuration, Endeffector Pose, Values of error functions)
237 
238  '''
239  def __init__(self):
240 
241  self.num_success = 0
242  self.num_inrange = 0
243  self.num_suc_inrange = 0
244  self.num_run = 0
245 
246  self.sum_num_iter = 0 # Total number of iterations for all target poses
247  self.max_num_iter = 0 # Maximum number of iterations
248  self.max_num_iter_pose_number = 0 # Pose number corresponding to maximum number of iterations
249  self.min_num_iter = 1000000 # Minimum number of iterations
250  self.min_num_iter_pose_number = 0 # Pose number corresponding to minimum number of iterations
251 
252  self.sum_num_trial = 0 # Total number of trials for all target poses
253  self.max_num_trial = 0 # Maximum number of trials
254  self.max_num_trial_pose_number = 0 # Pose number corresponding to maximum number of trials
255  self.min_num_trial = 1000000 # Minimum number of trials
256  self.min_num_trial_pose_number = 0 # Pose number corresponding to minimum number of trials
257 
258  self.max_run_time = 0.0
259  self.max_run_time_pose_number = 0 # Pose number corresponding to maximum running time
260  self.min_run_time = 1000000.00
261  self.min_run_time_pose_number = 0 # Pose number corresponding to minimum running time
262  self.sum_run_time = 0.0
263 
264  self.mean_num_iter = 0.0
265  self.mean_num_trial = 0.0
266  self.mean_run_time = 0.0
267  self.mean_stp_time = 0.0
268  self.sd_num_iter = 0.0
269  self.sd_run_time = 0.0
270  self.mse_num_iter = 0.0
271  self.mse_run_time = 0.0
272 
273  self.median_num_iter = 0.0
274  self.median_run_time = 0.0
275 
276  self.str_parameter_set = ['NRun','NSRun','NSIR','PS','NI-tot', 'NI-max', 'NI-min', 'NI-avr','NI-sdv','NI-mse',
277  'NT-max', 'NT-min','NT-avr', 'RT-tot', 'RT-max', 'RT-min', 'RT-avr', 'RT-mse']
278  self.csv_parameter_set = ['PS', 'NI-avr','NI-mse', 'RT-max', 'RT-min', 'RT-avr', 'RT-mse']
279 
280  def parameter_value(self, parameter):
281  if parameter == 'NRun':
282  return str(self.num_run)
283  elif parameter == 'NSRun':
284  return str(self.num_success)
285  elif parameter == 'NSIR':
286  return str(self.num_suc_inrange)
287  elif parameter == 'NIR':
288  return str(self.num_inrange)
289  elif parameter == 'PS':
290  return vecmat.value_to_str(100*self.num_success/float(self.num_run))
291  elif parameter == 'PSIR':
292  return vecmat.value_to_str(100*self.num_suc_inrange/float(self.num_run))
293  elif parameter == 'NI-tot':
294  return str(self.sum_num_iter)
295  elif parameter == 'NI-max':
296  # return str(self.max_num_iter) + " for target pose number: " + str(self.max_num_iter_pose_number)
297  return str(self.max_num_iter)
298  elif parameter == 'NI-min':
299  # return str(self.min_num_iter) + " for target pose number: " + str(self.min_num_iter_pose_number)
300  return str(self.min_num_iter)
301  elif parameter == 'NI-avr':
302  return vecmat.value_to_str(self.mean_num_iter)
303  elif parameter == 'NI-med':
304  return vecmat.value_to_str(self.median_num_iter)
305  elif parameter == 'NI-sdv':
306  return vecmat.value_to_str(self.sd_num_iter)
307  elif parameter == 'NI-mse':
308  return vecmat.value_to_str(self.mse_num_iter)
309  elif parameter == 'NT-max':
310  # return str(self.max_num_trial) + ' for target pose number: ' + str(self.max_num_trial_pose_number)
311  return vecmat.value_to_str(self.max_num_trial)
312  elif parameter == 'NT-min':
313  # return str(self.min_num_trial) + ' for target pose number: ' + str(self.min_num_trial_pose_number)
314  return vecmat.value_to_str(self.min_num_trial)
315  elif parameter == 'NT-avr':
316  return vecmat.value_to_str(self.mean_num_trial)
317  elif parameter == 'RT-tot':
318  return vecmat.value_to_str(1000*self.sum_run_time)
319  elif parameter == 'RT-max':
320  return vecmat.value_to_str(1000*self.max_run_time)
321  elif parameter == 'RT-min':
322  return vecmat.value_to_str(1000*self.min_run_time)
323  elif parameter == 'RT-avr':
324  return vecmat.value_to_str(1000*self.mean_run_time)
325  elif parameter == 'RT-med':
326  return vecmat.value_to_str(1000*self.median_run_time)
327  elif parameter == 'RT-sdv':
328  return vecmat.value_to_str(1000*self.sd_run_time)
329  elif parameter == 'RT-mse':
330  return vecmat.value_to_str(1000*self.mse_run_time)
331  else:
332  assert False, genpy.err_str(__name__, __class__.__name__, 'parameter_value', parameter + ' is an invalid value for parameter')
333 
334  def __str__(self, parameter_set = None):
335  if parameter_set == None:
336  parameter_set = self.str_parameter_set
337  s = '\n'
338  s += 'Test Statistics:' + '\n\n'
339  for p in parameter_set:
340  value = self.parameter_value(p)
341  param = key_dic[p]
342  s += param + " "*(40-len(param)) +': ' + value + '\n'
343 
344  s += '\n' + '______________________________________________________________________________________________________________________________'
345 
346  return s
347 
348  def csv(self, header = True, parameter_set = None):
349  if parameter_set == None:
350  parameter_set = self.csv_parameter_set
351  if header:
352  s = 'Parameter' + ',' + 'Value' +'\n'
353  else:
354  s = ''
355  for p in parameter_set:
356  value = self.parameter_value(p)
357  s += key_dic[p] + "," + value + '\n'
358  return s
359 
360  def csv_horizontal_header(self, parameter_set = None, use_key = False):
361  if parameter_set == None:
362  parameter_set = self.csv_parameter_set
363  s = ''
364  for p in parameter_set:
365  if use_key:
366  s += p + ","
367  else:
368  s += key_dic[p] + ","
369  s = s[0:len(s) - 1]
370  return s
371 
372  def csv_horizontal(self, parameter_set = None):
373  if parameter_set == None:
374  parameter_set = self.csv_parameter_set
375  s = ''
376  for p in parameter_set:
377  s += self.parameter_value(p) + ','
378  s = s[0:len(s) - 1]
379  return s
380 
381  def write_csv(self, filename):
382  print 'Eval_Log_Data_Statistics(): Writing csv file started ...'
383  CSV_FILE_HANDLE = open(filename, "w")
384  CSV_FILE_HANDLE.write(self.csv())
385  print 'Eval_Log_Data_Statistics(): Writing csv file ended.'
386 
387  def calculate_statistics(self, body):
388 
389  self.__init__()
390  sum_stp_time = 0.0
391 
392  self.num_run = len(body)
393  num_iter_list = []
394  num_trial_list = []
395  run_time_list = []
396 
397  for i in range(0, self.num_run):
398  num_iter_list.append(body[i].num_iter)
399  num_trial_list.append(body[i].num_trial)
400  run_time_list.append(body[i].run_time)
401 
402  self.sum_num_iter += body[i].num_iter
403  self.sum_num_trial += body[i].num_trial
404  self.sum_run_time += body[i].run_time
405  sum_stp_time += body[i].mean_stp_time
406 
407  if body[i].num_iter > self.max_num_iter:
408  self.max_num_iter = body[i].num_iter
409  self.max_num_iter_pose_number = i
410  if body[i].num_iter < self.min_num_iter:
411  self.min_num_iter = body[i].num_iter
412  self.min_num_iter_pose_number = i
413 
414  if body[i].num_trial > self.max_num_trial:
415  self.max_num_trial = body[i].num_trial
416  self.max_num_trial_pose_number = i
417  if body[i].num_trial < self.min_num_trial:
418  self.min_num_trial = body[i].num_trial
419  self.min_num_trial_pose_number = i
420 
421  if body[i].run_time > self.max_run_time:
422  self.max_run_time = body[i].run_time
423  self.max_run_time_pose_number = i
424  if body[i].run_time < self.min_run_time:
425  self.min_run_time = body[i].run_time
426  self.min_run_time_pose_number = i
427 
428  assert self.sum_run_time == body[self.num_run - 1].run_time_til_now
429  assert self.sum_num_iter == body[self.num_run - 1].num_iter_til_now
430 
431  self.mean_num_iter = float(self.sum_num_iter) / self.num_run
432  self.mean_num_trial = float(self.sum_num_trial) / self.num_run
433  self.mean_run_time = self.sum_run_time / self.num_run
434  self.mean_stp_time = sum_stp_time / self.num_run
435 
436  self.median_num_iter = statistics.median(num_iter_list)
437  self.median_run_time = statistics.median(run_time_list)
438 
439  sum_var_num_iter = 0
440  sum_var_run_time = 0
441 
442  self.num_inrange = 0
443  self.num_success = 0
444  self.num_suc_inrange = 0
445  for i in range(0, self.num_run):
446 
447  sum_var_num_iter += (float(body[i].num_iter) - self.mean_num_iter) ** 2
448  sum_var_run_time += ( body[i].run_time - self.mean_run_time) ** 2
449 
450  self.num_inrange += body[i].config_in_range
451  self.num_success += body[i].success
452  self.num_suc_inrange += (body[i].config_in_range and body[i].success)
453 
454  if self.num_run > 1:
455  den = self.num_run - 1
456  else:
457  den = 1
458 
459  var_num_iter = sum_var_num_iter / den
460  var_run_time = sum_var_run_time / den
461 
462  self.sd_num_iter = math.sqrt(var_num_iter)
463  self.sd_run_time = math.sqrt(var_run_time)
464  self.mse_num_iter = self.sd_num_iter / math.sqrt(den)
465  self.mse_run_time = self.sd_run_time / math.sqrt(den)
466 
467  assert self.num_success == body[self.num_run - 1].num_suc_til_now
468 
469 class Test_Log():
470  '''
471  Contains data structure for evaluation test results for a set of runs associated with multiple target poses
472  Including:
473  Header:
474  Test Settings (An instance of "Kinematic_Manager_Settings")
475  Body:
476  Log data for each configuration (A list of instances of "Run_Log")
477  Footer
478  Statistic Data (An instance of "Run_Log_Statistics")
479 
480  '''
481  def __init__(self, km_settings ):
482  self.header = km_settings
483  self.body = [] # should be an array of instances of Run_Log()
484  self.footer = Test_Statistics()
485 
486  def write_log(self, filename):
487  print 'Test_Log(): Writing log file started ...'
488  LOG_FILE_HANDLE = open(filename, "w")
489  LOG_FILE_HANDLE.write(str(self.header))
490  LOG_FILE_HANDLE.write("\n" + "--------------------------------------------------------------------------------" + "\n")
491  for body_log in self.body:
492  LOG_FILE_HANDLE.write(str(body_log))
493  LOG_FILE_HANDLE.write("\n" + "--------------------------------------------------------------------------------" + "\n")
494  LOG_FILE_HANDLE.write(str(self.footer))
495  print 'Test_Log: Writing log file ended.'
496 
497  def write_self(self, filename):
498  print 'Test_Log: Writing self file started ...'
499  SELF_FILE_HANDLE = open(filename, "w")
500  pickle.dump(self, SELF_FILE_HANDLE)
501  print 'Test_Log: Writing self file ended.'
502 
503  def write_csv(self, filename):
504  print 'Test_Log: Writing csv file started ...'
505  CSV_FILE_HANDLE = open(filename, "w")
506  x = self.body[0]
507  CSV_FILE_HANDLE.write(x.csv_horizontal_header() + '\n')
508  for x in self.body:
509  CSV_FILE_HANDLE.write(x.csv_horizontal() + '\n')
510  print 'Test_Log: Writing csv file ended.'
511 
512 # \endcond