235 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # -*- coding: utf-8 -*-
 | |
| # This file is part of Eigen, a lightweight C++ template library
 | |
| # for linear algebra.
 | |
| #
 | |
| # Copyright (C) 2021 Huang, Zhaoquan <zhaoquan2008@hotmail.com>
 | |
| #
 | |
| # This Source Code Form is subject to the terms of the Mozilla Public
 | |
| # License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | |
| 
 | |
| # Pretty printers for Eigen::Matrix to use with LLDB debugger
 | |
| #
 | |
| # Usage:
 | |
| # 1. Add the following line (change it according to the path to this file)
 | |
| #    to the file ~/.lldbinit (create one if it doesn't exist):
 | |
| #        `command script import /path/to/eigenlldb.py`
 | |
| # 2. Inspect the variables in LLDB command line
 | |
| #        `frame variable`
 | |
| 
 | |
| import lldb
 | |
| from typing import List
 | |
| import bisect
 | |
| 
 | |
| 
 | |
| def __lldb_init_module(debugger, internal_dict):
 | |
|     debugger.HandleCommand("type synthetic add -x Eigen::Matrix<.*> --python-class eigenlldb.EigenMatrixChildProvider")
 | |
|     debugger.HandleCommand(
 | |
|         "type synthetic add -x Eigen::SparseMatrix<.*> --python-class eigenlldb.EigenSparseMatrixChildProvider")
 | |
| 
 | |
| 
 | |
| class EigenMatrixChildProvider:
 | |
|     _valobj: lldb.SBValue
 | |
|     _scalar_type: lldb.SBType
 | |
|     _scalar_size: int
 | |
|     _rows_compile_time: int
 | |
|     _cols_compile_time: int
 | |
|     _row_major: bool
 | |
|     _fixed_storage: bool
 | |
| 
 | |
|     def __init__(self, valobj, internal_dict):
 | |
|         self._valobj = valobj
 | |
|         valtype = valobj.GetType().GetCanonicalType()
 | |
| 
 | |
|         scalar_type = valtype.GetTemplateArgumentType(0)
 | |
|         if not scalar_type.IsValid():
 | |
|             # In the case that scalar_type is invalid on LLDB 9.0 on Windows with CLion
 | |
|             storage = valobj.GetChildMemberWithName("m_storage")
 | |
|             data = storage.GetChildMemberWithName("m_data")
 | |
|             data_type = data.GetType()
 | |
|             if data_type.IsPointerType():
 | |
|                 scalar_type = data.GetType().GetPointeeType()
 | |
|             else:
 | |
|                 scalar_type = data.GetChildMemberWithName("array").GetType().GetArrayElementType()
 | |
|         self._scalar_type = scalar_type
 | |
|         self._scalar_size = self._scalar_type.GetByteSize()
 | |
| 
 | |
|         name = valtype.GetName()
 | |
|         template_begin = name.find("<")
 | |
|         template_end = name.find(">")
 | |
|         template_args = name[(template_begin + 1):template_end].split(",")
 | |
|         self._rows_compile_time = int(template_args[1])
 | |
|         self._cols_compile_time = int(template_args[2])
 | |
|         self._row_major = (int(template_args[3]) & 1) != 0
 | |
| 
 | |
|         max_rows = int(template_args[4])
 | |
|         max_cols = int(template_args[5])
 | |
|         self._fixed_storage = (max_rows != -1 and max_cols != -1)
 | |
| 
 | |
|     def num_children(self):
 | |
|         return self._cols() * self._rows()
 | |
| 
 | |
|     def get_child_index(self, name):
 | |
|         pass
 | |
| 
 | |
|     def get_child_at_index(self, index):
 | |
|         storage = self._valobj.GetChildMemberWithName("m_storage")
 | |
|         data = storage.GetChildMemberWithName("m_data")
 | |
|         offset = self._scalar_size * index
 | |
| 
 | |
|         if self._row_major:
 | |
|             row = index // self._cols()
 | |
