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