def _fit_patches(self, X, y): self._check_params(X) num_samples, _, _, _, _, _, _ = self._get_dims() S = self._create_s_matrix(X) R = self._create_r_matrix() print("Solving the ridge problem...", end='') if self.solver == "primal": c = np.linalg.lstsq( S.T @ S + num_samples * (self.lbd * R + self.mu * np.eye(S.shape[1])), S.T @ y, rcond=None, )[0] elif self.solver == "dual": if self.lbd == 0: c = (S.T @ np.linalg.inv(S @ S.T + num_samples * self.mu * np.eye(S.shape[0])) @ y) else: B = num_samples * ( self.mu * sparse.eye(S.shape[1], format="csc") + self.lbd * R) B_inv = sparse_inv(B) c = (B_inv @ S.T @ np.linalg.inv(S @ B_inv @ S.T + np.eye(S.shape[0])) @ y) else: raise ValueError( f"solver must be 'primal' or 'dual', got '{self.solver}'") print(" OK.") self._R, self._S, self._spline_coef = R, S, c
def cal_surface_gf(self, E, order=2, delta=0.000001, epsilon=0.000001): I = sparse_eye(self.size).tocsc() if order == 1: ws = (E + 1j * delta) * I - self.D00 wb = (E + 1j * delta) * I - self.D11 else: ws = ((E + 1j * delta)**2) * I - self.D00 wb = ((E + 1j * delta)**2) * I - self.D11 tau1 = self.D01 tau2 = tau1.H while abs(tau1).max() > epsilon: wb_I = sparse_inv(wb) ws = ws - tau1 * wb_I * tau2 wb = wb - tau1 * wb_I * tau2 - tau2 * wb_I * tau1 tau1 = tau1 * wb_I * tau1 tau2 = tau2 * wb_I * tau2 self.gf = sparse_inv(ws)
def cal_surface_gf(self, E, order=2, delta=0.000001, epsilon=0.000001): I = sparse_eye(self.size).tocsc() if order == 1: ws = (E + 1j*delta)*I - self.D00 wb = (E + 1j*delta)*I - self.D11 else: ws = ((E + 1j*delta)**2)*I - self.D00 wb = ((E + 1j*delta)**2)*I - self.D11 tau1 = self.D01 tau2 = tau1.H while abs(tau1).max() > epsilon: wb_I = sparse_inv(wb) ws = ws - tau1*wb_I*tau2 wb = wb - tau1*wb_I*tau2 - tau2*wb_I*tau1 tau1 = tau1*wb_I*tau1 tau2 = tau2*wb_I*tau2 self.gf= sparse_inv(ws)
def cal_diag_gf(self): """ calculate diagonal green's function for center area. """ length = self.length g = self.g # forward iterating g[0] = sparse_inv(self.M(0, 0)) for j in range(1, length): g[j] = sparse_inv(self.M(j, j) - self.M(j, j-1)*g[j-1]*self.M(j-1, j)) G = self.gf G[self.length - 1][self.length - 1] = g[self.length - 1] # calculate more green's function according to the flag # backward iterating for j in list(range(self.length - 1))[::-1]: G[j][j] = g[j] + g[j]*self.M(j, j+1)*G[j+1][j+1]*self.M(j+1, j)*g[j]
def cal_diag_gf(self): """ calculate diagonal green's function for center area. """ length = self.length g = self.g # forward iterating g[0] = sparse_inv(self.M(0, 0)) for j in range(1, length): g[j] = sparse_inv( self.M(j, j) - self.M(j, j - 1) * g[j - 1] * self.M(j - 1, j)) G = self.gf G[self.length - 1][self.length - 1] = g[self.length - 1] # calculate more green's function according to the flag # backward iterating for j in list(range(self.length - 1))[::-1]: G[j][j] = g[j] + g[j] * self.M( j, j + 1) * G[j + 1][j + 1] * self.M(j + 1, j) * g[j]
def LBOAproximation(v, f, scalar_function, k, cls='half_cotangent'): eig_vals, eig_vects = laplacian_spectrum(v, f, k, cls) M = barycenter_vertex_mass_matrix(v, f) L = Laplacian(v, f, cls) scalar_function_hat = eig_vects @ eig_vects.T @ M @ scalar_function normlized_laplacian_scalarFunc = sparse_inv( csc_matrix(M)) @ L @ scalar_function return scalar_function_hat, normlized_laplacian_scalarFunc
def LaplacianDiscreteMeanCurveture(v, f, cls='half_cotangent', W=None): L = Laplacian(v, f, cls, W=W) M = barycenter_vertex_mass_matrix(v, f) Hn = sparse_inv(csc_matrix(M)) @ L @ v #Hn = sparse_inv(M) @ L @ v Hn_abs = np.linalg.norm(Hn, axis=1) #Get curveture sign by checking direction of curveture and the normal mesh = Mesh(v=v, f=f) normals = mesh.vertexNormals() Hn_normlized = Hn / Hn_abs.reshape((len(v), 1)) Hn_signs = np.sign(np.diag(Hn_normlized @ normals.T)) Hn_scalarFunc = Hn_abs * Hn_signs return Hn_scalarFunc
def solve_flows( net: nx.Graph, boundary_conditions: Dict[str, float], root: Union[List[str], str] = None, viscosity=1., ): # root must be a list of nodes assert root is not None if isinstance(root, str): root = [root] # convert viscosity to (mmHg s) units _viscosity = viscosity * 1e-6 * 7.5006 # define internal and external nodes internal_nodes = [node for node, k in net.degree if k > 1] external_nodes = [node for node, k in net.degree if k == 1] # index to label conversions for nodes nodes_idx2label = dict(enumerate(net.nodes)) nodes_label2idx = {v: k for k, v in nodes_idx2label.items()} # sparse matrices to solve the linear algebra problem N = len(net.nodes) b = dok_matrix((N, 1)) S = dok_matrix((N, N)) # initial condition p = np.zeros(N) # set pressure of root for node, press in boundary_conditions.items(): p[nodes_label2idx[node]] = press # fill in coefficients for u, v in net.edges: r = net[u][v]["radius"] length = net[u][v]["length"] cij = np.math.pi * (2 * r)**4 / (128 * _viscosity * length) i = nodes_label2idx[u] j = nodes_label2idx[v] if u in internal_nodes: S[i, i] += cij S[j, i] += -cij else: b[j] += cij * p[i] if v in internal_nodes: S[j, j] += cij S[i, j] += -cij else: b[i] += cij * p[j] bb = [x in internal_nodes for x in net.nodes] SS = csc_matrix(S.todense()[bb].T[bb].T) # solve the system # i.e. find pressure at each node SS_inv = sparse_inv(SS) sol = SS_inv.dot(csc_matrix(b.todense()[bb])) pressure_internal = dict(zip(internal_nodes, (sol.toarray().T[0]))) pressure_external = dict( zip(external_nodes, p[[x in external_nodes for x in net.nodes]])) pressure_all_nodes = {**pressure_internal, **pressure_external} # fill in network with pressure and flows dinet = nx.DiGraph() dinet.add_nodes_from(net.nodes) # copy over node positions dd = nx.get_node_attributes(net, "position") nx.set_node_attributes(dinet, dd, "position") # write pressures dict nx.set_node_attributes(dinet, pressure_all_nodes, "pressure") edge_attrs = {} pressure_dict = nx.get_node_attributes(dinet, "pressure") for i, (u, v) in enumerate(net.edges): # get its properties pu = pressure_dict[u] pv = pressure_dict[v] r = net[u][v]["radius"] length = net[u][v]["length"] cij = np.math.pi * (2 * r)**4 / (128 * _viscosity * length) flow = cij * (pu - pv) if flow < 0: flow = -flow u, v = v, u speed = flow / (np.math.pi * r**2) time = length / speed # create the edge dinet.add_edge(u, v) # save properties in dict entry edge_attrs[(u, v)] = { "flow": flow, "speed": speed, "time": time, "radius": r, "length": length } nx.set_edge_attributes(dinet, edge_attrs) return dinet
def solve_flows(self, root: Union[List[str], str] = None, viscosity=1., iterative_min_rad=1, bin_s=0.3, cc_idx=0, force_root: bool = False): """ Solve the flows problem. Parameters ---------- root: str Label of root node in the format "FJ????_submesh?_node?". viscosity: float The viscosity of blood, relative to water = 1. iterative_min_rad: float In iterative solving mode, sets the radius below wich nodes' preassure is *not* updated iteratively. bin_s: float In iterative solving mode, radius tolerance to infer pressures. cc_idx: int Which connected compoent (from large to small) to use force_root: bool If passed source node is not a viable root, force it to be by adding a phantom node. """ # root must be a list of nodes assert root is not None if isinstance(root, str): root = [root] # convert viscosity to (mmHg s) units self.viscosity = viscosity * 1e-6 * 7.5006 # get largest connected component cc = nx.connected_component_subgraphs(self.network) sorted_cc = sorted(cc, key=len, reverse=True) net = sorted_cc[cc_idx] # if root has not degree 1, force it if force_root: _root = [] for roo in root: if net.degree[roo] > 1: sroo = "source_" + roo net.add_node(sroo) r = np.mean( [net[roo][v]["radius"] for v in net.neighbors(roo)]) net.add_edge(sroo, roo, radius=r, length=1) _root.append(sroo) else: _root.append(roo, ) root = _root self.fill_missing_radiuses() # define internal and external nodes internal_nodes = [node for node, k in net.degree if k > 1] external_nodes = [node for node, k in net.degree if k == 1] for roo in root: if roo not in external_nodes: raise RuntimeError( f"Node {roo} was passed as source node but is not a leaf") # index to label conversions for nodes nodes_idx2label = dict(enumerate(net.nodes)) nodes_label2idx = {v: k for k, v in nodes_idx2label.items()} # sparse matrices to solve the linear algebra problem N = len(net.nodes) b = dok_matrix((N, 1)) S = dok_matrix((N, N)) # initial condition p = np.zeros(N) + 20 # set pressure of root for roo in root: p[nodes_label2idx[roo]] = 100 # if not first iteration, guess boundary conditions if self.solved: # auxiliar df to infer pressures p_dict = nx.get_node_attributes(self.network_solved, "pressure") r_dict = nx.get_node_attributes(self.network, "radius") df = pd.DataFrame(data=[r_dict, p_dict], index=["radius", "pressure"]).T.dropna() # set boundary conditions of external nodes except root for node in external_nodes: if node not in root: i = nodes_label2idx[node] target_r = df.loc[node, "radius"] if target_r > iterative_min_rad: inferred_p = infer_pressure(df=df, target_r=target_r, bin_s=bin_s) p[i] = inferred_p # fill in coefficients for u, v in net.edges: r = net[u][v]["radius"] length = net[u][v]["length"] cij = np.math.pi * (2 * r)**4 / (128 * self.viscosity * length) i = nodes_label2idx[u] j = nodes_label2idx[v] if u in internal_nodes: S[i, i] += cij S[j, i] += -cij else: b[j] += cij * p[i] if v in internal_nodes: S[j, j] += cij S[i, j] += -cij else: b[i] += cij * p[j] bb = [x in internal_nodes for x in net.nodes] SS = csc_matrix(S.todense()[bb].T[bb].T) # solve the system # i.e. find pressure at each node SS_inv = sparse_inv(SS) sol = SS_inv.dot(csc_matrix(b.todense()[bb])) pressure_internal = dict(zip(internal_nodes, (sol.toarray().T[0]))) pressure_external = dict( zip(external_nodes, p[[x in external_nodes for x in net.nodes]])) pressure_all_nodes = {**pressure_internal, **pressure_external} # fill in network with pressure and flows dinet = nx.DiGraph() dinet.add_nodes_from(net.nodes) # copy over node positions dd = nx.get_node_attributes(net, "position") nx.set_node_attributes(dinet, dd, "position") # write pressures dict nx.set_node_attributes(dinet, pressure_all_nodes, "pressure") # mark the system as solved self.solved = True edge_attrs = {} pressure_dict = nx.get_node_attributes(dinet, "pressure") for i, (u, v) in enumerate(net.edges): # get its properties pu = pressure_dict[u] pv = pressure_dict[v] r = net[u][v]["radius"] length = net[u][v]["length"] cij = np.math.pi * (2 * r)**4 / (128 * self.viscosity * length) flow = cij * (pu - pv) if flow < 0: flow = -flow u, v = v, u speed = flow / (np.math.pi * r**2) time = length / speed # create the edge dinet.add_edge(u, v) # save properties in dict entry edge_attrs[(u, v)] = { "flow": flow, "speed": speed, "time": time, "radius": r, "length": length } nx.set_edge_attributes(dinet, edge_attrs) self.network_solved = dinet
def __call__(self, fluxes, concentrations, parameters, flux_jacobian=False): """ :param fluxes: `Dict` or `pd.Series` of reference flux vector :param concentrations: `Dict` or `pd.Series` of reference concentration vector :param parameters: `Dict` or `pd.Series` of reference parameters vector """ # TODO: # Attention the Fluxes and concentrations need to be sorted # according to the model! if self.volume_ratio_function is None: volume_ratios = array([ 1, ] * len(concentrations)) else: volume_ratios = self.volume_ratio_function(parameters) #Calculate the Jacobian flux_matrix = diags(array(fluxes), 0).tocsc() # Elasticity matrix if self.conservation_relation.nnz == 0: volume_ratio_matrix_indep = diags(array(volume_ratios)).tocsc() concentration_matrix = diags(array(concentrations)).tocsc() inv_concentration_matrix = sparse_inv(concentration_matrix) elasticity_matrix = self.independent_elasticity_function( concentrations, parameters) else: # We need to get only the concentrations of the independent metabolites ix = self.independent_variable_ix volume_ratio_matrix_indep = diags(array(volume_ratios)[ix]).tocsc() inv_volume_ratio_matrix_indep = sparse_inv( volume_ratio_matrix_indep) ix_dep = self.dependent_variable_ix volume_ratio_matrix_dep = diags( array(volume_ratios)[ix_dep]).tocsc() concentration_matrix = diags(array(concentrations)[ix]).tocsc() inv_concentration_matrix = sparse_inv(concentration_matrix) elasticity_matrix = self.independent_elasticity_function( concentrations, parameters) dependent_weights = self.dependent_elasticity_function.\ get_dependent_weights( concentration_vector=concentrations, L0=self.conservation_relation, all_dependent_ix=self.dependent_variable_ix, all_independent_ix=self.independent_variable_ix, volume_ratios=volume_ratios ) elasticity_matrix += self.dependent_elasticity_function(concentrations, parameters)\ .dot(dependent_weights) if flux_jacobian: jacobian = flux_matrix.dot(elasticity_matrix)\ .dot(inv_concentration_matrix)\ .dot(volume_ratio_matrix_indep)\ .dot(self.reduced_stoichometry) else: jacobian = volume_ratio_matrix_indep.dot(self.reduced_stoichometry)\ .dot(flux_matrix)\ .dot(elasticity_matrix)\ .dot(inv_concentration_matrix) return jacobian
def __call__(self, flux_dict, concentration_dict, parameter_population): # Calculate the Concentration Control coefficients # Log response of the concentration with respect to the log change in a Parameter # # C_Xi_P = -(N_r*V*E_i + N_r*V*E_d*Q_i)(N_r*V*Pi) # fluxes = [flux_dict[r] for r in self.model.reactions] # Only consider independent concentrations concentrations = [concentration_dict[r] for r in self.model.reactants] num_parameters = len( self.parameter_elasticity_function.respective_variables) num_concentration = len(self.independent_variable_ix) population_size = len(parameter_population) concentration_control_coefficients = zeros( (num_concentration, num_parameters, population_size)) for i, parameters in enumerate(parameter_population): flux_matrix = diags(array(fluxes), 0).tocsc() if self.volume_ratio_function is None: volume_ratios = array([ 1, ] * len(concentrations)) else: volume_ratios = self.volume_ratio_function(parameters) # Elasticity matrix if self.conservation_relation.nnz == 0: # If there are no moieties volume_ratio_matrix = diags(array(volume_ratios)).tocsc() elasticity_matrix = self.independent_elasticity_function( concentrations, parameters) else: # If there are moieties ix = self.independent_variable_ix volume_ratio_matrix = diags(array(volume_ratios)[ix]).tocsc() elasticity_matrix = self.independent_elasticity_function( concentrations, parameters) dependent_weights = self.dependent_elasticity_function.\ get_dependent_weights( concentration_vector=concentrations, L0=self.conservation_relation, all_dependent_ix=self.dependent_variable_ix, all_independent_ix=self.independent_variable_ix, volume_ratios=volume_ratios ) # Calculate the effective elasticises elasticity_matrix += self.dependent_elasticity_function(concentrations, parameters)\ .dot(dependent_weights) N_E_V = volume_ratio_matrix.dot(self.reduced_stoichometry).dot( flux_matrix).dot(elasticity_matrix) N_E_V_inv = sparse_inv(N_E_V) parameter_elasticity_matrix = self.parameter_elasticity_function( concentrations, parameters) N_E_P = volume_ratio_matrix.dot(self.reduced_stoichometry).dot( flux_matrix).dot(parameter_elasticity_matrix) this_cc = -N_E_V_inv.dot(N_E_P) concentration_control_coefficients[:, :, i] = this_cc.todense() concentration_index = pd.Index([ self.model.reactants.iloc(i)[0] for i in self.independent_variable_ix ], name="concentration") parameter_index = pd.Index( self.parameter_elasticity_function.respective_variables, name="parameter") sample_index = pd.Index(range(population_size), name="sample") tensor_ccc = Tensor( concentration_control_coefficients, [concentration_index, parameter_index, sample_index]) return tensor_ccc