|             col = index % self._cols()
 | |
|         else:
 | |
|             row = index % self._rows()
 | |
|             col = index // self._rows()
 | |
|         if self._fixed_storage:
 | |
|             data = data.GetChildMemberWithName("array")
 | |
|         if self._cols() == 1:
 | |
|             name = '[{}]'.format(row)
 | |
|         elif self._rows() == 1:
 | |
|             name = '[{}]'.format(col)
 | |
|         else:
 | |
|             name = '[{},{}]'.format(row, col)
 | |
|         return data.CreateChildAtOffset(
 | |
|             name, offset, self._scalar_type
 | |
|         )
 | |
| 
 | |
|     def _cols(self):
 | |
|         if self._cols_compile_time == -1:
 | |
|             storage = self._valobj.GetChildMemberWithName("m_storage")
 | |
|             cols = storage.GetChildMemberWithName("m_cols")
 | |
|             return cols.GetValueAsUnsigned()
 | |
|         else:
 | |
|             return self._cols_compile_time
 | |
| 
 | |
|     def _rows(self):
 | |
|         if self._rows_compile_time == -1:
 | |
|             storage = self._valobj.GetChildMemberWithName("m_storage")
 | |
|             rows = storage.GetChildMemberWithName("m_rows")
 | |
|             return rows.GetValueAsUnsigned()
 | |
|         else:
 | |
|             return self._rows_compile_time
 | |
| 
 | |
| 
 | |
| class EigenSparseMatrixChildProvider:
 | |
|     _valobj: lldb.SBValue
 | |
|     _scalar_type: lldb.SBType
 | |
|     _scalar_size: int
 | |
|     _index_type: lldb.SBType
 | |
|     _index_size: int
 | |
|     _row_major: bool
 | |
| 
 | |
|     _outer_size: int
 | |
|     _nnz: int
 | |
|     _values: lldb.SBValue
 | |
|     _inner_indices: lldb.SBValue
 | |
|     _outer_starts: lldb.SBValue
 | |
|     _inner_nnzs: lldb.SBValue
 | |
|     _compressed: bool
 | |
| 
 | |
|     # Index of the first synthetic child under each outer index
 | |
|     _child_indices: List[int]
 | |
| 
 | |
|     def __init__(self, valobj, internal_dict):
 | |
|         self._valobj = valobj
 | |
|         valtype = valobj.GetType().GetCanonicalType()
 | |
|         scalar_type = valtype.GetTemplateArgumentType(0)
 | |
|         if not scalar_type.IsValid():
 | |
|             # In the case that scalar_type is invalid on LLDB 9.0 on Windows with CLion
 | |
|             data = valobj.GetChildMemberWithName("m_data")
 | |
|             values = data.GetChildMemberWithName("m_values")
 | |
|             scalar_type = values.GetType().GetPointeeType()
 | |
|         self._scalar_type = scalar_type
 | |
|         self._scalar_size = scalar_type.GetByteSize()
 | |
| 
 | |
|         index_type = valtype.GetTemplateArgumentType(2)
 | |
|         if not index_type.IsValid():
 | |
|             # In the case that scalar_type is invalid on LLDB 9.0 on Windows with CLion
 | |
|             outer_starts = valobj.GetChildMemberWithName("m_outerIndex")
 | |
|             index_type = outer_starts.GetType().GetPointeeType()
 | |
|         self._index_type = index_type
 | |
|         self._index_size = index_type.GetByteSize()
 | |
| 
 | |
|         name = valtype.GetName()
 | |
|         template_begin = name.find("<")
 | |
|         template_end = name.find(">")
 | |
|         template_args = name[(template_begin + 1):template_end].split(",")
 | |
|         self._row_major = (int(template_args[1]) & 1) != 0
 | |
| 
 | |
|     def num_children(self):
 | |
|         return self._nnz + 2
 | |
| 
 | |
|     def get_child_index(self, name):
 | |
|         pass
 | |
