]>
git.rmz.io Git - dotfiles.git/blob - gdb/eigen.py
   1 # -*- coding: utf-8 -*- 
   2 # This file is part of Eigen, a lightweight C++ template library 
   5 # Copyright (C) 2009 Benjamin Schindler <bschindler@inf.ethz.ch> 
   7 # This Source Code Form is subject to the terms of the Mozilla Public 
   8 # License, v. 2.0. If a copy of the MPL was not distributed with this 
   9 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 
  11 # Pretty printers for Eigen::Matrix 
  12 # This is still pretty basic as the python extension to gdb is still pretty basic.  
  13 # It cannot handle complex eigen types and it doesn't support many of the other eigen types 
  14 # This code supports fixed size as well as dynamic size matrices 
  18 # * Create a directory and put the file as well as an empty __init__.py in  
  20 # * Create a ~/.gdbinit file, that contains the following: 
  23 #      sys.path.insert(0, '/path/to/eigen/printer/directory') 
  24 #      from printers import register_eigen_printers 
  25 #      register_eigen_printers(None) 
  30 from bisect 
import bisect_left
 
  33 # Basic row/column iteration code for use with Sparse and Dense matrices 
  34 class _MatrixEntryIterator(object): 
  36         def __init__(self
, rows
, cols
, row_major
): 
  41                 self
.rowMajor 
= row_major
 
  47                 return self
.__next
__()  # Python 2.x compatibility 
  52                 if self
.rowMajor 
== 0: 
  53                         if self
.currentCol 
>= self
.cols
: 
  57                         if self
.currentRow 
>= self
.rows
: 
  61                         if self
.currentRow 
>= self
.rows
: 
  65                         if self
.currentCol 
>= self
.cols
: 
  72 class EigenMatrixPrinter
: 
  73         """Print Eigen Matrix or Array of some kind""" 
  75         def __init__(self
, variety
, val
): 
  76                 """Extract all the necessary information""" 
  78                 # Save the variety (presumably "Matrix" or "Array") for later usage 
  79                 self
.variety 
= variety
 
  81                 # The gdb extension does not support value template arguments - need to extract them by hand 
  83                 if typeinfo
.code 
== gdb
.TYPE_CODE_REF
: 
  84                         typeinfo 
= typeinfo
.target() 
  85                 self
.type = typeinfo
.unqualified().strip_typedefs() 
  87                 regex 
= re
.compile('<.*>') 
  88                 m 
= regex
.findall(tag
)[0][1:-1] 
  89                 template_params 
= m
.split(',') 
  90                 template_params 
= [x
.replace(" ", "") for x 
in template_params
] 
  92                 if template_params
[1] in ['-0x00000000000000001', '-0x000000001', '-1']: 
  93                         self
.rows 
= val
['m_storage']['m_rows'] 
  95                         self
.rows 
= int(template_params
[1]) 
  97                 if template_params
[2] in ['-0x00000000000000001', '-0x000000001', '-1']: 
  98                         self
.cols 
= val
['m_storage']['m_cols'] 
 100                         self
.cols 
= int(template_params
[2]) 
 102                 self
.options 
= 0  # default value 
 103                 if len(template_params
) > 3: 
 104                         self
.options 
= template_params
[3] 
 106                 self
.rowMajor 
= (int(self
.options
) & 0x1) 
 108                 self
.innerType 
= self
.type.template_argument(0) 
 112                 # Fixed size matrices have a struct as their storage, so we need to walk through this 
 113                 self
.data 
= self
.val
['m_storage']['m_data'] 
 114                 if self
.data
.type.code 
== gdb
.TYPE_CODE_STRUCT
: 
 115                         self
.data 
= self
.data
['array'] 
 116                         self
.data 
= self
.data
.cast(self
.innerType
.pointer()) 
 118         class _Iterator(_MatrixEntryIterator
): 
 119                 def __init__(self
, rows
, cols
, data_ptr
, row_major
): 
 120                         super(EigenMatrixPrinter
._Iterator
, self
).__init
__(rows
, cols
, row_major
) 
 122                         self
.dataPtr 
= data_ptr
 
 125                         row
, col 
= super(EigenMatrixPrinter
._Iterator
, self
).__next
__() 
 127                         item 
= self
.dataPtr
.dereference() 
 129                         if self
