geometry_tools.utils.numerical
1import numpy as np 2 3def svd_kernel(mat, assume_full_rank=False, matching_rank=True, 4 tolerance=1e-8, with_dimensions=False, 5 with_loc=False): 6 7 if assume_full_rank and not matching_rank: 8 raise ValueError("matching_rank must be True if assume_full_rank is True") 9 10 _, s, v = np.linalg.svd(mat) 11 12 min_kernel_dim = max(mat.shape[-1] - mat.shape[-2], 0) 13 14 if assume_full_rank: 15 kernel_dim = min_kernel_dim 16 else: 17 small_sv = s < tolerance 18 kernel_dims = min_kernel_dim + np.count_nonzero(small_sv, axis=-1) 19 actual_ranks_match = np.all( 20 kernel_dims == np.atleast_1d(kernel_dims)[0] 21 ) 22 23 if matching_rank and not actual_ranks_match: 24 raise ValueError( 25 "Input matrices do not have matching rank. Try calling " 26 "this function with matching_rank=False." 27 ) 28 29 kernel_dim = (kernel_dims).flatten()[0] 30 31 if matching_rank: 32 return v[..., -kernel_dim:, :].swapaxes(-1, -2) 33 34 possible_dims = np.unique(kernel_dims) 35 kernel_bases = [] 36 kernel_dim_loc = [] 37 38 for kernel_dim in possible_dims: 39 where_dim = (kernel_dims == kernel_dim) 40 kernel_bases.append( 41 v[where_dim, -kernel_dim:, :].swapaxes(-1, -2) 42 ) 43 kernel_dim_loc.append(where_dim) 44 45 # flat is better than nested 46 if not with_loc and not with_dimensions: 47 return tuple(kernel_bases) 48 49 if with_dimensions and not with_loc: 50 return (possible_dims, tuple(kernel_bases)) 51 52 if with_loc and not with_dimensions: 53 return (tuple(kernel_bases), tuple(kernel_dim_loc)) 54 55 return (possible_dims, tuple(kernel_bases), tuple(kernel_dim_loc))
def
svd_kernel( mat, assume_full_rank=False, matching_rank=True, tolerance=1e-08, with_dimensions=False, with_loc=False):
4def svd_kernel(mat, assume_full_rank=False, matching_rank=True, 5 tolerance=1e-8, with_dimensions=False, 6 with_loc=False): 7 8 if assume_full_rank and not matching_rank: 9 raise ValueError("matching_rank must be True if assume_full_rank is True") 10 11 _, s, v = np.linalg.svd(mat) 12 13 min_kernel_dim = max(mat.shape[-1] - mat.shape[-2], 0) 14 15 if assume_full_rank: 16 kernel_dim = min_kernel_dim 17 else: 18 small_sv = s < tolerance 19 kernel_dims = min_kernel_dim + np.count_nonzero(small_sv, axis=-1) 20 actual_ranks_match = np.all( 21 kernel_dims == np.atleast_1d(kernel_dims)[0] 22 ) 23 24 if matching_rank and not actual_ranks_match: 25 raise ValueError( 26 "Input matrices do not have matching rank. Try calling " 27 "this function with matching_rank=False." 28 ) 29 30 kernel_dim = (kernel_dims).flatten()[0] 31 32 if matching_rank: 33 return v[..., -kernel_dim:, :].swapaxes(-1, -2) 34 35 possible_dims = np.unique(kernel_dims) 36 kernel_bases = [] 37 kernel_dim_loc = [] 38 39 for kernel_dim in possible_dims: 40 where_dim = (kernel_dims == kernel_dim) 41 kernel_bases.append( 42 v[where_dim, -kernel_dim:, :].swapaxes(-1, -2) 43 ) 44 kernel_dim_loc.append(where_dim) 45 46 # flat is better than nested 47 if not with_loc and not with_dimensions: 48 return tuple(kernel_bases) 49 50 if with_dimensions and not with_loc: 51 return (possible_dims, tuple(kernel_bases)) 52 53 if with_loc and not with_dimensions: 54 return (tuple(kernel_bases), tuple(kernel_dim_loc)) 55 56 return (possible_dims, tuple(kernel_bases), tuple(kernel_dim_loc))