| 
 | |
|     def get_child_at_index(self, index):
 | |
|         if index == 0:
 | |
|             name = "rows" if self._row_major else "cols"
 | |
|             return self._valobj.GetChildMemberWithName("m_outerSize") \
 | |
|                 .CreateChildAtOffset(name, 0, self._index_type)
 | |
|         elif index == 1:
 | |
|             name = "cols" if self._row_major else "rows"
 | |
|             return self._valobj.GetChildMemberWithName("m_innerSize") \
 | |
|                 .CreateChildAtOffset(name, 0, self._index_type)
 | |
|         else:
 | |
|             index = index - 2
 | |
|         outer_index = bisect.bisect_right(self._child_indices, index) - 1
 | |
|         total_nnzs = self._child_indices[outer_index]
 | |
|         if self._compressed:
 | |
|             item_index = index
 | |
|             inner_index = self._inner_indices \
 | |
|                 .CreateChildAtOffset("", item_index * self._index_size, self._index_type) \
 | |
|                 .GetValueAsUnsigned()
 | |
|             return self._values \
 | |
|                 .CreateChildAtOffset(self._child_name(outer_index, inner_index),
 | |
|                                      item_index * self._scalar_size,
 | |
|                                      self._scalar_type)
 | |
|         else:
 | |
|             index_begin = self._outer_starts \
 | |
|                 .CreateChildAtOffset("", outer_index * self._index_size, self._index_type) \
 | |
|                 .GetValueAsUnsigned()
 | |
|             item_index = index - total_nnzs + index_begin
 | |
|             inner_index = self._inner_indices \
 | |
|                 .CreateChildAtOffset("", item_index * self._index_size, self._index_type) \
 | |
|                 .GetValueAsUnsigned()
 | |
|             return self._values \
 | |
|                 .CreateChildAtOffset(self._child_name(outer_index, inner_index),
 | |
|                                      item_index * self._scalar_size,
 | |
|                                      self._scalar_type)
 | |
| 
 | |
|     def update(self):
 | |
|         valobj = self._valobj
 | |
|         self._outer_size = valobj.GetChildMemberWithName("m_outerSize").GetValueAsUnsigned()
 | |
|         data = valobj.GetChildMemberWithName("m_data")
 | |
|         self._values = data.GetChildMemberWithName("m_values")
 | |
|         self._inner_indices = data.GetChildMemberWithName("m_indices")
 | |
|         self._outer_starts = valobj.GetChildMemberWithName("m_outerIndex")
 | |
|         self._inner_nnzs = valobj.GetChildMemberWithName("m_innerNonZeros")
 | |
| 
 | |
|         self._compressed = self._inner_nnzs.GetValueAsUnsigned() == 0
 | |
| 
 | |
|         total_nnzs = 0
 | |
|         child_indices = [0]
 | |
|         for outer_index in range(self._outer_size):
 | |
|             if self._compressed:
 | |
|                 index_end = self._outer_starts \
 | |
|                     .CreateChildAtOffset("", (outer_index + 1) * self._index_size, self._index_type) \
 | |
|                     .GetValueAsUnsigned()
 | |
|                 total_nnzs = index_end
 | |
|                 child_indices.append(total_nnzs)
 | |
|             else:
 | |
|                 nnzs = self._inner_nnzs \
 | |
|                     .CreateChildAtOffset("", outer_index * self._index_size, self._index_type) \
 | |
|                     .GetValueAsUnsigned()
 | |
|                 total_nnzs = total_nnzs + nnzs
 | |
|                 child_indices.append(total_nnzs)
 | |
|         self._child_indices = child_indices
 | |
|         self._nnz = total_nnzs
 | |
| 
 | |
|     def _child_name(self, outer_index, inner_index):
 | |
|         if self._row_major:
 | |
|             return "[{0},{1}]".format(outer_index, inner_index)
 | |
|         else:
 | |
|             return "[{1},{0}]".format(outer_index, inner_index)
 | 
