]> git.rmz.io Git - dotfiles.git/blob - gdb/eigen.py
lazyvim: absorb keymaps
[dotfiles.git] / gdb / eigen.py
1 # -*- coding: utf-8 -*-
2 # This file is part of Eigen, a lightweight C++ template library
3 # for linear algebra.
4 #
5 # Copyright (C) 2009 Benjamin Schindler <bschindler@inf.ethz.ch>
6 #
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/.
10
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
15
16 # To use it:
17 #
18 # * Create a directory and put the file as well as an empty __init__.py in
19 # that directory.
20 # * Create a ~/.gdbinit file, that contains the following:
21 # python
22 # import sys
23 # sys.path.insert(0, '/path/to/eigen/printer/directory')
24 # from printers import register_eigen_printers
25 # register_eigen_printers(None)
26 # end
27
28 import gdb
29 import re
30 from bisect import bisect_left
31
32
33 # Basic row/column iteration code for use with Sparse and Dense matrices
34 class _MatrixEntryIterator(object):
35
36 def __init__(self, rows, cols, row_major):
37 self.rows = rows
38 self.cols = cols
39 self.currentRow = 0
40 self.currentCol = 0
41 self.rowMajor = row_major
42
43 def __iter__(self):
44 return self
45
46 def next(self):
47 return self.__next__() # Python 2.x compatibility
48
49 def __next__(self):
50 row = self.currentRow
51 col = self.currentCol
52 if self.rowMajor == 0:
53 if self.currentCol >= self.cols:
54 raise StopIteration
55
56 self.currentRow += 1
57 if self.currentRow >= self.rows:
58 self.currentRow = 0
59 self.currentCol += 1
60 else:
61 if self.currentRow >= self.rows:
62 raise StopIteration
63
64 self.currentCol += 1
65 if self.currentCol >= self.cols:
66 self.currentCol = 0
67 self.currentRow += 1
68
69 return row, col
70
71
72 class EigenMatrixPrinter:
73 """Print Eigen Matrix or Array of some kind"""
74
75 def __init__(self, variety, val):
76 """Extract all the necessary information"""
77
78 # Save the variety (presumably "Matrix" or "Array") for later usage
79 self.variety = variety
80
81 # The gdb extension does not support value template arguments - need to extract them by hand
82 typeinfo = val.type
83 if typeinfo.code == gdb.TYPE_CODE_REF:
84 typeinfo = typeinfo.target()
85 self.type = typeinfo.unqualified().strip_typedefs()
86 tag = self.type.tag
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]
91
92 if template_params[1] in ['-0x00000000000000001', '-0x000000001', '-1']:
93 self.rows = val['m_storage']['m_rows']
94 else:
95 self.rows = int(template_params[1])
96
97 if template_params[2] in ['-0x00000000000000001', '-0x000000001', '-1']:
98 self.cols = val['m_storage']['m_cols']
99 else:
100 self.cols = int(template_params[2])
101
102 self.options = 0 # default value
103 if len(template_params) > 3:
104 self.options = template_params[3]
105
106 self.rowMajor = (int(self.options) & 0x1)
107
108 self.innerType = self.type.template_argument(0)
109
110 self.val = val
111
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())
117
118 class _Iterator(_MatrixEntryIterator):
119 def __init__(self, rows, cols, data_ptr, row_major):
120 super(EigenMatrixPrinter._Iterator, self).__init__(rows, cols, row_major)
121
122 self.dataPtr = data_ptr
123
124 def __next__(self):
125 row, col = super(EigenMatrixPrinter._Iterator, self).__next__()
126
127 item = self.dataPtr.dereference()
128 self.dataPtr += 1
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
134
135 def children(self):
136 return self._Iterator(self.rows, self.cols, self.data, self.rowMajor)
137
138 def to_string(self):
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)
142
143
144 class EigenSparseMatrixPrinter:
145 """Print an Eigen SparseMatrix"""
146
147 def __init__(self, val):
148 """Extract all the necessary information"""
149
150 typeinfo = val.type
151 if typeinfo.code == gdb.TYPE_CODE_REF:
152 typeinfo = typeinfo.target()
153 self.type = typeinfo.unqualified().strip_typedefs()
154 tag = self.type.tag
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]
159
160 self.options = 0
161 if len(template_params) > 1:
162 self.options = template_params[1]
163
164 self.rowMajor = (int(self.options) & 0x1)
165
166 self.innerType = self.type.template_argument(0)
167
168 self.val = val
169
170 self.data = self.val['m_data']
171 self.data = self.data.cast(self.innerType.pointer())
172
173 class _Iterator(_MatrixEntryIterator):
174 def __init__(self, rows, cols, val, row_major):
175 super(EigenSparseMatrixPrinter._Iterator, self).__init__(rows, cols, row_major)
176
177 self.val = val
178
179 def __next__(self):
180 row, col = super(EigenSparseMatrixPrinter._Iterator, self).__next__()
181
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]
186 end = (
187 (start + self.val['m_innerNonZeros'][outer])
188 if self.val['m_innerNonZeros'] else self.val['m_outerIndex'][outer+1]
189 )
190
191 # and from CompressedStorage.h:
192 data = self.val['m_data']
193 if start >= end:
194 item = 0
195 elif (end > start) and (inner == data['m_indices'][end-1]):
196 item = data['m_values'][end-1]
197 else:
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]
204 else:
205 item = 0
206
207 return '[%d,%d]' % (row, col), item
208
209 def children(self):
210 if self.data:
211 return self._Iterator(self.rows(), self.cols(), self.val, self.rowMajor)
212
213 return iter([]) # empty matrix, for now
214
215 def rows(self):
216 return self.val['m_outerSize'] if self.rowMajor else self.val['m_innerSize']
217
218 def cols(self):
219 return self.val['m_innerSize'] if self.rowMajor else self.val['m_outerSize']
220
221 def to_string(self):
222
223 if self.data:
224 status = ("not compressed" if self.val['m_innerNonZeros'] else "compressed")
225 else:
226 status = "empty"
227 dimensions = "%d x %d" % (self.rows(), self.cols())
228 layout = "row" if self.rowMajor else "column"
229
230 return "Eigen::SparseMatrix<%s>, %s, %s major, %s" % (
231 self.innerType, dimensions, layout, status)
232
233
234 class EigenQuaternionPrinter:
235 """Print an Eigen Quaternion"""
236
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
240 typeinfo = val.type
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)
245 self.val = val
246
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())
250
251 class _Iterator:
252 def __init__(self, data_ptr):
253 self.dataPtr = data_ptr
254 self.currentElement = 0
255 self.elementNames = ['x', 'y', 'z', 'w']
256
257 def __iter__(self):
258 return self
259
260 def next(self):
261 return self.__next__() # Python 2.x compatibility
262
263 def __next__(self):
264 element = self.currentElement
265
266 if self.currentElement >= 4: # there are 4 elements in a quaternion
267 raise StopIteration
268
269 self.currentElement += 1
270
271 item = self.dataPtr.dereference()
272 self.dataPtr += 1
273 return '[%s]' % (self.elementNames[element],), item
274
275 def children(self):
276 return self._Iterator(self.data)
277
278 def to_string(self):
279 return "Eigen::Quaternion<%s> (data ptr: %s)" % (self.innerType, self.data)
280
281
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)
286
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
291
292 # Convert the Eigen::Block to an Eigen::Matrix
293 return val.cast(gdb.lookup_type(val_type[begin:end]))
294
295
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)
305
306
307 def register_eigen_printers(obj):
308 """Register eigen pretty-printers with objfile Obj"""
309
310 if obj is None:
311 obj = gdb
312 obj.pretty_printers.append(lookup_function)
313
314
315 def lookup_function(val):
316 """Look-up and return a pretty-printer that can print val."""
317
318 typeinfo = val.type
319
320 if typeinfo.code == gdb.TYPE_CODE_REF:
321 typeinfo = typeinfo.target()
322
323 typeinfo = typeinfo.unqualified().strip_typedefs()
324
325 typename = typeinfo.tag
326 if typename is None:
327 return None
328
329 for function in pretty_printers_dict:
330 if function.search(typename):
331 return pretty_printers_dict[function](val)
332
333 return None
334
335
336 pretty_printers_dict = {}
337
338 build_eigen_dictionary()