def ell_valign(v: np.ndarray, x: np.ndarray) -> np.ndarray: if (not is_numeric(v)) or (not is_numeric(x)): throw_error('wrongInput:v,x', 'ELL_VALIGN: both arguments must be vectors in R^n.') if v.size != max(v.shape): throw_error('wrongInput:v', 'ELL_VALIGN: first argument must be a vector.') if x.size != max(x.shape): throw_error('wrongInput:x', 'ELL_VALIGN: second argument must be a vector.') if v.ndim == 0: v = np.expand_dims(v, axis=0) else: v = np.squeeze(v) if x.ndim == 0: x = np.expand_dims(x, axis=0) else: x = np.squeeze(x) if v.shape[0] != x.shape[0]: throw_error('wrongInput:v,x', 'ELL_VALIGN: both vectors must be of the same dimension.') u1_mat, _, v1_mat = svd(np.expand_dims(v, axis=1), full_matrices=True) u2_mat, _, v2_mat = svd(np.expand_dims(x, axis=1), full_matrices=True) v2_mat = v2_mat[0, 0] v1_mat = v1_mat[0, 0] t_mat = v1_mat * v2_mat * u1_mat @ u2_mat.T return t_mat
def compare_m_mat_with_numerics(m_mat, cor_mat, res_mat): def cmp_up_to_digits(first_num_str, second_num_str, n_cmp_digits): first_list = first_num_str.split('.') second_list = second_num_str.split('.') is_res_ok = first_list[0] == second_list[0] and len( first_list) == len(second_list) if is_res_ok and len(first_list) > 1: is_res_ok = first_list[1][0:n_cmp_digits - 1] == \ second_list[1][0:n_cmp_digits - 1] return is_res_ok is_num_mat = np.reshape( [is_numeric(el) for el in list(m_mat.flatten())], m_mat.shape) if np.any(is_num_mat.flatten()): if not np.array_equal(cor_mat[~is_num_mat], res_mat[~is_num_mat]): return False if not np.all(is_num_mat.flatten()): if not np.all( np.array([ cmp_up_to_digits(cor_el, res_el, TestSym.__N_COMPARE_DECIMAL_DIGITS) for cor_el, res_el in zip(list(cor_mat[is_num_mat]), list(res_mat[is_num_mat])) ])): return False return True
def sort_rows_tol(inp_mat: np.ndarray, tol: float) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: if tol < 0.: throw_error('wrongInput:tol', 'tol is expected to be a positive number') if not (inp_mat.ndim == 2 and is_numeric(inp_mat)): throw_error('wrongInput:inp_mat', 'input is expected to be a numeric matrix') copy_inp_mat = np.copy(inp_mat) n_cols = np.size(copy_inp_mat, 1) n_rows = np.size(copy_inp_mat, 0) if n_rows > 0: res_mat = np.copy(copy_inp_mat) for i_col in range(n_cols): ind_col_sort_vec = np.argsort(copy_inp_mat[:, i_col]) col_vec = copy_inp_mat[ind_col_sort_vec, i_col] col_diff_vec = np.diff(col_vec) is_less_vec = np.abs(col_diff_vec) <= tol col_diff_vec[is_less_vec] = 0. col_vec = np.cumsum(np.hstack((col_vec[0], col_diff_vec))) ind_col_rev_sort_vec = np.argsort(ind_col_sort_vec) copy_inp_mat[:, i_col] = col_vec[ind_col_rev_sort_vec] ind_sort_vec = np.lexsort(np.fliplr(copy_inp_mat).T) res_mat = res_mat[ind_sort_vec] else: res_mat = copy_inp_mat ind_sort_vec = np.empty((0, ), dtype=np.float64) ind_rev_sort_vec = np.argsort(ind_sort_vec) return res_mat, ind_sort_vec, ind_rev_sort_vec
def reg_mat(inp_mat: np.ndarray, reg_tol: float) -> np.ndarray: if not (np.isscalar(reg_tol) and is_numeric(reg_tol) and reg_tol > 0.): throw_error('wrongInput:reg_tol', 'reg_tol must be a positive numeric scalar') reg_tol = try_treat_as_real(reg_tol) u_mat, s_vec, v_mat = np.linalg.svd(inp_mat) s_mat = np.diag(np.maximum(s_vec, reg_tol)) res_mat = u_mat @ s_mat @ v_mat return res_mat
def sphere_tri(depth: int) -> Tuple[np.ndarray, np.ndarray]: def normvert(x: np.ndarray) -> np.ndarray: return x / ml.repmat(np.sqrt(np.sum(x * x, 1)).reshape(-1, 1), 1, 3) if not (np.isscalar(depth) and is_numeric(np.array(depth)) and 0 <= depth == np.fix(depth)): throw_error('wrong_input', 'depth is expected to be a non-negative integer scalar') v_mat, f_mat = icosahedron() v_mat, f_mat = shrink_face_tri(v_mat, f_mat, 0, depth, normvert) return v_mat, f_mat
def ell_sim_diag(a_mat: np.ndarray, b_mat: np.ndarray, abs_tol: float) -> np.ndarray: if not (is_numeric(a_mat) and is_numeric(b_mat)): throw_error('wrongInput', 'both arguments must be numeric matrices') if not is_mat_pos_def(a_mat, abs_tol): throw_error( 'wrongInput:a_mat', 'first argument must be a symmetric positive definite matrix') if not is_mat_symm(b_mat): throw_error('wrongInput:b_mat', 'second argument must be a symmetric matrix') if a_mat.shape[0] != b_mat.shape[0]: throw_error('wrongInput', 'both matrices must be of the same dimension') u1_mat, s_vec, _ = np.linalg.svd(a_mat, full_matrices=True) u_mat = np.linalg.lstsq( sqrtm_pos(np.diag(s_vec), abs_tol).T, u1_mat.T, -1)[0].T u2_mat, _, _ = np.linalg.svd(u_mat.T @ b_mat @ u_mat) return u2_mat.T @ u_mat.T
def sphere_tri_ext(n_dim: int, n_points: int, return_f_grid: bool = False) \ -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]: def spherebndr_2d(n_points_2d: int, return_f_vec: bool = False) -> \ Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]: bp_mat = circle_part(n_points_2d) if return_f_vec: f_mat = np.vstack( (np.arange(0, n_points_2d), np.arange(1, n_points_2d + 1))).T f_mat[n_points_2d - 1, 1] = 0 return bp_mat, f_mat return bp_mat def spherebndr_3d(n_points_3d: int) -> Tuple[np.ndarray, np.ndarray]: sphere_triang_num = calc_depth(n_points_3d) bp_mat, f_mat = sphere_tri(sphere_triang_num) return bp_mat, f_mat def calc_depth(num_points: int) -> int: # Initial icosaeder parameters: __VERTICES_NUM = 12 __FACES_NUM = 20 __EDGES_NUM = 30 vert_num = __VERTICES_NUM face_num = __FACES_NUM edge_num = __EDGES_NUM # cur_depth = 0 is_stop = False while not is_stop: cur_depth = cur_depth + 1 vert_num = vert_num + edge_num edge_num = 2 * edge_num + 3 * face_num face_num = 4 * face_num is_stop = vert_num >= num_points triang_depth = cur_depth return triang_depth if not (np.isscalar(n_points) and is_numeric(np.array(n_points)) and 0 < n_points == np.fix(n_points)): throw_error( 'wrong_input', 'n_points is expected to be a positive integer scalar number') if n_dim == 2: if return_f_grid: v_grid_mat, f_grid_mat = spherebndr_2d(n_points, return_f_grid) else: v_grid_mat = spherebndr_2d(n_points) v_grid_mat[np.equal(v_grid_mat, 0)] = np.finfo(float).eps return v_grid_mat else: v_grid_mat, f_grid_mat = spherebndr_3d(n_points) v_grid_mat[np.equal(v_grid_mat, 0)] = np.finfo(float).eps return v_grid_mat, f_grid_mat
def reg_pos_def_mat(inp_mat: np.ndarray, reg_tol: float) -> np.ndarray: if not (np.isscalar(reg_tol) and is_numeric(reg_tol) and np.real(reg_tol) > 0.0): throw_error('wrongInput:reg_tol', 'reg_tol must be a positive numeric scalar') reg_tol = try_treat_as_real(reg_tol) if not (is_mat_symm(inp_mat)): throw_error('wrongInput:inp_mat', 'matrix must be symmetric') d_mat, v_mat = np.linalg.eig(inp_mat) m_mat = np.diag(np.maximum(0.0, reg_tol - d_mat)) m_mat = v_mat @ m_mat @ v_mat.T regular_mat = inp_mat + m_mat regular_mat = 0.5 * (regular_mat + regular_mat.T) return regular_mat
def try_treat_as_real(inp_mat: Union[bool, int, float, complex, np.ndarray], tol_val: float = np.finfo(float).eps) \ -> np.ndarray: if not (np.isscalar(tol_val) and is_numeric(tol_val) and tol_val > 0.0): throw_error('wrongInput:tol_val', 'tol_val must be a positive numeric scalar') if np.all(np.isreal(inp_mat)): return inp_mat else: img_inp_mat = inp_mat.imag if np.isscalar(img_inp_mat): norm_value = np.abs(img_inp_mat) else: norm_value = linalg.norm(img_inp_mat, np.inf) if norm_value < tol_val: return np.real(inp_mat.real) else: throw_error( 'wrongInput:inp_mat', 'Norm of imaginary part of source object = {}. It can not be more then tol_val = {}.' .format(norm_value, tol_val))
def rep_mat(self, shape_vec: Union[Iterable, np.ndarray]) -> np.ndarray: shape_vec = np.array(shape_vec) if not is_numeric(shape_vec): throw_error('wrongInput:shape_vec', 'size array should be numeric') shape_vec = try_treat_as_real(shape_vec) if shape_vec.size == 0 or shape_vec.size != np.max(shape_vec.shape): throw_error( 'wrongInput:shape_vec', 'size vector must have at least two elements and be not a matrix' ) shape_vec = shape_vec.flatten() if not np.all( np.logical_and(shape_vec == np.fix(shape_vec), shape_vec >= 0)): throw_error( 'wrongInput:shape_vec', 'size vector must contain non-negative integer values') n_elems = np.prod(shape_vec).flatten()[0] shape_vec = tuple(shape_vec) ell_arr = np.empty((n_elems, ), dtype=np.object) for i_elem in range(n_elems): ell_arr[i_elem] = self._get_single_copy() ell_arr = np.reshape(ell_arr, shape_vec) return ell_arr
def quad_mat(q_mat: np.ndarray, x_vec: np.ndarray, c_vec: Union[int, float, np.ndarray] = 0., mode: str = 'plain') -> float: if not is_numeric(q_mat): throw_error('wrongInput:q_mat', 'q_mat must be numeric') if not is_numeric(x_vec): throw_error('wrongInput:x_vec', 'x_vec must be numeric') if not is_numeric(c_vec): throw_error('wrongInput:c_vec', 'c_vec must be numeric') if mode.lower() not in ['plain', 'inv', 'invadv']: throw_error('wrongInput:mode', 'mode must be one of the next types: ' + "'plain', 'inv', 'invadv'") if q_mat.ndim != 2: throw_error('wrongInput:q_mat', 'q_mat must be a matrix') q_matm_elems, q_matn_elems = q_mat.shape if q_matm_elems != q_matn_elems: throw_error('wrongInput:q_mat', 'q_mat must be square') if x_vec.ndim > 2: throw_error('wrongInput:x_vec', 'x_vec must be a vector') elif x_vec.ndim == 1: x_vec = np.expand_dims(x_vec, axis=0) x_vecm_elems, x_vecn_elems = x_vec.shape if x_vecm_elems > 1 and x_vecn_elems > 1: throw_error('wrongInput:x_vec', 'x_vec must be a vector') elif x_vecm_elems > 1: x_vec = x_vec.T x_vecn_elems = x_vec.shape[1] c_vec = np.array(c_vec, dtype=np.float64) if c_vec.size == 1 and np.all(c_vec.flatten()[0] == 0.): c_vec = np.zeros((1, x_vecn_elems), dtype=np.float64) elif c_vec.ndim > 2: throw_error('wrongInput:c_vec', 'c_vec must be a vector') elif c_vec.ndim <= 1: c_vec = np.reshape(c_vec, (1, c_vec.size)) if x_vecn_elems != q_matn_elems: throw_error('wrongInput:q_mat:x_vec', 'Dimensions of q_mat and x_vec must be coordinated') c_vecm_elems, c_vecn_elems = c_vec.shape if (c_vecm_elems > 1) & (c_vecn_elems > 1): throw_error('wrongInput:c_vec', 'c_vec must be a vector') elif c_vecm_elems > 1: c_vec = c_vec.T c_vecn_elems = c_vec.shape[1] if c_vecn_elems != q_matn_elems: throw_error('wrongInput:q_mat:c_vec', 'Dimensions of q_mat and c_vec must be coordinated') if mode.lower() == 'plain': res = np.dot(x_vec - c_vec, q_mat @ (x_vec - c_vec).T) elif mode.lower() == 'invadv': res = np.dot(x_vec - c_vec, inv_mat(q_mat) @ (x_vec - c_vec).T) else: res = (x_vec - c_vec) @ np.linalg.lstsq(q_mat, (x_vec - c_vec).T, -1)[0] return res
def comp_fun(x, y, comp_abs_tol: float, comp_rel_tol: float) -> Tuple[bool, str]: comp_report_str = '' x_dtype = np.asarray(x).dtype.kind y_dtype = np.asarray(y).dtype.kind x_type = type(x) if x_type != type(y) or x_dtype != y_dtype: comp_report_str = 'Different types' return False, comp_report_str if is_numeric(x) and x_type != list: x_arr = np.array(x) y_arr = np.array(y) x_shape_vec = x_arr.shape y_shape_vec = y_arr.shape if x_shape_vec != y_shape_vec: comp_report_str = 'Different sizes (left: {}, right: {})'.format( x_shape_vec, y_shape_vec) return False, comp_report_str if x_dtype in 'ui': x_arr = np.array(x_arr, dtype=np.float) y_arr = np.array(y_arr, dtype=np.float) if x_dtype == 'fc': if not np.array_equal(np.isnan(x_arr), np.isnan(y_arr)): comp_report_str = 'Nans are on the different places' return False, comp_report_str if not np.array_equal(x_arr == -np.inf, y_arr == -np.inf): comp_report_str = '-Infs are on the different places' return False, comp_report_str if not np.array_equal(x_arr == np.inf, y_arr == np.inf): comp_report_str = '+Infs are on the different places' return False, comp_report_str is_comp_arr = np.isfinite(x_arr) else: is_comp_arr = np.ones(x_arr.shape, dtype=bool) is_comp_eq, _, _, _, _, comp_report_str = abs_rel_compare( x_arr[is_comp_arr], y_arr[is_comp_arr], comp_abs_tol, comp_rel_tol, lambda z: np.abs(z)) if not is_comp_eq: comp_report_str = 'Max. ' + comp_report_str return False, comp_report_str elif x_type in [dict, list, np.ndarray]: is_dict = x_type == dict if not is_dict and x_type == np.ndarray and x.size > 0: is_dict = type(x.flatten()[0]) == dict if is_dict: is_comp_eq, comp_report_str = dict_compare( x, y, comp_abs_tol, comp_rel_tol) if not is_comp_eq: return False, comp_report_str else: n_comp_elems = len(x) if n_comp_elems == 0: return True, '' is_comp_eq = True for i_comp_elem in range(n_comp_elems): is_comp_eq, comp_report_str = comp_fun( x[i_comp_elem], y[i_comp_elem], comp_abs_tol, comp_rel_tol) if not is_comp_eq: comp_report_str = '{' + str( i_comp_elem) + '}' + comp_report_str break if not is_comp_eq: return False, comp_report_str elif x != y: return False, 'values are different' return True, comp_report_str