def test_simplify(): x = sympy.Symbol('x') y = sympy.Symbol('y') p1 = Parameter('x', 3) p2 = Parameter('y', 9, fix=True) pset = Parameters([p1, p2]) assert pset.simplify(x * y) == 9.0 * x p1 = Parameter('x', 3, lower=0.001) p2 = Parameter('y', 9) pset = Parameters([p1, p2]) assert pset.simplify(abs(x)) == x p1 = Parameter('x', 3, lower=0) p2 = Parameter('y', 9) pset = Parameters([p1, p2]) assert pset.simplify(sympy.Piecewise((2, sympy.Ge(x, 0)), (56, True))) == 2 p1 = Parameter('x', -3, upper=-1) p2 = Parameter('y', 9) pset = Parameters([p1, p2]) assert pset.simplify(abs(x)) == -x p1 = Parameter('x', -3, upper=0) p2 = Parameter('y', 9) pset = Parameters([p1, p2]) assert pset.simplify(sympy.Piecewise((2, sympy.Le(x, 0)), (56, True))) == 2 p1 = Parameter('x', 3) p2 = Parameter('y', 9) pset = Parameters([p1, p2]) assert pset.simplify(x * y) == x * y
def border_conditions(direction, field, ghost_layers=1): abs_direction = tuple(-e if e < 0 else e for e in direction) assert sum(abs_direction) == 1 idx = abs_direction.index(1) val = direction[idx] loop_ctrs = [ LoopOverCoordinate.get_loop_counter_symbol(i) for i in range(len(direction)) ] loop_ctr = loop_ctrs[idx] gl = ghost_layers border_condition = sp.Eq(loop_ctr, gl if val < 0 else field.shape[idx] - gl - 1) if ghost_layers == 0: return type_all_numbers(border_condition, loop_ctr.dtype) else: other_min = [sp.Ge(c, gl) for c in loop_ctrs if c != loop_ctr] other_max = [ sp.Lt(c, field.shape[i] - gl) for i, c in enumerate(loop_ctrs) if c != loop_ctr ] result = sp.And(border_condition, *other_min, *other_max) return type_all_numbers(result, loop_ctr.dtype)
def _sub_question_or_entity(context, p, q, is_question): """Generates entity or question for subtraction p - q.""" value = p.value - q.value if is_question: templates = [ '{p} - {q}', 'Work out {p} - {q}.', 'What is {p} minus {q}?', 'What is {p} take away {q}?', 'What is {q} less than {p}?', 'Subtract {q} from {p}.', 'Calculate {p} - {q}.', 'What is {p} - {q}?', ] if sympy.Ge(p.value, q.value): # We calculate p - q, so the difference (|p - q|) is the correct answer. for adjective in ['distance', 'difference']: for pair in ['{p} and {q}', '{q} and {p}']: templates.append('What is the {} between {}?'.format(adjective, pair)) template = random.choice(templates) return example.Problem( question=example.question(context, template, p=p, q=q, problem_type='sub'), answer=value) else: return composition.Entity( context=context, value=value, description='Let {self} = {p} - {q}.', p=p, q=q, problem_type='sub')
def extreme(fn, over, maximizing): """Maximizes [minimizes] the function fn for 'over'. Returns the first extreme expression and a list of conditions for it to be a maximum [minimum]. >>> sp.var('x p', positive=True) (x, p) >>> theta = sp.Symbol('theta', positive=True) >>> fn = p*x - theta*x*x >>> maximize(fn, x) (p/(2*theta), 0 < theta) >>> maximize(fn.subs(theta, 1), x) (p/2, 0 <= p) >>> maximize(fn.subs(theta, -1), x) (None, False) """ first = sp.diff(fn, over) extremes_at = sp.solve(first, over) second = sp.diff(first, over) for m in extremes_at: positive = False try: ## We only want values of over that are positive. positive = sp.solve(sp.Ge(m, 0)) except: ## Inequality solve only works with a single variable. ## Assume it is true. We are missing a condition. positive = True ## Checking for inequality to False because an inequality will ## evaluate as False even if present in positive if positive is not False: conditions = [] if positive is not True: conditions.append(positive) try: if maximizing: max_min_cond = sp.solve(sp.Lt(second.subs(over, m), 0)) else: max_min_cond = sp.solve(sp.Gt(second.subs(over, m), 0)) except: ## Not always works. Assume it is true. We are ## missing a condition. max_min_cond = True if max_min_cond: if max_min_cond is not True: conditions.append(max_min_cond) return m, reduce(sp.And, [True] + conditions) return None, False
def supply(self): """ >>> sp.var('p q', positive=True) (p, q) >>> f = Firm(q, p, q**2/1000., SFC=1000) >>> f.supply() Piecewise((0, p < 1000.0), (500.0*p, And(0 <= p, p >= 1000.0))) >>> f = Firm(q, p, 10*q, SFC=0, FC=0) >>> f.supply() p - 10 == 0 """ min_atc, min_atc_cond = self.min_atc_sfc() supply, supply_cond = tools.maximize(self.earnings(), over=self.q) if supply is None: return sp.Eq(sp.diff(self.earnings(), self.q), 0) return sp.Piecewise( (0, sp.Lt(self.p, min_atc)), (supply, sp.And(sp.Ge(self.p, min_atc), supply_cond, min_atc_cond)))
def _sub_question_or_entity(context, p, q, is_question): """Generates entity or question for subtraction p - q.""" value = p.value - q.value if is_question: # templates = [ # '{p} - {q}', # 'Work out {p} - {q}.', # 'What is {p} minus {q}?', # 'What is {p} take away {q}?', # 'What is {q} less than {p}?', # 'Subtract {q} from {p}.', # 'Calculate {p} - {q}.', # 'What is {p} - {q}?', # ] templates = [ '{p} - {q}', 'Рассчитайте {p} - {q}.', 'Сколько будет {p} минус {q}?', 'Сколько будет {p} отнять {q}?', 'Какое число на {q} меньше {p}?', 'Отнимите {q} от {p}.', 'Вычислите {p} - {q}.', 'Чему равно {p} - {q}?', ] if sympy.Ge(p.value, q.value): # We calculate p - q, so the difference (|p - q|) is the correct answer. for adjective in ['разница']: for pair in ['{p} и {q}', '{q} и {p}']: templates.append('Чему равна {} {}?'.format(adjective, pair)) template = random.choice(templates) return example.Problem( question=example.question(context, template, p=p, q=q), answer=value) else: return composition.Entity( context=context, value=value, description='Пусть {self} = {p} - {q}.', p=p, q=q)
def evaluate(self, values): return sp.simplify(self.lhs.subs(values, simultaneous=True) % self.rhs) == 0 def validate(self, t, f, k, n, closed_form): to_validated = self.lhs.subs({sp.Symbol('_PRS_x%d' % i): closed_form[i] for i in range(closed_form.shape[0])}, simultaneous=True) res = [] for i in t: check = my_simplify(to_validated.subs(n, k*n + i), n) if sp.Eq(check % self.rhs, 0) != True: for x in range(999999999999): if sp.Eq(check % self.rhs, 0) != True: res.append((False, x*k + i)) break else: res.append((True, -1)) for i in f: check = my_simplify(to_validated.subs(n, k*n + i), n) # print(check) if sp.Eq(check % self.rhs, 0): for x in range(999999999999): if sp.Eq(check % self.rhs, 0): res.append((False, x*k + i)) break else: res.append((True, -1)) return res if __name__ == '__main__': x1, x2 = sp.symbols('x1 x2') cond = PolyCondition(sp.Ge(x1 + x2, 1)) print(cond.evaluate({x1: 10, x2: -20}))
def sum_over_piecewise(expr: sympy.Piecewise, sum_var: sympy.Symbol, sum_start: typing.Union[sympy.Basic, int], sum_end: sympy.Basic, extra_condition: sympy.Basic = True) -> sympy.Expr: """ :return: equivalent to Sum(expr, (sum_var, sum_start, sum_end)), but we try to remove the piecewise. We assume that the piecewise conditions also depend on sum_var. """ assert sum_var.is_Integer or sum_var.assumptions0["integer"] assert isinstance(expr, sympy.Piecewise) res = sympy.sympify(0) cond_start = sympy.Ge(sum_var, sum_start) cond_end = sympy.Le(sum_var, sum_end) prev_ranges = [(None, sum_start - 1), (sum_end + 1, None)] def check(cond__): false_cond = simplify_and(sympy.And(sympy.Not(cond__), extra_condition)) if false_cond == sympy.sympify(False): return True true_cond = simplify_and(sympy.And(cond__, extra_condition)) if true_cond == sympy.sympify(False): return False return None for value, cond in expr.args: j = 0 while j < len(prev_ranges) - 1: cond_r_start = sympy.Ge(sum_var, prev_ranges[j][1] + 1) cond_r_end = sympy.Le(sum_var, prev_ranges[j + 1][0] - 1) cond = sympy.And(cond, cond_start, cond_end, cond_r_start, cond_r_end) cond_ = simplify_and(cond, sum_var, extra_conditions=extra_condition) # print(cond, "->", cond_) if cond_ == sympy.sympify(False): j += 1 continue if isinstance(cond_, sympy.And): if any( [sum_var not in part.free_symbols for part in cond_.args]): new_extra_conditions = [ part for part in cond_.args if sum_var not in part.free_symbols ] new_extra_condition = sympy.And(*new_extra_conditions) if check(new_extra_condition) is False: j += 1 continue assert check(new_extra_condition) cond_ = sympy.And(*[ part for part in cond_.args if sum_var in part.free_symbols ]) r = range_from_relationals(cond_, sum_var) if r[0] is None: # e.g. if cond_start == True because sum_var is >= 0 always r = (sum_start, r[1]) if sympy.Eq(r[0], r[1]) == sympy.sympify(True): res += value.subs(sum_var, r[0]) else: res += sympy.Sum(value, (sum_var, r[0], r[1])).doit() for i in range(1, len(prev_ranges) + 1): assert i < len(prev_ranges), "where to insert %r?" % ( r, ) # should not get past here assert check(sympy.Gt(r[0], prev_ranges[i - 1][1])) if check(sympy.Eq(r[0] - 1, prev_ranges[i - 1][1])): prev_ranges[i - 1] = (prev_ranges[i - 1][0], r[1]) break if check(sympy.Lt(r[0], prev_ranges[i][0])) or check( sympy.Lt(r[1], prev_ranges[i][0])): if check(sympy.Eq(r[1] + 1, prev_ranges[i][0])): prev_ranges[i] = (r[0], prev_ranges[i][1]) else: prev_ranges.insert(i, r) break # print("prev ranges:", prev_ranges) j = 0 # start over... if len(prev_ranges) == 2 and sympy.Eq( prev_ranges[0][1], prev_ranges[1][0]) == sympy.sympify(True): # We have the full range covered. break return res.simplify()
def gen_greaterthaneq(self, ident, val): return sym.Ge(val.exp_a, val.exp_b)
# Methods that have a `__foo__` as well as `__rfoo__` reflectable_magic_methods = { 'add': lambda a, b: a + b, 'sub': lambda a, b: a - b, 'mul': lambda a, b: a * b, 'mod': lambda a, b: a % b, } magic_methods = { **reflectable_magic_methods, 'eq': lambda a, b: sympy.Eq(a, b), 'gt': lambda a, b: sympy.Gt(a, b), 'lt': lambda a, b: sympy.Lt(a, b), 'le': lambda a, b: sympy.Le(a, b), 'ge': lambda a, b: sympy.Ge(a, b), } for method, _func in magic_methods.items(): method_name = f'{method}' def _create_magic_impl(func): def magic_impl(self, other): if isinstance(other, PySymInt): other = other.expr return PySymInt(func(self.expr, other), self.shape_env) return magic_impl # this should be wrapped transparently into torch._C.SymIntNode setattr(PySymInt, method_name, _create_magic_impl(_func))
def _ex_more_equal(self, e): return sp.Ge(self.ex(e[0]), self.ex(e[1]))
def __kkts(self): alpha_st_kkts = sp.Matrix( np.diag(np.array(self.alphas.T * self.__subject_to_func().T))) alpha_kkts = sp.Matrix([sp.Ge(alpha, 0) for alpha in self.alphas]) st_kkts = sp.Matrix([sp.Le(st, 0) for st in self.__subject_to_func()]) return alpha_st_kkts, alpha_kkts, st_kkts
def test_reader_writer(self): # Test using the proper reader/writer try: import sympy as sp except ImportError: print('Sympy not found, skipping test.') return # Create writer and reader w = mypy.SymPyExpressionWriter() r = mypy.SymPyExpressionReader(self._model) # Name a = self._a ca = sp.Symbol('c.a') self.assertEqual(w.ex(a), ca) self.assertEqual(r.ex(ca), a) # Number with unit b = myokit.Number('12', 'pF') cb = sp.Float(12) self.assertEqual(w.ex(b), cb) # Note: Units are lost in sympy im/ex-port! #self.assertEqual(r.ex(cb), b) # Number without unit b = myokit.Number('12') cb = sp.Float(12) self.assertEqual(w.ex(b), cb) self.assertEqual(r.ex(cb), b) # Prefix plus x = myokit.PrefixPlus(b) self.assertEqual(w.ex(x), cb) # Note: Sympy doesn't seem to have a prefix plus self.assertEqual(r.ex(cb), b) # Prefix minus # Note: SymPy treats -x as Mul(NegativeOne, x) # But for numbers just returns a number with a negative value x = myokit.PrefixMinus(b) self.assertEqual(w.ex(x), -cb) self.assertEqual(float(r.ex(-cb)), float(x)) # Plus x = myokit.Plus(a, b) self.assertEqual(w.ex(x), ca + cb) # Note: SymPy likes to re-order the operands... self.assertEqual(float(r.ex(ca + cb)), float(x)) # Minus x = myokit.Minus(a, b) self.assertEqual(w.ex(x), ca - cb) self.assertEqual(float(r.ex(ca - cb)), float(x)) # Multiply x = myokit.Multiply(a, b) self.assertEqual(w.ex(x), ca * cb) self.assertEqual(float(r.ex(ca * cb)), float(x)) # Divide x = myokit.Divide(a, b) self.assertEqual(w.ex(x), ca / cb) self.assertEqual(float(r.ex(ca / cb)), float(x)) # Quotient x = myokit.Quotient(a, b) self.assertEqual(w.ex(x), ca // cb) self.assertEqual(float(r.ex(ca // cb)), float(x)) # Remainder x = myokit.Remainder(a, b) self.assertEqual(w.ex(x), ca % cb) self.assertEqual(float(r.ex(ca % cb)), float(x)) # Power x = myokit.Power(a, b) self.assertEqual(w.ex(x), ca**cb) self.assertEqual(float(r.ex(ca**cb)), float(x)) # Sqrt x = myokit.Sqrt(a) cx = sp.sqrt(ca) self.assertEqual(w.ex(x), cx) # Note: SymPy converts sqrt to power self.assertEqual(float(r.ex(cx)), float(x)) # Exp x = myokit.Exp(a) cx = sp.exp(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Log(a) x = myokit.Log(a) cx = sp.log(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Log(a, b) x = myokit.Log(a, b) cx = sp.log(ca, cb) self.assertEqual(w.ex(x), cx) self.assertEqual(float(r.ex(cx)), float(x)) # Log10 x = myokit.Log10(b) cx = sp.log(cb, 10) self.assertEqual(w.ex(x), cx) self.assertAlmostEqual(float(r.ex(cx)), float(x)) # Sin x = myokit.Sin(a) cx = sp.sin(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Cos x = myokit.Cos(a) cx = sp.cos(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Tan x = myokit.Tan(a) cx = sp.tan(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # ASin x = myokit.ASin(a) cx = sp.asin(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # ACos x = myokit.ACos(a) cx = sp.acos(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # ATan x = myokit.ATan(a) cx = sp.atan(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Floor x = myokit.Floor(a) cx = sp.floor(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Ceil x = myokit.Ceil(a) cx = sp.ceiling(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Abs x = myokit.Abs(a) cx = sp.Abs(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Equal x = myokit.Equal(a, b) cx = sp.Eq(ca, cb) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # NotEqual x = myokit.NotEqual(a, b) cx = sp.Ne(ca, cb) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # More x = myokit.More(a, b) cx = sp.Gt(ca, cb) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Less x = myokit.Less(a, b) cx = sp.Lt(ca, cb) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # MoreEqual x = myokit.MoreEqual(a, b) cx = sp.Ge(ca, cb) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # LessEqual x = myokit.LessEqual(a, b) cx = sp.Le(ca, cb) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Not x = myokit.Not(a) cx = sp.Not(ca) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # And cond1 = myokit.More(a, b) cond2 = myokit.Less(a, b) c1 = sp.Gt(ca, cb) c2 = sp.Lt(ca, cb) x = myokit.And(cond1, cond2) cx = sp.And(c1, c2) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Or x = myokit.Or(cond1, cond2) cx = sp.Or(c1, c2) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # If # Note: sympy only does piecewise, not if x = myokit.If(cond1, a, b) cx = sp.Piecewise((ca, c1), (cb, True)) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x.piecewise()) # Piecewise c = myokit.Number(1) cc = sp.Float(1) x = myokit.Piecewise(cond1, a, cond2, b, c) cx = sp.Piecewise((ca, c1), (cb, c2), (cc, True)) self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Myokit piecewise's (like CellML's) always have a final True # condition (i.e. an 'else'). SymPy doesn't require this, so test if # we can import this --> It will add an "else 0" x = myokit.Piecewise(cond1, a, myokit.Number(0)) cx = sp.Piecewise((ca, c1)) self.assertEqual(r.ex(cx), x) # SymPy function without Myokit equivalent --> Should raise exception cu = sp.principal_branch(cx, cc) self.assertRaisesRegex(ValueError, 'Unsupported type', r.ex, cu) # Derivative m = self._model.clone() avar = m.get('c.a') r = mypy.SymPyExpressionReader(self._model) avar.promote(4) x = myokit.Derivative(self._a) cx = sp.symbols('dot(c.a)') self.assertEqual(w.ex(x), cx) self.assertEqual(r.ex(cx), x) # Equation e = myokit.Equation(a, b) ce = sp.Eq(ca, cb) self.assertEqual(w.eq(e), ce) # There's no backwards equivalent for this! # The ereader can handle it, but it becomes and Equals expression. # Test sympy division del (m, avar, x, cx, e, ce) a = self._model.get('c.a') b = self._model.get('c').add_variable('bbb') b.set_rhs('1 / a') e = b.rhs() ce = w.ex(b.rhs()) e = r.ex(ce) self.assertEqual( e, myokit.Multiply(myokit.Number(1), myokit.Power(myokit.Name(a), myokit.Number(-1)))) # Test sympy negative numbers a = self._model.get('c.a') e1 = myokit.PrefixMinus(myokit.Name(a)) ce = w.ex(e1) e2 = r.ex(ce) self.assertEqual(e1, e2)
def xml_to_sympy_expr(self, xml_node): if isTag(xml_node, '/MathML}cn'): return float(xml_node.text) elif isTag(xml_node, '/MathML}ci'): if xml_node.text not in self.symbol_table: self.symbol_table[xml_node.text] = sp.Symbol(xml_node.text) self.extra_assignments[self.symbol_table[xml_node.text]] = None return self.symbol_table[xml_node.text] elif not isTag(xml_node, '/MathML}apply'): raise ValueError("Do not know hot to parse node %s" % xml_node) try: func, *arg_children = filterTags(xml_node.getchildren()) except ValueError: raise processed_args = [] for child in arg_children: processed_args.append(self.xml_to_sympy_expr(child)) if isTag(func, '/MathML}plus'): out_expr = sp.Add(*processed_args) elif isTag(func, '/MathML}times'): out_expr = sp.Mul(*processed_args) elif isTag(func, '/MathML}power'): if len(processed_args) != 2: raise ValueError("Power is a binary operation!") out_expr = sp.Pow(*processed_args) elif isTag(func, '/MathML}divide'): if len(processed_args) != 2: raise ValueError("Division is a binary operation!") out_expr = sp.Mul(processed_args[0], sp.Pow(processed_args[1], -1)) elif isTag(func, '/MathML}minus'): if (len(processed_args) > 2) or (len(processed_args) == 0): raise ValueError("Subtraction is a unitary or binary operation!") elif len(processed_args) == 2: out_expr = sp.Add(processed_args[0], sp.Mul(processed_args[1], -1)) elif len(processed_args) == 1: out_expr = sp.Mul(processed_args[0], -1) elif isTag(func, '/MathML}abs'): if len(processed_args) != 1: raise ValueError("Absolute value is a unitary operation!") out_expr = sp.Abs(processed_args[0]) elif isTag(func, '/MathML}cos'): if len(processed_args) != 1: raise ValueError("cos is a unitary operation!") out_expr = sp.cos(processed_args[0]) elif isTag(func, '/MathML}sin'): if len(processed_args) != 1: raise ValueError("sin is a unitary operation!") out_expr = sp.sin(processed_args[0]) elif isTag(func, '/MathML}csymbol'): if func.text == 'atan2': if len(processed_args) != 2: raise ValueError("atan2 is a binary operation!") out_expr = sp.atan2(*processed_args) else: raise ValueError("Unknown csymbol %s" % func.text) elif isTag(func, '/MathML}piecewise'): *pieces, otherwise = func.getchildren() otherwise_children = filterTags(otherwise.getchildren()) conditions = [] values = [] if len(otherwise_children) != 1: raise ValueError("Too many `otherwise` children") for piece in filterTags(pieces): value_child, condition_child = filterTags(piece.getchildren()) values.append(self.xml_to_sympy_expr(value_child)) conditions.append(self.xml_to_sympy_expr(condition_child)) values.append(self.xml_to_sympy_expr(otherwise_children[0])) conditions.append(True) out_expr = sp.Piecewise(*[(value, condition) for value, condition in zip(values, conditions)]) elif isTag(func, '/MathML}lt'): if len(processed_args) != 2: raise ValueError("Less than is a binary operation!") out_expr = sp.Le(*processed_args) elif isTag(func, '/MathML}gt'): if len(processed_args) != 2: raise ValueError("Greater than is a binary operation!") out_expr = sp.Gt(*processed_args) elif isTag(func, '/MathML}leq'): if len(processed_args) != 2: raise ValueError("Less than equal to is a binary operation!") out_expr = sp.Le(*processed_args) elif isTag(func, '/MathML}geq'): if len(processed_args) != 2: raise ValueError("Greater than equal to is a binary operation!") out_expr = sp.Ge(*processed_args) else: raise ValueError("Unknown func tag, %s" % func.tag) if out_expr is None: raise ValueError("Calculated None") else: return out_expr
], ), ( '$PRED\nIF (X.EQ.0) THEN ; anything \n Y = 23\nZ = 9\nEND IF;AFTER', [ (S('Y'), sympy.Piecewise((23, sympy.Eq(S('X'), 0)))), (S('Z'), sympy.Piecewise((9, sympy.Eq(S('X'), 0)))), ], ), ( '$PRED\nIF (NEWIND.NE.2.OR.EVID.GE.3) THEN ; begin\nTNXD=TIME ; TIME\nENDIF', [( S('TNXD'), sympy.Piecewise((S('TIME'), sympy.Or(sympy.Ne(S('NEWIND'), 2), sympy.Ge(S('EVID'), 3)))), )], ), ( '$PRED IF (B0.LT.3) THEN\nCL = THETA(1)\nELSE;A close comment\nCL = 23\nENDIF', [(S('CL'), sympy.Piecewise((S('THETA(1)'), S('B0') < 3), (23, True)))], ), ( '$PRED\nIF(MIXNUM.EQ.3) THEN\n TVCL=THETA(1) ; CL in population 1\nELSE\n ' 'TVCL=THETA(2) ; CL in population 2\nENDIF\n', [( S('TVCL'), sympy.Piecewise((S('THETA(1)'), sympy.Eq(S('MIXNUM'), 3)), (S('THETA(2)'), True)), )],