def test_nested_relational(self): expr = Expression( sympy.And( sympy.Or(sympy.Eq(self.a, self.b), sympy.Eq(self.c, self.d)), sympy.Or(sympy.Eq(self.e, self.f), sympy.Lt(self.g, self.f)))) self.assertEqual(expr.rhs_cstr, '(a == b || c == d) && (e == f || g < f)')
def test_nested_relational(self): expr = Expression('((a == b) || (c == d)) && ((e == f) || (g < f))') self.assertEqual( expr.rhs, sympy.And( sympy.Or(sympy.Eq(self.a, self.b), sympy.Eq(self.c, self.d)), sympy.Or(sympy.Eq(self.e, self.f), sympy.Lt(self.g, self.f))))
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 quadratic_denom_rule(integral): integrand, symbol = integral a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) c = sympy.Wild('c', exclude=[symbol]) match = integrand.match(a / (b * symbol**2 + c)) if not match: return a, b, c = match[a], match[b], match[c] return PiecewiseRule([ (ArctanRule(a, b, c, integrand, symbol), sympy.Gt(c / b, 0)), (ArccothRule(a, b, c, integrand, symbol), sympy.And(sympy.Gt(symbol**2, -c / b), sympy.Lt(c / b, 0))), (ArctanhRule(a, b, c, integrand, symbol), sympy.And(sympy.Lt(symbol**2, -c / b), sympy.Lt(c / b, 0))), ], integrand, symbol)
def test_pheno(parser): code = """$PK IF(AMT.GT.0) BTIME=TIME TAD=TIME-BTIME TVCL=THETA(1)*WGT TVV=THETA(2)*WGT IF(APGR.LT.5) TVV=TVV*(1+THETA(3)) CL=TVCL*EXP(ETA(1)) V=TVV*EXP(ETA(2)) S1=V """ rec = parser.parse(code).records[0] assert len(rec.statements) == 8 assert rec.statements[0].symbol == S('BTIME') assert rec.statements[1].symbol == S('TAD') assert rec.statements[2].symbol == S('TVCL') assert rec.statements[3].symbol == S('TVV') assert rec.statements[4].symbol == S('TVV') assert rec.statements[5].symbol == S('CL') assert rec.statements[6].symbol == S('V') assert rec.statements[7].symbol == S('S1') assert rec.statements[0].expression == sympy.Piecewise( (S('TIME'), sympy.Gt(S('AMT'), 0)), (0, True)) assert rec.statements[1].expression == S('TIME') - S('BTIME') assert rec.statements[2].expression == S('THETA(1)') * S('WGT') assert rec.statements[3].expression == S('THETA(2)') * S('WGT') assert rec.statements[4].expression == sympy.Piecewise( (S('TVV') * (1 + S('THETA(3)')), sympy.Lt(S('APGR'), 5)), (S('TVV'), True)) assert rec.statements[5].expression == S('TVCL') * sympy.exp(S('ETA(1)')) assert rec.statements[6].expression == S('TVV') * sympy.exp(S('ETA(2)')) assert rec.statements[7].expression == S('V') symbol_names = {s.name for s in rec.statements.free_symbols} assert symbol_names == { 'AMT', 'BTIME', 'TIME', 'TAD', 'TVCL', 'THETA(1)', 'WGT', 'TVV', 'THETA(2)', 'APGR', 'THETA(3)', 'CL', 'ETA(1)', 'V', 'ETA(2)', 'S1', }
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 demand(self, rational=True): """Compute the demand as the maximization of the utility function. >>> sp.var('x p') (x, p) >>> cu = Consumer(x, p, benefit=tools.benefit_from_demand(x, p, 9/p - 1)) >>> sp.simplify(cu.benefit() - 9*sp.log(x + 1)) 0 >>> cu.demand() Piecewise((0, p < 0), ((-p + 9)/p, True)) >>> tau = sp.Symbol('tau') >>> cu_rat = Consumer(x, p, benefit=2*sp.sqrt(x)) >>> cu_del = Consumer(x, p, benefit=2*sp.sqrt(x), ... decision_benefit=20*sp.sqrt(x), ... other=-(1+tau)*p*x) >>> sp.solve(cu_del.demand(rational=False)-cu_rat.demand(), tau) [-11, 9] """ maxima, condition = tools.maximize(self.utility(rational), over=self.x) if maxima is None: maxima = 0 return sp.Piecewise((0, sp.Lt(self.p, 0)), (maxima, condition), (0, True))
def _make_comparison_question(context, left, right): """Makes a question for comparing two values.""" if random.choice([False, True]) and sympy.Ne(left.value, right.value): # Do question of form: "Which is bigger: a or b?". if random.choice([False, True]): answer = (left.handle if sympy.Gt(left.value, right.value) else right.handle) template = random.choice([ 'Which is bigger: {left} or {right}?', 'Which is greater: {left} or {right}?', ]) else: answer = (left.handle if sympy.Lt(left.value, right.value) else right.handle) template = random.choice([ 'Which is smaller: {left} or {right}?', ]) return example.Problem(question=example.question(context, template, left=left, right=right), answer=answer) comparisons = { '<': sympy.Lt, '<=': sympy.Le, '>': sympy.Gt, '>=': sympy.Ge, '=': sympy.Eq, '!=': sympy.Ne, } templates = { '<': [ 'Is {left} ' + ops.LT_SYMBOL + ' {right}?', 'Is {left} less than {right}?', 'Is {left} smaller than {right}?', ], '<=': [ 'Is {left} ' + ops.LE_SYMBOL + ' {right}?', 'Is {left} less than or equal to {right}?', 'Is {left} at most {right}?', 'Is {left} at most as big as {right}?', ], '>': [ 'Is {left} ' + ops.GT_SYMBOL + ' {right}?', 'Is {left} greater than {right}?', 'Is {left} bigger than {right}?', ], '>=': [ 'Is {left} ' + ops.GE_SYMBOL + ' {right}?', 'Is {left} greater than or equal to {right}?', 'Is {left} at least {right}?', 'Is {left} at least as big as {right}?', ], '=': [ 'Does {left} ' + ops.EQ_SYMBOL + ' {right}?', 'Are {left} and {right} equal?', 'Is {left} equal to {right}?', 'Do {left} and {right} have the same value?', ], '!=': [ 'Is {left} ' + ops.NE_SYMBOL + ' {right}?', 'Is {left} not equal to {right}?', 'Are {left} and {right} unequal?', 'Are {left} and {right} nonequal?', 'Are {left} and {right} non-equal?', 'Do {left} and {right} have different values?', ], } comparison = random.choice(list(comparisons.keys())) template = random.choice(templates[comparison]) question = example.question(context, template, left=left, right=right) answer = comparisons[comparison](left.value, right.value) return example.Problem(question=question, answer=answer)
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 simplify_and( x: sympy.Basic, gen: typing.Optional[sympy.Symbol] = None, extra_conditions: typing.Optional[sympy.Basic] = True) -> sympy.Basic: """ Some rules, because SymPy currently does not automatically simplify them... """ assert isinstance(x, sympy.Basic), "type x: %r" % type(x) from sympy.solvers.inequalities import reduce_rational_inequalities from sympy.core.relational import Relational syms = [] if gen is not None: syms.append(gen) w1 = sympy.Wild("w1") w2 = sympy.Wild("w2") for sub_expr in x.find(sympy.Eq(w1, w2)): m = sub_expr.match(sympy.Eq(w1, w2)) ws_ = m[w1], m[w2] for w_ in ws_: if isinstance(w_, sympy.Symbol) and w_ not in syms: syms.append(w_) for w_ in x.free_symbols: if w_ not in syms: syms.append(w_) if len(syms) >= 1: _c = syms[0] if len(syms) >= 2: n = syms[1] else: n = sympy.Wild("n") else: return x x = x.replace(((_c - 2 * n >= -1) & (_c - 2 * n <= -1)), sympy.Eq(_c, 2 * n - 1)) # probably not needed anymore... apply_rules = True while apply_rules: apply_rules = False for and_expr in x.find(sympy.And): assert isinstance(and_expr, sympy.And) and_expr_ = reduce_rational_inequalities([and_expr.args], _c) # print(and_expr, "->", and_expr_) if and_expr_ != and_expr: x = x.replace(and_expr, and_expr_) and_expr = and_expr_ if and_expr == sympy.sympify(False): continue if isinstance(and_expr, sympy.Rel): continue assert isinstance(and_expr, sympy.And) and_expr_args = list(and_expr.args) # for i, part in enumerate(and_expr_args): # and_expr_args[i] = part.simplify() if all([ isinstance(part, Relational) and _c in part.free_symbols for part in and_expr_args ]): # No equality, as that should have been resolved above. rel_ops = ["==", ">=", "<="] if not (_c.is_Integer or _c.assumptions0["integer"]): rel_ops.extend(["<", ">"]) rhs_by_c = {op: [] for op in rel_ops} for part in and_expr_args: assert isinstance(part, Relational) part = _solve_inequality(part, _c) assert isinstance(part, Relational) assert part.lhs == _c rel_op, rhs = part.rel_op, part.rhs if _c.is_Integer or _c.assumptions0["integer"]: if rel_op == "<": rhs = rhs - 1 rel_op = "<=" elif rel_op == ">": rhs = rhs + 1 rel_op = ">=" assert rel_op in rhs_by_c, "x: %r, _c: %r, and expr: %r, part %r" % ( x, _c, and_expr, part) other_rhs = rhs_by_c[rel_op] assert isinstance(other_rhs, list) need_to_add = True for rhs_ in other_rhs: cmp = Relational.ValidRelationOperator[rel_op](rhs, rhs_) if simplify_and( sympy.And(sympy.Not(cmp), extra_conditions)) == sympy.sympify( False): # checks True... other_rhs.remove(rhs_) break elif simplify_and(sympy.And( cmp, extra_conditions)) == sympy.sympify(False): need_to_add = False break # else: # raise NotImplementedError("cannot compare %r in %r; extra cond %r" % (cmp, and_expr, extra_conditions)) if need_to_add: other_rhs.append(rhs) if rhs_by_c[">="] and rhs_by_c["<="]: all_false = False for lhs in rhs_by_c[">="]: for rhs in rhs_by_c["<="]: if sympy.Lt(lhs, rhs) == sympy.sympify(False): all_false = True if sympy.Eq(lhs, rhs) == sympy.sympify(True): rhs_by_c["=="].append(lhs) if all_false: x = x.replace(and_expr, False) continue if rhs_by_c["=="]: all_false = False while len(rhs_by_c["=="]) >= 2: lhs, rhs = rhs_by_c["=="][:2] if sympy.Eq(lhs, rhs) == sympy.sympify(False): all_false = True break elif sympy.Eq(lhs, rhs) == sympy.sympify(True): rhs_by_c["=="].pop(1) else: raise NotImplementedError( "cannot cmp %r == %r. rhs_by_c %r" % (lhs, rhs, rhs_by_c)) if all_false: x = x.replace(and_expr, False) continue new_parts = [sympy.Eq(_c, rhs_by_c["=="][0])] for op in rel_ops: for part in rhs_by_c[op]: new_parts.append( Relational.ValidRelationOperator[op]( rhs_by_c["=="][0], part).simplify()) else: # no "==" new_parts = [] for op in rel_ops: for part in rhs_by_c[op]: new_parts.append( Relational.ValidRelationOperator[op](_c, part)) assert new_parts and_expr_ = sympy.And(*new_parts) # print(and_expr, "--->", and_expr_) x = x.replace(and_expr, and_expr_) and_expr = and_expr_ # Probably all the remaining hard-coded rules are not needed anymore with the more generic code above... if sympy.Eq(_c, 2 * n) in and_expr.args: if (_c - 2 * n <= -1) in and_expr.args: x = x.replace(and_expr, False) continue if sympy.Eq(_c - 2 * n, -1) in and_expr.args: x = x.replace(and_expr, False) continue if (_c - n <= -1) in and_expr.args: x = x.replace(and_expr, False) continue if (_c >= n) in and_expr.args and (_c - n <= -1) in and_expr.args: x = x.replace(and_expr, False) continue if sympy.Eq(_c - 2 * n, -1) in and_expr.args: # assume n>=1 if (_c >= n) in and_expr.args: x = x.replace( and_expr, sympy.And( * [arg for arg in and_expr.args if arg != (_c >= n)])) apply_rules = True break if (_c - n >= -1) in and_expr.args: x = x.replace( and_expr, sympy.And(*[ arg for arg in and_expr.args if arg != (_c - n >= -1) ])) apply_rules = True break if (_c >= n) in and_expr.args: if (_c - n >= -1) in and_expr.args: x = x.replace( and_expr, sympy.And(*[ arg for arg in and_expr.args if arg != (_c - n >= -1) ])) apply_rules = True break if (_c - n >= -1) in and_expr.args and (_c - n <= -1) in and_expr.args: args = list(and_expr.args) args.remove((_c - n >= -1)) args.remove((_c - n <= -1)) args.append(sympy.Eq(_c - n, -1)) if (_c - 2 * n <= -1) in args: args.remove((_c - 2 * n <= -1)) x = x.replace(and_expr, sympy.And(*args)) apply_rules = True break return x
return bool(self.shape_env.evaluate_expr(self.expr)) # 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
def gen_lessthan(self, ident, val): return sym.Lt(val.exp_a, val.exp_b)
def _make_comparison_question(context, left, right): """Makes a question for comparing two values.""" if random.choice([False, True]) and sympy.Ne(left.value, right.value): # Do question of form: "Which is bigger: a or b?". if random.choice([False, True]): answer = (left.handle if sympy.Gt(left.value, right.value) else right.handle) template = random.choice([ 'Что больше: {left} или {right}?', 'Какое из чисел больше: {left} или {right}?', ]) else: answer = (left.handle if sympy.Lt(left.value, right.value) else right.handle) template = random.choice([ 'Что меньше: {left} или {right}?', 'Какое число меньше: {left} или {right}?' ]) return example.Problem(question=example.question(context, template, left=left, right=right), answer=answer) comparisons = { '<': sympy.Lt, '<=': sympy.Le, '>': sympy.Gt, '>=': sympy.Ge, '=': sympy.Eq, '!=': sympy.Ne, } templates = { '<': [ 'Правда ли, что {left} ' + ops.LT_SYMBOL + ' {right}?', '{left} меньше, чем {right}?', 'Число {left} меньше числа {right}?', ], '<=': [ 'Правда ли, что {left} ' + ops.LE_SYMBOL + ' {right}?', 'Правда ли, что {left} меньше или равно {right}?', 'Число {left} не больше {right}?', 'Число {left} не превосходит {right}?', ], '>': [ 'Правда ли, что {left} ' + ops.GT_SYMBOL + ' {right}?', '{left} больше, чем {right}?', 'Число {left} больше числа {right}?', ], '>=': [ 'Правда ли, что {left} ' + ops.GE_SYMBOL + ' {right}?', 'Правда ли, что {left} больше или равно {right}?', 'Число {left} не меньше {right}?', ], '=': [ 'Правда ли, что {left} ' + ops.EQ_SYMBOL + ' {right}?', 'Равны ли {left} и {right}?', 'Число {left} равно числу {right}?', 'Одинаковы ли {left} и {right}?', ], '!=': [ 'Правда ли, что {left} ' + ops.NE_SYMBOL + ' {right}?', 'Число {left} не равно {right}?', 'Числа {left} и {right} не равны?', 'Значения числа {left} и числа {right} отличаются?', '{left} и {right} не равны друг другу?', ], } comparison = random.choice(list(comparisons.keys())) template = random.choice(templates[comparison]) question = example.question(context, template, left=left, right=right) answer = comparisons[comparison](left.value, right.value) return example.Problem(question=question, answer=answer)
def _ex_less(self, e): return sp.Lt(self.ex(e[0]), self.ex(e[1]))
sympy.tan(S('X')) * sympy.exp(S('Y'))), ('$PRED K_ = ATAN(1) - ASIN(X)/ACOS(X)', S('K_'), sympy.atan(1) - sympy.asin(S('X')) / sympy.acos(S('X'))), ('$PRED CL = INT(-2.2)', S('CL'), -2), ('$PRED CL = INT(0.2)', S('CL'), 0), ('$PRED CL = MOD(1, 2)', S('CL'), sympy.Mod(1, 2)), ('$PRED CL = GAMLN(2 + X) ;COMMENT', S('CL'), sympy.loggamma(S('X') + 2)), ('$PRED IF (X.EQ.2) CL=23', S('CL'), sympy.Piecewise((23, sympy.Eq(S('X'), 2)))), ('$PRED IF (X.NE.1.5) CL=THETA(1)', S('CL'), sympy.Piecewise((S('THETA(1)'), sympy.Ne(S('X'), 1.5)))), ('$PRED IF (X.EQ.2+1) CL=23', S('CL'), sympy.Piecewise((23, sympy.Eq(S('X'), 3)))), ('$PRED IF (X < ETA(1)) CL=23', S('CL'), sympy.Piecewise((23, sympy.Lt(S('X'), S('ETA(1)'))))), ('$PK IF(AMT.GT.0) BTIME=TIME', S('BTIME'), sympy.Piecewise((S('TIME'), sympy.Gt(S('AMT'), 0)))), ('$PRED IF (X.EQ.2.AND.Y.EQ.3) CL=23', S('CL'), sympy.Piecewise( (23, sympy.And(sympy.Eq(S('X'), 2), sympy.Eq(S('Y'), 3))))), ('$PRED IF (X.EQ.2.OR.Y.EQ.3) CL=23', S('CL'), sympy.Piecewise( (23, sympy.Or(sympy.Eq(S('X'), 2), sympy.Eq(S('Y'), 3))))), ('$PRED IF (.NOT.X.EQ.2) CL=25', S('CL'), sympy.Piecewise((25, sympy.Not(sympy.Eq(S('X'), 2))))), ('$PRED IF (Q.EQ.(R+C)/D) L=0', S('L'), sympy.Piecewise( (0, sympy.Eq(S('Q'), sympy.Mul(sympy.Add(S('R'), S('C')), 1 / S('D')))))), ('$PRED IF (Q.EQ.R+C/D) L=0', S('L'),
def _make_comparison_question(context, left, right): """Makes a question for comparing two values.""" if random.choice([False, True]) and sympy.Ne(left.value, right.value): # Do question of form: "Which is bigger: a or b?". if random.choice([False, True]): answer = (left.handle if sympy.Gt(left.value, right.value) else right.handle) template = random.choice([ 'Mana yang lebih besar: {left} atau {right}?', ]) else: answer = (left.handle if sympy.Lt(left.value, right.value) else right.handle) template = random.choice([ 'Mana yang lebih kecil: {left} atau {right}?', ]) return example.Problem(question=example.question(context, template, left=left, right=right), answer=answer) comparisons = { '<': sympy.Lt, '<=': sympy.Le, '>': sympy.Gt, '>=': sympy.Ge, '=': sympy.Eq, '!=': sympy.Ne, } templates = { '<': [ 'Apakah {left} ' + ops.LT_SYMBOL + ' {right}?', 'Apakah {left} kurang dari {right}?', 'Apakah {left} lebih kecil dari {right}?', ], '<=': [ 'Apakah {left} ' + ops.LE_SYMBOL + ' {right}?', 'Apakah {left} kurang dari atau sama dengan {right}?', 'Apakah {left} lebih banyak {right}?', 'Apakah {left} paling tidak sama dengan {right}?', ], '>': [ 'Apakah {left} ' + ops.GT_SYMBOL + ' {right}?', 'Apakah {left} lebih dari {right}?', 'Apakah {left} lebih besar dari {right}?', ], '>=': [ 'Apakah {left} ' + ops.GE_SYMBOL + ' {right}?', 'Apakah {left} lebih dari atau sama dengan {right}?', 'Apakah {left} setidaknya {right}?', 'Apakah {left} setidaknya sama besar dengan {right}?', ], '=': [ 'Apakah {left} ' + ops.EQ_SYMBOL + ' {right}?', 'Apakah {left} dan {right} sama?', 'Apakah {left} sama dengan {right}?', 'Apakah {left} dan {right} memiliki nilai yang sama?', ], '!=': [ 'Apakah {left} ' + ops.NE_SYMBOL + ' {right}?', 'Apakah {left} tidak sama dengan {right}?', 'Apakah {left} dan {right} berbeda?', 'Apakah {left} dan {right} tidak sama?', 'Apakah {left} dan {right} memiliki nilai yang berbeda?', ], } comparison = random.choice(list(comparisons.keys())) template = random.choice(templates[comparison]) question = example.question(context, template, left=left, right=right) answer = comparisons[comparison](left.value, right.value) return example.Problem(question=question, answer=answer)
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)