.cols 
== 1:  # if it's a column vector 
 130                                 return '[%d]' % (row
,), item
 
 131                         elif self
.rows 
== 1:  # if it's a row vector 
 132                                 return '[%d]' % (col
,), item
 
 133                         return '[%d,%d]' % (row
, col
), item
 
 136                 return self
._Iterator
(self
.rows
, self
.cols
, self
.data
, self
.rowMajor
) 
 139                 return "Eigen::%s<%s,%d,%d,%s> (data ptr: %s)" % ( 
 140                         self
.variety
, self
.innerType
, self
.rows
, self
.cols
, 
 141                         "RowMajor" if self
.rowMajor 
else "ColMajor", self
.data
) 
 144 class EigenSparseMatrixPrinter
: 
 145         """Print an Eigen SparseMatrix""" 
 147         def __init__(self
, val
): 
 148                 """Extract all the necessary information""" 
 151                 if typeinfo
.code 
== gdb
.TYPE_CODE_REF
: 
 152                         typeinfo 
= typeinfo
.target() 
 153                 self
.type = typeinfo
.unqualified().strip_typedefs() 
 155                 regex 
= re
.compile('<.*>') 
 156                 m 
= regex
.findall(tag
)[0][1:-1] 
 157                 template_params 
= m
.split(',') 
 158                 template_params 
= [x
.replace(" ", "") for x 
in template_params
] 
 161                 if len(template_params
) > 1: 
 162                         self
.options 
= template_params
[1] 
 164                 self
.rowMajor 
= (int(self
.options
) & 0x1) 
 166                 self
.innerType 
= self
.type.template_argument(0) 
 170                 self
.data 
= self
.val
['m_data'] 
 171                 self
.data 
= self
.data
.cast(self
.innerType
.pointer()) 
 173         class _Iterator(_MatrixEntryIterator
): 
 174                 def __init__(self
, rows
, cols
, val
, row_major
): 
 175                         super(EigenSparseMatrixPrinter
._Iterator
, self
).__init
__(rows
, cols
, row_major
) 
 180                         row
, col 
= super(EigenSparseMatrixPrinter
._Iterator
, self
).__next
__() 
 182                         # repeat calculations from SparseMatrix.h: 
 183                         outer 
= row 
if self
.rowMajor 
else col
 
 184                         inner 
= col 
if self
.rowMajor 
else row
 
 185                         start 
= self
.val
['m_outerIndex'][outer
] 
 187                                 (start 
+ self
.val
['m_innerNonZeros'][outer
]) 
 188                                 if self
.val
['m_innerNonZeros'] else self
.val
['m_outerIndex'][outer
+1] 
 191                         # and from CompressedStorage.h: 
 192                         data 
= self
.val
['m_data'] 
 195                         elif (end 
> start
) and (inner 
== data
['m_indices'][end
-1]): 
 196                                 item 
= data
['m_values'][end
-1] 
 198                                 # create Python index list from the target range within m_indices 
 199                                 indices 
= [data
['m_indices'][x
] for x 
in range(int(start
), int(end
)-1)] 
 200                                 # find the index with binary search 
 201                                 idx 
= int(start
) + bisect_left(indices
, inner
) 
 202                                 if idx 
< end 
and data
['m_indices'][idx
] == inner
: 
 203                                         item 
= data
['m_values'][idx
] 
 207                         return '[%d,%d]' % (row
, col
), item
 
 211                         return self
._Iterator
(self
.rows(), self
.cols(), self
.val
, self
.rowMajor
) 
 213                 return iter([])   # empty matrix, for now 
 216                 return self
.val
['m_outerSize'] if self
.rowMajor 
else self
.val
['m_innerSize'] 
 219                 return self
.val
['m_innerSize'] if self
.rowMajor 
else self
.val
['m_outerSize'] 
 224                         status 
= ("not compressed" if self
.val
['m_innerNonZeros'] else "compressed") 
 227                 dimensions 
= "%d x %d" % (self
.rows(), self
.cols()) 
 228                 layout 
= "row" if self
.rowMajor 
else "column" 
 230                 return "Eigen::SparseMatrix<%s>, %s, %s major, %s" % ( 
 231                         self
.innerType
, dimensions
, layout
, status
) 
 234 class EigenQuaternionPrinter
