]>
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()