def solve_path2(s1, s2): """ Input: s1 and s2: strs of ratelaws; variable is 'X' solve_for: 'X' or 'J' #idx_root: 0 or 1, since there can be two roots (if v1 - v2 == 0 # is a quadratic equation) Output: A tuple of (X string, J string) """ if 'inf' in s1 and 'inf' in s2: raise ValueError elif 'inf' in s1: Xstr = str(sympy.solve(s1.replace('inf', '1'), 'X', simplify=True)[0]) Jstr = exprmanip.simplify_expr(exprmanip.sub_for_var(s2, 'X', Xstr)) elif 'inf' in s2: Xstr = str(sympy.solve(s2.replace('inf', '1'), 'X', simplify=True)[0]) Jstr = exprmanip.simplify_expr(exprmanip.sub_for_var(s1, 'X', Xstr)) else: eqn = '(%s) - (%s)' % (s1, s2) roots = sympy.solve(eqn, 'X', simplify=True) if len(roots) == 2: # choose the positive root (can be the 1st or the 2nd of the two) bools = ['+ sqrt' in str(sympy.expand(root)) for root in roots] idx = bools.index(True) Xstr = str(roots[idx]) else: Xstr = str(roots[0]) Jstr = exprmanip.simplify_expr(exprmanip.sub_for_var(s1, 'X', Xstr)) """ try: xsol = str(roots[1]) varids = list(exprmanip.extract_vars(xsol)) tests = [] for i in range(10): subs = dict(zip(varids, np.random.lognormal(size=len(varids)))) subs['sqrt'] = np.sqrt tests.append(eval(xsol, subs) > 0) if not all(tests): raise ValueError except (IndexError, ValueError): xsol = str(roots[0]) """ return Xstr, Jstr
def test_sub_for_var(self): cases = [ ('x', 'x', 'y', 'y'), ('x + 1', 'x', 'y', 'y + 1'), ('f(x)**2 - y + z', 'x', 'y*z/(x-2)', 'f(y*z/(x-2))**2 - y + z'), ('x**2', 'x', 'y+2', '(y+2)**2'), ('p[0]**x', 'x', 'y+2', 'p[0]**(y+2)'), ('g(x, y, f(z)) != y+2 and z == y', 'z', 'y', '(g(x, y, f(y)) != (y + 2)) and (y == y)'), ] for expr, out_var, in_expr, answer in cases: subbed = ExprManip.sub_for_var(expr, out_var, in_expr) assert eval(answer) == eval(subbed)
def replace_varid(self, varid_old, varid_new, only_expr=False): """Change id of reaction, species, or parameter. :param only_expr: bool; if True, only replace varid in expressions such as reaction ratelaws or assignment rules but not variable ids; useful when varid_new == 'varid_old * r' """ if only_expr: f = lambda varid: varid else: f = lambda varid: varid_new if varid == varid_old else varid netid_new = f(self.id) net_new = self.__class__(netid_new) for var in self.variables: var_new = copy.deepcopy(var) var_new.id = f(var.id) net_new.variables.set(var_new.id, var_new) for rxn in self.reactions: rxn_new = copy.deepcopy(rxn) rxn_new.id = f(rxn.id) rxn_new.stoichiometry = OD( zip(map(f, rxn.stoichiometry.keys()), rxn.stoichiometry.values())) try: rxn_new.reactant_stoichiometry =\ OD(zip(map(f, rxn.reactant_stoichiometry.keys()), rxn.reactant_stoichiometry.values())) rxn_new.product_stoichiometry =\ OD(zip(map(f, rxn.product_stoichiometry.keys()), rxn.product_stoichiometry.values())) except AttributeError: # some rxns have no reactant/product stoich pass rxn_new.parameters = set(map(f, rxn.parameters)) rxn_new.kineticLaw = exprmanip.sub_for_var(rxn.kineticLaw, varid_old, varid_new) net_new.reactions.set(rxn_new.id, rxn_new) for varid, rule in self.assignmentRules.items(): net_new.assignmentRules.set( f(varid), exprmanip.sub_for_var(rule, varid_old, varid_new)) for varid, rule in self.algebraicRules.items(): net_new.algebraicRules.set( exprmanip.sub_for_var(varid, varid_old, varid_new), exprmanip.sub_for_var(rule, varid_old, varid_new)) for varid, rule in self.rateRules.items(): net_new.rateRules.set( f(varid), exprmanip.sub_for_var(rule, varid_old, varid_new)) for eid, event in self.events.items(): eid_new = f(eid) trigger_new = exprmanip.sub_for_var(event.trigger, varid_old, varid_new) assignments_new = OD( zip(map(f, event.event_assignments.keys()), event.event_assignments.values())) net_new.add_event(eid_new, trigger_new, assignments_new) net_new.functionDefinitions = self.functionDefinitions.copy() for fid, f in net_new.functionDefinitions.items(): fstr = 'lambda %s: %s' % (','.join(f.variables), f.math) net_new.namespace[fid] = eval(fstr, net_new.namespace) # _makeCrossReferences will take care of at least the following # attributes: # assignedVars, constantVars, optimizableVars, dynamicVars, # algebraicVars net_new._makeCrossReferences() return net_new