def parse_ode(lines, varnames): """ Input: Output: list of SparsePolynomial representing this ODE system ordered as variables in the ring """ eqs_raw = dict() plhs = re.compile("d\((\w+)\)") for l in lines: if plhs.search(l): lhs, rhs = l.split("=") lhs = plhs.search(lhs).groups(1)[0] rhs = rhs.strip() eqs_raw[lhs] = rhs var_to_ind = {v: i for i, v in enumerate(varnames)} eqs = dict() for lhs, rhs in eqs_raw.items(): if lhs not in varnames: raise ValueError(f"Variable {lhs} is not in the list of variables") try: eqs[lhs] = SparsePolynomial.from_string(rhs, varnames, var_to_ind) except TypeError as e: print(rhs) print(e) for v in varnames: if v not in eqs: eqs[v] = SparsePolynomial(varnames, QQ) return [eqs[v] for v in varnames]
def parse_reactions(lines, varnames): """ Input: lines with reactions, each reaction of the form "reactants -> products, rate" and varnames Output: the list of corresponding equations """ raw_reactions = [] var_to_ind = {v: i for i, v in enumerate(varnames)} for l in lines: if "," not in l: continue reaction, rate = separate_reation_rate(l) lhs, rhs = reaction.split("->") raw_reactions.append((lhs.strip(), rhs.strip(), rate.strip())) eqs = {v: SparsePolynomial(varnames, QQ) for v in varnames} for lhs, rhs, rate in raw_reactions: rate_poly = SparsePolynomial.from_string(rate, varnames, var_to_ind) ldict = species_to_multiset(lhs) rdict = species_to_multiset(rhs) monomial = tuple((var_to_ind[v], mult) for v, mult in ldict.items()) reaction_poly = rate_poly * SparsePolynomial(varnames, QQ, {monomial: QQ(1)}) for v, mult in rdict.items(): eqs[v] += reaction_poly * mult for v, mult in ldict.items(): eqs[v] += reaction_poly * (-mult) return [eqs[v] for v in varnames]
def construct_matrices_from_rational_functions(rational_functions): """ Computes Jacobian, pulls out common denominator, and constructs matrices J_1^T, ..., J_N^T from the remaining polynomial matrix Input - rational_functions - the right-hand side of the system of ODEs (f_1, ..., f_n) represented by RationalFunction Output a list of matrices (SparseMatrix) J_1^T, ..., J_N^T """ logging.debug("Starting constructing matrices (RationalFunction)") variables = rational_functions[0].gens field = rational_functions[0].domain # Compute Jacobian J = [[rf.derivative(v) for rf in rational_functions] for v in variables] def lcm_rec(arr, l, u): if u - l == 1: return arr[l] mid = (u + l) // 2 res = SparsePolynomial.lcm( [lcm_rec(arr, l, mid), lcm_rec(arr, mid, u)]) return res denoms = [rf.denom for rf in rational_functions] d = list( filter((lambda x: x != SparsePolynomial.from_string("1", [])), denoms)) lcm = lcm_rec(d, 0, len(d)) lcm = lcm * lcm p = [lcm // (denom * denom) for denom in denoms] # Pull out the common denominator poly_J = [] for i in range(len(J)): poly_J_row = [] for j in range(len(J[i])): poly_J_row.append(J[i][j].num * p[j]) poly_J.append(poly_J_row) # Work with remaining polynomial matrix as in construct_matrices_from_polys jacobians = dict() for row_ind, poly_row in enumerate(poly_J): for col_ind, poly in enumerate(poly_row): p_ind = row_ind * len(poly_row) + col_ind logging.debug("Processing numerator polynomial number %d", p_ind) for m, coef in poly.dataiter(): if m not in jacobians: jacobians[m] = SparseRowMatrix(len(variables), field) jacobians[m].increment(row_ind, col_ind, coef) return jacobians.values()
def from_string(s, varnames, var_to_ind = None): """ Parsing a string to a rational function, sting is allowed to include floating-point numbers in the standard and scientific notation, they will be converted to rationals IMPORTANT: String must contain only one "/"! """ if "/" not in s: num_str = s denom_str = "1" else: split = s.split("/") if len(split) == 2: num_str = split[0] denom_str = split[1] else: raise NotImplementedError num = SparsePolynomial.from_string(num_str, varnames, var_to_ind) denom = SparsePolynomial.from_string(denom_str, varnames, var_to_ind) return RationalFunction(num, denom)
def extract_observables(lines, varnames): """ Input: lines of the partitions section Output: list of SparsePolynomial representing the observables """ var_to_ind = {v : i for i, v in enumerate(varnames)} sets = [m.groups(1)[0] for m in re.finditer("\{([^\{\}]*)\}", " ".join(lines))] observables = [] for s in sets: obs_as_str = "+".join(re.split("\s*,\s*", s)) obs_poly = SparsePolynomial.from_string(obs_as_str, varnames, var_to_ind) observables.append(obs_poly) return observables
# lumping = do_lumping( # system["equations"], # [SparsePolynomial.from_string("C3GActive", system["variables"])], # print_reduction=False, # discard_useless_matrices=True, # ) # time += timeit.default_timer() - start # print("Average Time: ", time/N) # check_lumping("BIOMD0000000033", system["equations"], lumping) # MODEL1502270000 system = read_system("../examples/RationalFunctions/MODEL1502270000.ode") lumping = do_lumping( system["equations"], [SparsePolynomial.from_string("gmax*Kp+a", system["variables"])], print_reduction=False, discard_useless_matrices=True, ) print("Lumping Size: ", len(lumping['rhs'])) check_lumping("MODEL1502270000", system["equations"], lumping) lumping = do_lumping( system["equations"], [SparsePolynomial.from_string("si", system["variables"])], print_reduction=False, discard_useless_matrices=False, ) print("Lumping Size: ", len(lumping['rhs'])) check_lumping("MODEL1502270000", system["equations"], lumping) # print(lumping)
# Model generated from: # Borisov, N. M., Chistopolsky, A. S., Faeder, J. R., & Kholodenko, B. N. # Domain-oriented reduction of rule-based network models. IET systems biology, 2(5), 342-351, 2008. # Source: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2628550/bin/NIHMS80246-supplement-Supplement_4.doc ## import sys import time from sympy import QQ sys.path.insert(0, "../") sys.path.insert(0, "./../../") import parser import clue from sparse_polynomial import SparsePolynomial system = parser.read_system("OrderedPhosphorylation.ode") obs = SparsePolynomial.from_string("s0", system['variables']) start = time.time() lumped = clue.do_lumping(system['equations'], [obs]) end = time.time() print(f"The size of the original model is {len(system['equations'])}") print(f"The size of the reduced model is {len(lumped['polynomials'])}") print(f"Computation took {end - start} seconds")
from sympy import QQ sys.path.insert(0, "../") sys.path.insert(0, "./../../") import parser import clue from sparse_polynomial import SparsePolynomial system = parser.read_system("BIOMD0000000504.ode") obs_sets = [["cFos_P", "cJun_P"], ["MMP1_mRNA", "MMP13_mRNA", "TIMP1_mRNA"], ["MMP1", "MMP13", "ColFrag"], [ "JAK1_P", "JNK_P", "cJun_P", "cJun_dimer", "STAT3_P_nuc", "STAT3_P_cyt" ]] for obs_set in obs_sets: print("===============================================") obs_polys = [ SparsePolynomial.from_string(s, system['variables']) for s in obs_set ] start = time.time() lumped = clue.do_lumping(system['equations'], obs_polys) end = time.time() print(f"The size of the original model is {len(system['equations'])}") print(f"The size of the reduced model is {len(lumped['polynomials'])}") print(f"Computation took {end - start} seconds")
############################################### obss = { "BIOMD0000000504.ode": [["cFos_P", "cJun_P"], ["MMP1_mRNA", "MMP13_mRNA", "TIMP1_mRNA"], ["MMP1", "MMP13", "ColFrag"], ["JAK1_P", "JNK_P", "cJun_P", "cJun_dimer", "STAT3_P_nuc", "STAT3_P_cyt"]], "fceri_ji.ode": [["S0"], ["S2", "S178", "S267", "S77"], ["S2 + S178 + S267 + S77"], ["S7"], ["S1"]], "e2.ode": [["S0"], ["S1"]], "Barua.ode": [["aS000"], ["aS027"]] } if __name__ == "__main__": path = sys.argv[1] name = path[path.rindex('/') + 1:] system = read_system("{0}".format(path)) obs_sets = obss[name] for obs_set in obs_sets: obs_polys = [ SparsePolynomial.from_string(s, system['variables']) for s in obs_set ] do_lumping(system["equations"], obs_polys)
lumped_polys_values = [evalp(p, specialization_lumped) for p in lumped_system] assert(polys_values_lumped == lumped_polys_values) print(test_name + ": lumping is correct") ############################################### if __name__ == "__main__": # Example 1 R = sympy.polys.rings.vring(["x0", "x1", "x2"], QQ) polys = [x0**2 + x1 + x2, x2, x1] lumping = do_lumping(polys, [x0], print_reduction=False, initial_conditions={"x0" : 1, "x1" : 2, "x2" : 5}) check_lumping("Example 1", polys, lumping, 2) assert lumping["new_ic"] == [QQ(1), QQ(7)] # Example 2 polys = [x1**2 + 4 * x1 * x2 + 4 * x2**2, x1 + 2 * x0**2, x2 - x0**2] lumping = do_lumping(polys, [x0], print_reduction=False) check_lumping("Example 2", polys, lumping, 2) # PP for n = 2 system = read_system("e2.ode") lumping = do_lumping( system["equations"], [SparsePolynomial.from_string("S0", system["variables"])], print_reduction=False ) check_lumping("PP for n = 2", system["equations"], lumping, 12) ############################################
rf2dx_expected = RationalFunction.from_string("(2*y**2*x)/(z**2)", varnames) rf2dx_test = rf2.derivative('x') print("Expected: \t", rf2dx_expected) print("Actual: \t", rf2dx_test) rf2dz_expected = RationalFunction.from_string("(-(2*x**2*y**2))/(z**3)", varnames) rf2dz_test = rf2.derivative('z') print("Expected: \t", rf2dz_expected) print("Actual: \t", rf2dz_test) rf = RationalFunction.from_string("(x)/(2 * y**2)", varnames) rf_dz = rf.derivative('z') print(rf_dz) sp1 = SparsePolynomial.from_string("2*x**23 + 4", ['x']) sp2 = SparsePolynomial.from_string("2*x**23 + 4", ['x']) assert sp1 == sp2 rf1 = RationalFunction.from_string("x/y",['x','y']) rf2 = RationalFunction.from_string("x/y",['x','y']) assert rf1 == rf2 print("--- LCM Test --------------------------------------------------------") sp1 = SparsePolynomial.from_string("x*y**2 + x**2*y", ['x','y']) sp2 = SparsePolynomial.from_string("x**2*y**2", ['x','y']) lcm = SparsePolynomial.lcm([sp1,sp2]) print("Expected: \t", "x**2*y**3 + x**3*y**2") print("Actual: \t", lcm) print("--- Division Test ---------------------------------------------------") sp1 = SparsePolynomial.from_string("x**2 - 1", ['x'])
# A stochastic model of Escherichia coli AI‐2 quorum signal circuit reveals alternative synthesis pathways. # Molecular systems biology, 2(1), 2006 # Source: https://www.ebi.ac.uk/biomodels/MODEL8262229752 ## import sys import time from sympy import QQ sys.path.insert(0, "../") sys.path.insert(0, "./../../") import parser import clue from sparse_polynomial import SparsePolynomial system = parser.read_system("MODEL8262229752.ode") obs = [ SparsePolynomial.from_string("Pfs_mRNA", system['variables']), SparsePolynomial.from_string("LuxS_mRNA", system['variables']), SparsePolynomial.from_string("AI2_intra", system['variables']) ] start = time.time() lumped = clue.do_lumping(system['equations'], obs) end = time.time() print(f"The size of the original model is {len(system['equations'])}") print(f"The size of the reduced model is {len(lumped['polynomials'])}") print(f"Computation took {end - start} seconds")
def perform_change_of_variables(self, rhs, new_vars_name='y'): """ Restrict a system of ODEs with the rhs given by rhs (SparsePolynomial or RationalFunction) to the subspace new_vars_name (optional) - the name for variables in the lumped polynomials """ old_vars = rhs[0].gens domain = rhs[0].domain new_vars = [new_vars_name + str(i) for i in range(self.dim())] pivots = set(self.parametrizing_coordinates()) lpivots = sorted(pivots) basis = self.basis() logging.debug("Constructing new rhs") if isinstance(rhs[0], SparsePolynomial): new_rhs = [ SparsePolynomial(old_vars, domain) for _ in range(self.dim()) ] elif isinstance(rhs[0], RationalFunction): new_rhs = [ RationalFunction( SparsePolynomial(old_vars, domain), SparsePolynomial.from_string("1", old_vars, domain)) for _ in range(self.dim()) ] for i, vec in enumerate(basis): logging.debug(f" Equation number {i}") for j in vec.nonzero_iter(): # ordering is important due to the implementation of # multiplication for SparsePolynomial new_rhs[i] += rhs[j] * vec._data[j] logging.debug("Plugging zero to nonpivot coordinates") if isinstance(rhs[0], SparsePolynomial): shrinked_polys = [] for p in new_rhs: filtered_dict = dict() for monom, coef in p.dataiter(): new_monom = [] skip = False for var, exp in monom: if var not in pivots: skip = True break else: new_monom.append((lpivots.index(var), exp)) if not skip: new_monom = tuple(new_monom) filtered_dict[new_monom] = coef shrinked_polys.append( SparsePolynomial(new_vars, domain, filtered_dict)) return shrinked_polys elif isinstance(rhs[0], RationalFunction): # plugging all nonpivot variables with zeros shrinked_rfs = [] for rf in new_rhs: num_filtered_dict = dict() for monom, coef in rf.num.dataiter(): new_monom = [] skip = False for var, exp in monom: if var not in pivots: skip = True break else: new_monom.append((lpivots.index(var), exp)) if not skip: new_monom = tuple(new_monom) num_filtered_dict[new_monom] = coef new_num = SparsePolynomial(new_vars, domain, num_filtered_dict) denom_filtered_dict = dict() for monom, coef in rf.denom.dataiter(): new_monom = [] skip = False for var, exp in monom: if var not in pivots: skip = True break else: new_monom.append((lpivots.index(var), exp)) if not skip: new_monom = tuple(new_monom) denom_filtered_dict[new_monom] = coef new_denom = SparsePolynomial(new_vars, domain, denom_filtered_dict) if new_denom.is_zero() and False: print() print("Before plugging all nonpivot variables with zeros:") print('\t', rf) print() print("After plugging all nonpivot variables with zeros:") print('\t', f"({new_num})/({new_denom})") print() raise ZeroDivisionError shrinked_rfs.append(RationalFunction(new_num, new_denom)) return shrinked_rfs
import sys import time from sympy import QQ sys.path.insert(0, "../") sys.path.insert(0, "./../../") import parser import clue from sparse_polynomial import SparsePolynomial system = parser.read_system("BIOMD0000000033.ode") obs = SparsePolynomial.from_string("AktInactive", system['variables']) start = time.time() lumped = clue.do_lumping(system['equations'], [obs], print_system=True) end = time.time() print(f"The size of the original model is {len(system['equations'])}") print(f"The size of the reduced model is {len(lumped['polynomials'])}") print(f"Computation took {end - start} seconds")
import sys import sympy from sympy import QQ sys.path.insert(0, "../") sys.path.insert(0, "./") import clue from sparse_polynomial import SparsePolynomial exprs = [ "a * (3 * a + b) - 8.5 * (a + b)**5 - 3 * c * b * (c - a)", "(a + b + c**2)**5 - 3 * a + b * 17 * 19 * 0.5" ] for e in exprs: parsed = sympy.parse_expr(e) sp = SparsePolynomial.from_string(e, ["a", "b", "c"]) assert (sympy.simplify(parsed - sympy.parse_expr(str(sp))) == 0)