xref: /aosp_15_r20/external/eigen/debug/gdb/printers.py (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1*bf2c3715SXin Li# -*- coding: utf-8 -*-
2*bf2c3715SXin Li# This file is part of Eigen, a lightweight C++ template library
3*bf2c3715SXin Li# for linear algebra.
4*bf2c3715SXin Li#
5*bf2c3715SXin Li# Copyright (C) 2009 Benjamin Schindler <[email protected]>
6*bf2c3715SXin Li#
7*bf2c3715SXin Li# This Source Code Form is subject to the terms of the Mozilla Public
8*bf2c3715SXin Li# License, v. 2.0. If a copy of the MPL was not distributed with this
9*bf2c3715SXin Li# file, You can obtain one at http://mozilla.org/MPL/2.0/.
10*bf2c3715SXin Li
11*bf2c3715SXin Li# Pretty printers for Eigen::Matrix
12*bf2c3715SXin Li# This is still pretty basic as the python extension to gdb is still pretty basic.
13*bf2c3715SXin Li# It cannot handle complex eigen types and it doesn't support many of the other eigen types
14*bf2c3715SXin Li# This code supports fixed size as well as dynamic size matrices
15*bf2c3715SXin Li
16*bf2c3715SXin Li# To use it:
17*bf2c3715SXin Li#
18*bf2c3715SXin Li# * Create a directory and put the file as well as an empty __init__.py in
19*bf2c3715SXin Li#   that directory.
20*bf2c3715SXin Li# * Create a ~/.gdbinit file, that contains the following:
21*bf2c3715SXin Li#      python
22*bf2c3715SXin Li#      import sys
23*bf2c3715SXin Li#      sys.path.insert(0, '/path/to/eigen/printer/directory')
24*bf2c3715SXin Li#      from printers import register_eigen_printers
25*bf2c3715SXin Li#      register_eigen_printers (None)
26*bf2c3715SXin Li#      end
27*bf2c3715SXin Li
28*bf2c3715SXin Liimport gdb
29*bf2c3715SXin Liimport re
30*bf2c3715SXin Liimport itertools
31*bf2c3715SXin Lifrom bisect import bisect_left
32*bf2c3715SXin Li
33*bf2c3715SXin Li# Basic row/column iteration code for use with Sparse and Dense matrices
34*bf2c3715SXin Liclass _MatrixEntryIterator(object):
35*bf2c3715SXin Li
36*bf2c3715SXin Li	def __init__ (self, rows, cols, rowMajor):
37*bf2c3715SXin Li		self.rows = rows
38*bf2c3715SXin Li		self.cols = cols
39*bf2c3715SXin Li		self.currentRow = 0
40*bf2c3715SXin Li		self.currentCol = 0
41*bf2c3715SXin Li		self.rowMajor = rowMajor
42*bf2c3715SXin Li
43*bf2c3715SXin Li	def __iter__ (self):
44*bf2c3715SXin Li		return self
45*bf2c3715SXin Li
46*bf2c3715SXin Li	def next(self):
47*bf2c3715SXin Li                return self.__next__()  # Python 2.x compatibility
48*bf2c3715SXin Li
49*bf2c3715SXin Li	def __next__(self):
50*bf2c3715SXin Li		row = self.currentRow
51*bf2c3715SXin Li		col = self.currentCol
52*bf2c3715SXin Li		if self.rowMajor == 0:
53*bf2c3715SXin Li			if self.currentCol >= self.cols:
54*bf2c3715SXin Li				raise StopIteration
55*bf2c3715SXin Li
56*bf2c3715SXin Li			self.currentRow = self.currentRow + 1
57*bf2c3715SXin Li			if self.currentRow >= self.rows:
58*bf2c3715SXin Li				self.currentRow = 0
59*bf2c3715SXin Li				self.currentCol = self.currentCol + 1
60*bf2c3715SXin Li		else:
61*bf2c3715SXin Li			if self.currentRow >= self.rows:
62*bf2c3715SXin Li				raise StopIteration
63*bf2c3715SXin Li
64*bf2c3715SXin Li			self.currentCol = self.currentCol + 1
65*bf2c3715SXin Li			if self.currentCol >= self.cols:
66*bf2c3715SXin Li				self.currentCol = 0
67*bf2c3715SXin Li				self.currentRow = self.currentRow + 1
68*bf2c3715SXin Li
69*bf2c3715SXin Li		return (row, col)
70*bf2c3715SXin Li
71*bf2c3715SXin Liclass EigenMatrixPrinter:
72*bf2c3715SXin Li	"Print Eigen Matrix or Array of some kind"
73*bf2c3715SXin Li
74*bf2c3715SXin Li	def __init__(self, variety, val):
75*bf2c3715SXin Li		"Extract all the necessary information"
76*bf2c3715SXin Li
77*bf2c3715SXin Li		# Save the variety (presumably "Matrix" or "Array") for later usage
78*bf2c3715SXin Li		self.variety = variety
79*bf2c3715SXin Li
80*bf2c3715SXin Li		# The gdb extension does not support value template arguments - need to extract them by hand
81*bf2c3715SXin Li		type = val.type
82*bf2c3715SXin Li		if type.code == gdb.TYPE_CODE_REF:
83*bf2c3715SXin Li			type = type.target()
84*bf2c3715SXin Li		self.type = type.unqualified().strip_typedefs()
85*bf2c3715SXin Li		tag = self.type.tag
86*bf2c3715SXin Li		regex = re.compile('\<.*\>')
87*bf2c3715SXin Li		m = regex.findall(tag)[0][1:-1]
88*bf2c3715SXin Li		template_params = m.split(',')
89*bf2c3715SXin Li		template_params = [x.replace(" ", "") for x in template_params]
90*bf2c3715SXin Li
91*bf2c3715SXin Li		if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001' or template_params[1] == '-1':
92*bf2c3715SXin Li			self.rows = val['m_storage']['m_rows']
93*bf2c3715SXin Li		else:
94*bf2c3715SXin Li			self.rows = int(template_params[1])
95*bf2c3715SXin Li
96*bf2c3715SXin Li		if template_params[2] == '-0x00000000000000001' or template_params[2] == '-0x000000001' or template_params[2] == '-1':
97*bf2c3715SXin Li			self.cols = val['m_storage']['m_cols']
98*bf2c3715SXin Li		else:
99*bf2c3715SXin Li			self.cols = int(template_params[2])
100*bf2c3715SXin Li
101*bf2c3715SXin Li		self.options = 0 # default value
102*bf2c3715SXin Li		if len(template_params) > 3:
103*bf2c3715SXin Li			self.options = template_params[3];
104*bf2c3715SXin Li
105*bf2c3715SXin Li		self.rowMajor = (int(self.options) & 0x1)
106*bf2c3715SXin Li
107*bf2c3715SXin Li		self.innerType = self.type.template_argument(0)
108*bf2c3715SXin Li
109*bf2c3715SXin Li		self.val = val
110*bf2c3715SXin Li
111*bf2c3715SXin Li		# Fixed size matrices have a struct as their storage, so we need to walk through this
112*bf2c3715SXin Li		self.data = self.val['m_storage']['m_data']
113*bf2c3715SXin Li		if self.data.type.code == gdb.TYPE_CODE_STRUCT:
114*bf2c3715SXin Li			self.data = self.data['array']
115*bf2c3715SXin Li			self.data = self.data.cast(self.innerType.pointer())
116*bf2c3715SXin Li
117*bf2c3715SXin Li	class _iterator(_MatrixEntryIterator):
118*bf2c3715SXin Li		def __init__ (self, rows, cols, dataPtr, rowMajor):
119*bf2c3715SXin Li			super(EigenMatrixPrinter._iterator, self).__init__(rows, cols, rowMajor)
120*bf2c3715SXin Li
121*bf2c3715SXin Li			self.dataPtr = dataPtr
122*bf2c3715SXin Li
123*bf2c3715SXin Li		def __next__(self):
124*bf2c3715SXin Li
125*bf2c3715SXin Li			row, col = super(EigenMatrixPrinter._iterator, self).__next__()
126*bf2c3715SXin Li
127*bf2c3715SXin Li			item = self.dataPtr.dereference()
128*bf2c3715SXin Li			self.dataPtr = self.dataPtr + 1
129*bf2c3715SXin Li			if (self.cols == 1): #if it's a column vector
130*bf2c3715SXin Li				return ('[%d]' % (row,), item)
131*bf2c3715SXin Li			elif (self.rows == 1): #if it's a row vector
132*bf2c3715SXin Li				return ('[%d]' % (col,), item)
133*bf2c3715SXin Li			return ('[%d,%d]' % (row, col), item)
134*bf2c3715SXin Li
135*bf2c3715SXin Li	def children(self):
136*bf2c3715SXin Li
137*bf2c3715SXin Li		return self._iterator(self.rows, self.cols, self.data, self.rowMajor)
138*bf2c3715SXin Li
139*bf2c3715SXin Li	def to_string(self):
140*bf2c3715SXin Li		return "Eigen::%s<%s,%d,%d,%s> (data ptr: %s)" % (self.variety, self.innerType, self.rows, self.cols, "RowMajor" if self.rowMajor else  "ColMajor", self.data)
141*bf2c3715SXin Li
142*bf2c3715SXin Liclass EigenSparseMatrixPrinter:
143*bf2c3715SXin Li	"Print an Eigen SparseMatrix"
144*bf2c3715SXin Li
145*bf2c3715SXin Li	def __init__(self, val):
146*bf2c3715SXin Li		"Extract all the necessary information"
147*bf2c3715SXin Li
148*bf2c3715SXin Li		type = val.type
149*bf2c3715SXin Li		if type.code == gdb.TYPE_CODE_REF:
150*bf2c3715SXin Li			type = type.target()
151*bf2c3715SXin Li		self.type = type.unqualified().strip_typedefs()
152*bf2c3715SXin Li		tag = self.type.tag
153*bf2c3715SXin Li		regex = re.compile('\<.*\>')
154*bf2c3715SXin Li		m = regex.findall(tag)[0][1:-1]
155*bf2c3715SXin Li		template_params = m.split(',')
156*bf2c3715SXin Li		template_params = [x.replace(" ", "") for x in template_params]
157*bf2c3715SXin Li
158*bf2c3715SXin Li		self.options = 0
159*bf2c3715SXin Li		if len(template_params) > 1:
160*bf2c3715SXin Li			self.options = template_params[1];
161*bf2c3715SXin Li
162*bf2c3715SXin Li		self.rowMajor = (int(self.options) & 0x1)
163*bf2c3715SXin Li
164*bf2c3715SXin Li		self.innerType = self.type.template_argument(0)
165*bf2c3715SXin Li
166*bf2c3715SXin Li		self.val = val
167*bf2c3715SXin Li
168*bf2c3715SXin Li		self.data = self.val['m_data']
169*bf2c3715SXin Li		self.data = self.data.cast(self.innerType.pointer())
170*bf2c3715SXin Li
171*bf2c3715SXin Li	class _iterator(_MatrixEntryIterator):
172*bf2c3715SXin Li		def __init__ (self, rows, cols, val, rowMajor):
173*bf2c3715SXin Li			super(EigenSparseMatrixPrinter._iterator, self).__init__(rows, cols, rowMajor)
174*bf2c3715SXin Li
175*bf2c3715SXin Li			self.val = val
176*bf2c3715SXin Li
177*bf2c3715SXin Li		def __next__(self):
178*bf2c3715SXin Li
179*bf2c3715SXin Li			row, col = super(EigenSparseMatrixPrinter._iterator, self).__next__()
180*bf2c3715SXin Li
181*bf2c3715SXin Li			# repeat calculations from SparseMatrix.h:
182*bf2c3715SXin Li			outer = row if self.rowMajor else col
183*bf2c3715SXin Li			inner = col if self.rowMajor else row
184*bf2c3715SXin Li			start = self.val['m_outerIndex'][outer]
185*bf2c3715SXin Li			end = ((start + self.val['m_innerNonZeros'][outer]) if self.val['m_innerNonZeros'] else
186*bf2c3715SXin Li			       self.val['m_outerIndex'][outer+1])
187*bf2c3715SXin Li
188*bf2c3715SXin Li			# and from CompressedStorage.h:
189*bf2c3715SXin Li			data = self.val['m_data']
190*bf2c3715SXin Li			if start >= end:
191*bf2c3715SXin Li				item = 0
192*bf2c3715SXin Li			elif (end > start) and (inner == data['m_indices'][end-1]):
193*bf2c3715SXin Li				item = data['m_values'][end-1]
194*bf2c3715SXin Li			else:
195*bf2c3715SXin Li				# create Python index list from the target range within m_indices
196*bf2c3715SXin Li				indices = [data['m_indices'][x] for x in range(int(start), int(end)-1)]
197*bf2c3715SXin Li				# find the index with binary search
198*bf2c3715SXin Li				idx = int(start) + bisect_left(indices, inner)
199*bf2c3715SXin Li				if ((idx < end) and (data['m_indices'][idx] == inner)):
200*bf2c3715SXin Li					item = data['m_values'][idx]
201*bf2c3715SXin Li				else:
202*bf2c3715SXin Li					item = 0
203*bf2c3715SXin Li
204*bf2c3715SXin Li			return ('[%d,%d]' % (row, col), item)
205*bf2c3715SXin Li
206*bf2c3715SXin Li	def children(self):
207*bf2c3715SXin Li		if self.data:
208*bf2c3715SXin Li			return self._iterator(self.rows(), self.cols(), self.val, self.rowMajor)
209*bf2c3715SXin Li
210*bf2c3715SXin Li		return iter([])   # empty matrix, for now
211*bf2c3715SXin Li
212*bf2c3715SXin Li
213*bf2c3715SXin Li	def rows(self):
214*bf2c3715SXin Li		return self.val['m_outerSize'] if self.rowMajor else self.val['m_innerSize']
215*bf2c3715SXin Li
216*bf2c3715SXin Li	def cols(self):
217*bf2c3715SXin Li		return self.val['m_innerSize'] if self.rowMajor else self.val['m_outerSize']
218*bf2c3715SXin Li
219*bf2c3715SXin Li	def to_string(self):
220*bf2c3715SXin Li
221*bf2c3715SXin Li		if self.data:
222*bf2c3715SXin Li			status = ("not compressed" if self.val['m_innerNonZeros'] else "compressed")
223*bf2c3715SXin Li		else:
224*bf2c3715SXin Li			status = "empty"
225*bf2c3715SXin Li		dimensions  = "%d x %d" % (self.rows(), self.cols())
226*bf2c3715SXin Li		layout      = "row" if self.rowMajor else "column"
227*bf2c3715SXin Li
228*bf2c3715SXin Li		return "Eigen::SparseMatrix<%s>, %s, %s major, %s" % (
229*bf2c3715SXin Li			self.innerType, dimensions, layout, status )
230*bf2c3715SXin Li
231*bf2c3715SXin Liclass EigenQuaternionPrinter:
232*bf2c3715SXin Li	"Print an Eigen Quaternion"
233*bf2c3715SXin Li
234*bf2c3715SXin Li	def __init__(self, val):
235*bf2c3715SXin Li		"Extract all the necessary information"
236*bf2c3715SXin Li		# The gdb extension does not support value template arguments - need to extract them by hand
237*bf2c3715SXin Li		type = val.type
238*bf2c3715SXin Li		if type.code == gdb.TYPE_CODE_REF:
239*bf2c3715SXin Li			type = type.target()
240*bf2c3715SXin Li		self.type = type.unqualified().strip_typedefs()
241*bf2c3715SXin Li		self.innerType = self.type.template_argument(0)
242*bf2c3715SXin Li		self.val = val
243*bf2c3715SXin Li
244*bf2c3715SXin Li		# Quaternions have a struct as their storage, so we need to walk through this
245*bf2c3715SXin Li		self.data = self.val['m_coeffs']['m_storage']['m_data']['array']
246*bf2c3715SXin Li		self.data = self.data.cast(self.innerType.pointer())
247*bf2c3715SXin Li
248*bf2c3715SXin Li	class _iterator:
249*bf2c3715SXin Li		def __init__ (self, dataPtr):
250*bf2c3715SXin Li			self.dataPtr = dataPtr
251*bf2c3715SXin Li			self.currentElement = 0
252*bf2c3715SXin Li			self.elementNames = ['x', 'y', 'z', 'w']
253*bf2c3715SXin Li
254*bf2c3715SXin Li		def __iter__ (self):
255*bf2c3715SXin Li			return self
256*bf2c3715SXin Li
257*bf2c3715SXin Li		def next(self):
258*bf2c3715SXin Li			return self.__next__()  # Python 2.x compatibility
259*bf2c3715SXin Li
260*bf2c3715SXin Li		def __next__(self):
261*bf2c3715SXin Li			element = self.currentElement
262*bf2c3715SXin Li
263*bf2c3715SXin Li			if self.currentElement >= 4: #there are 4 elements in a quanternion
264*bf2c3715SXin Li				raise StopIteration
265*bf2c3715SXin Li
266*bf2c3715SXin Li			self.currentElement = self.currentElement + 1
267*bf2c3715SXin Li
268*bf2c3715SXin Li			item = self.dataPtr.dereference()
269*bf2c3715SXin Li			self.dataPtr = self.dataPtr + 1
270*bf2c3715SXin Li			return ('[%s]' % (self.elementNames[element],), item)
271*bf2c3715SXin Li
272*bf2c3715SXin Li	def children(self):
273*bf2c3715SXin Li
274*bf2c3715SXin Li		return self._iterator(self.data)
275*bf2c3715SXin Li
276*bf2c3715SXin Li	def to_string(self):
277*bf2c3715SXin Li		return "Eigen::Quaternion<%s> (data ptr: %s)" % (self.innerType, self.data)
278*bf2c3715SXin Li
279*bf2c3715SXin Lidef build_eigen_dictionary ():
280*bf2c3715SXin Li	pretty_printers_dict[re.compile('^Eigen::Quaternion<.*>$')] = lambda val: EigenQuaternionPrinter(val)
281*bf2c3715SXin Li	pretty_printers_dict[re.compile('^Eigen::Matrix<.*>$')] = lambda val: EigenMatrixPrinter("Matrix", val)
282*bf2c3715SXin Li	pretty_printers_dict[re.compile('^Eigen::SparseMatrix<.*>$')] = lambda val: EigenSparseMatrixPrinter(val)
283*bf2c3715SXin Li	pretty_printers_dict[re.compile('^Eigen::Array<.*>$')]  = lambda val: EigenMatrixPrinter("Array",  val)
284*bf2c3715SXin Li
285*bf2c3715SXin Lidef register_eigen_printers(obj):
286*bf2c3715SXin Li	"Register eigen pretty-printers with objfile Obj"
287*bf2c3715SXin Li
288*bf2c3715SXin Li	if obj == None:
289*bf2c3715SXin Li		obj = gdb
290*bf2c3715SXin Li	obj.pretty_printers.append(lookup_function)
291*bf2c3715SXin Li
292*bf2c3715SXin Lidef lookup_function(val):
293*bf2c3715SXin Li	"Look-up and return a pretty-printer that can print va."
294*bf2c3715SXin Li
295*bf2c3715SXin Li	type = val.type
296*bf2c3715SXin Li
297*bf2c3715SXin Li	if type.code == gdb.TYPE_CODE_REF:
298*bf2c3715SXin Li		type = type.target()
299*bf2c3715SXin Li
300*bf2c3715SXin Li	type = type.unqualified().strip_typedefs()
301*bf2c3715SXin Li
302*bf2c3715SXin Li	typename = type.tag
303*bf2c3715SXin Li	if typename == None:
304*bf2c3715SXin Li		return None
305*bf2c3715SXin Li
306*bf2c3715SXin Li	for function in pretty_printers_dict:
307*bf2c3715SXin Li		if function.search(typename):
308*bf2c3715SXin Li			return pretty_printers_dict[function](val)
309*bf2c3715SXin Li
310*bf2c3715SXin Li	return None
311*bf2c3715SXin Li
312*bf2c3715SXin Lipretty_printers_dict = {}
313*bf2c3715SXin Li
314*bf2c3715SXin Libuild_eigen_dictionary ()
315