: 
 235         """Print an Eigen Quaternion""" 
 237         def __init__(self
, val
): 
 238                 """Extract all the necessary information""" 
 239                 # The gdb extension does not support value template arguments - need to extract them by hand 
 241                 if typeinfo
.code 
== gdb
.TYPE_CODE_REF
: 
 242                         typeinfo 
= typeinfo
.target() 
 243                 self
.type = typeinfo
.unqualified().strip_typedefs() 
 244                 self
.innerType 
= self
.type.template_argument(0) 
 247                 # Quaternions have a struct as their storage, so we need to walk through this 
 248                 self
.data 
= self
.val
['m_coeffs']['m_storage']['m_data']['array'] 
 249                 self
.data 
= self
.data
.cast(self
.innerType
.pointer()) 
 252                 def __init__(self
, data_ptr
): 
 253                         self
.dataPtr 
= data_ptr
 
 254                         self
.currentElement 
= 0 
 255                         self
.elementNames 
= ['x', 'y', 'z', 'w'] 
 261                         return self
.__next
__()  # Python 2.x compatibility 
 264                         element 
= self
.currentElement
 
 266                         if self
.currentElement 
>= 4:  # there are 4 elements in a quaternion 
 269                         self
.currentElement 
+= 1 
 271                         item 
= self
.dataPtr
.dereference() 
 273                         return '[%s]' % (self
.elementNames
[element
],), item
 
 276                 return self
._Iterator
(self
.data
) 
 279                 return "Eigen::Quaternion<%s> (data ptr: %s)" % (self
.innerType
, self
.data
) 
 282 def cast_eigen_block_to_matrix(val
): 
 283         # Get the type of the variable (and convert to a string) 
 284         # Example: 'const Eigen::Block<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, -1, false> const, -1, -1, false>' 
 285         val_type 
= str(val
.type) 
 287         # Extract the Eigen::Matrix type from the Block: 
 288         # From the previous example: Eigen::Matrix<double, -1, -1, 0, -1, -1> 
 289         begin 
= val_type
.find('Eigen::Matrix<') 
 290         end 
= val_type
.find('>', begin
) + 1 
 292         # Convert the Eigen::Block to an Eigen::Matrix 
 293         return val
.cast(gdb
.lookup_type(val_type
[begin
:end
])) 
 296 def build_eigen_dictionary(): 
 297         pretty_printers_dict
[re
.compile('^Eigen::Quaternion<.*>$')] = lambda val
: EigenQuaternionPrinter(val
) 
 298         pretty_printers_dict
[re
.compile('^Eigen::Matrix<.*>$')] = lambda val
: EigenMatrixPrinter("Matrix", val
) 
 299         pretty_printers_dict
[re
.compile('^Eigen::Block<.*>$')] =\
 
 300                 lambda val
: EigenMatrixPrinter("Matrix", cast_eigen_block_to_matrix(val
)) 
 301         pretty_printers_dict
[re
.compile('^Eigen::VectorBlock<.*>$')] =\
 
 302                 lambda val
: EigenMatrixPrinter("Matrix", cast_eigen_block_to_matrix(val
)) 
 303         pretty_printers_dict
[re
.compile('^Eigen::SparseMatrix<.*>$')] = lambda val
: EigenSparseMatrixPrinter(val
) 
 304         pretty_printers_dict
[re
.compile('^Eigen::Array<.*>$')] = lambda val
: EigenMatrixPrinter("Array",  val
) 
 307 def register_eigen_printers(obj
): 
 308         """Register eigen pretty-printers with objfile Obj""" 
 312         obj
.pretty_printers
.append(lookup_function
) 
 315 def lookup_function(val
): 
 316         """Look-up and return a pretty-printer that can print val.""" 
 320         if typeinfo
.code 
== gdb
.TYPE_CODE_REF
: 
 321                 typeinfo 
= typeinfo
.target() 
 323         typeinfo 
= typeinfo
.unqualified().strip_typedefs() 
 325         typename 
= typeinfo
.tag
 
 329         for function 
in pretty_printers_dict
: 
 330                 if function
.search(typename
): 
 331                         return pretty_printers_dict
[function
](val
) 
 336 pretty_printers_dict 
= {} 
 338 build_eigen_dictionary()