def test_While(): xpp = AddAugmentedAssignment(x, 1) whl1 = While(x < 2, [xpp]) assert whl1.condition.args[0] == x assert whl1.condition.args[1] == 2 assert whl1.condition == Lt(x, 2, evaluate=False) assert whl1.body.args == (xpp, ) assert whl1.func(*whl1.args) == whl1 cblk = CodeBlock(AddAugmentedAssignment(x, 1)) whl2 = While(x < 2, cblk) assert whl1 == whl2 assert whl1 != While(x < 3, [xpp])
def as_FunctionDefinition(variables=None, name="logsumexp"): variables = variables or {} n = variables.get('n', Symbol('n', integer=True)) i = variables.get('i', Symbol('i', integer=True)) s = variables.get('s', Symbol('s')) x = variables.get('x', IndexedBase('x', shape=(n, ))) body = CodeBlock( FunctionCall('sympy_quicksort', (x, n), statement=True), Declaration(i, 0), Declaration(s, 0.0), While( i < n - 1, CodeBlock(AddAugmentedAssignment(s, exp(x[i])), AddAugmentedAssignment(i, 1))), ReturnStatement(log1p(s) + x[n - 1])) return FunctionDefinition("real", name, (x, n), body)
def test_ccode_codegen_ast(): assert ccode(Comment("this is a comment")) == "// this is a comment" assert ccode(While(abs(x) > 1, [aug_assign(x, '-', 1)])) == ('while (fabs(x) > 1) {\n' ' x -= 1;\n' '}') assert ccode(Scope([AddAugmentedAssignment(x, 1)])) == ('{\n' ' x += 1;\n' '}') inp_x = Declaration(Variable(x, type=real)) assert ccode(FunctionPrototype(real, 'pwer', [inp_x])) == 'double pwer(double x)' assert ccode( FunctionDefinition( real, 'pwer', [inp_x], [Assignment(x, x**2)])) == ('double pwer(double x){\n' ' x = pow(x, 2);\n' '}') # Elements of CodeBlock are formatted as statements: block = CodeBlock( x, Print([x, y], "%d %d"), FunctionCall('pwer', [x]), Return(x), ) assert ccode(block) == '\n'.join([ 'x;', 'printf("%d %d", x, y);', 'pwer(x);', 'return x;', ])
def test_Scope(): assign = Assignment(x, y) incr = AddAugmentedAssignment(x, 1) scp = Scope([assign, incr]) cblk = CodeBlock(assign, incr) assert scp.body == cblk assert scp == Scope(cblk) assert scp != Scope([incr, assign]) assert scp.func(*scp.args) == scp
def newton_raphson_algorithm(expr, wrt, atol=1e-12, delta=None, debug=False, itermax=None, counter=None): """ See https://en.wikipedia.org/wiki/Newton%27s_method """ if delta is None: delta = Dummy() Wrapper = Scope name_d = 'delta' else: Wrapper = lambda x: x name_d = delta.name delta_expr = -expr / expr.diff(wrt) body = [Assignment(delta, delta_expr), AddAugmentedAssignment(wrt, delta)] if debug: prnt = PrintStatement( r"{0}=%12.5g {1}=%12.5g\n".format(wrt.name, name_d), Tuple(wrt, delta)) body = [body[0], prnt] + body[1:] if isinstance(atol, float) and atol < 0: atol = -atol * 10**-PrinterSetting('precision') req = Gt(Abs(delta), atol) declars = [Declaration(delta, oo)] if itermax is not None: counter = counter or Dummy(integer=True) declars.append(Declaration(counter, 0)) body.append(AddAugmentedAssignment(counter, 1)) req = And(req, Lt(counter, itermax)) whl = While(req, CodeBlock(*body)) blck = declars + [whl] return Wrapper(CodeBlock(*blck))
def test_ccode_codegen_ast(): assert ccode(Comment("this is a comment")) == "// this is a comment" assert ccode(While(abs(x) > 1, [aug_assign(x, "-", 1)])) == ( "while (fabs(x) > 1) {\n" " x -= 1;\n" "}" ) assert ccode(Scope([AddAugmentedAssignment(x, 1)])) == ("{\n" " x += 1;\n" "}") inp_x = Declaration(Variable(x, type=real)) assert ccode(FunctionPrototype(real, "pwer", [inp_x])) == "double pwer(double x)" assert ccode( FunctionDefinition(real, "pwer", [inp_x], [Assignment(x, x ** 2)]) ) == ("double pwer(double x){\n" " x = pow(x, 2);\n" "}") # Elements of CodeBlock are formatted as statements: block = CodeBlock(x, Print([x, y], "%d %d"), FunctionCall("pwer", [x]), Return(x),) assert ccode(block) == "\n".join( ["x;", 'printf("%d %d", x, y);', "pwer(x);", "return x;",] )
def test_AugAssign(): # Here we just do things to show they don't error aug_assign(x, '+', y) aug_assign(x, '+', 0) aug_assign(A, '+', mat) aug_assign(A[1, 0], '+', 0) aug_assign(A[1, 0], '+', x) aug_assign(B[i], '+', x) aug_assign(B[i], '+', 0) a = aug_assign(x, '+', y) b = AddAugmentedAssignment(x, y) assert a.func(*a.args) == a == b a = aug_assign(x, '-', y) b = SubAugmentedAssignment(x, y) assert a.func(*a.args) == a == b a = aug_assign(x, '*', y) b = MulAugmentedAssignment(x, y) assert a.func(*a.args) == a == b a = aug_assign(x, '/', y) b = DivAugmentedAssignment(x, y) assert a.func(*a.args) == a == b a = aug_assign(x, '%', y) b = ModAugmentedAssignment(x, y) assert a.func(*a.args) == a == b # Here we test things to show that they error # Matrix to scalar raises(ValueError, lambda: aug_assign(B[i], '+', A)) raises(ValueError, lambda: aug_assign(B[i], '+', mat)) raises(ValueError, lambda: aug_assign(x, '+', mat)) raises(ValueError, lambda: aug_assign(x, '+', A)) raises(ValueError, lambda: aug_assign(A[1, 0], '+', mat)) # Scalar to matrix raises(ValueError, lambda: aug_assign(A, '+', x)) raises(ValueError, lambda: aug_assign(A, '+', 0)) # Non-atomic lhs raises(TypeError, lambda: aug_assign(mat, '+', A)) raises(TypeError, lambda: aug_assign(0, '+', x)) raises(TypeError, lambda: aug_assign(x * x, '+', 1)) raises(TypeError, lambda: aug_assign(A + A, '+', mat)) raises(TypeError, lambda: aug_assign(B, '+', 0))
def test_ccode_codegen_ast(): # Note that C only allows comments of the form /* ... */, double forward # slash is not standard C, and some C compilers will grind to a halt upon # encountering them. assert ccode( Comment("this is a comment")) == "/* this is a comment */" # not // assert ccode(While(abs(x) > 1, [aug_assign(x, '-', 1)])) == ('while (fabs(x) > 1) {\n' ' x -= 1;\n' '}') assert ccode(Scope([AddAugmentedAssignment(x, 1)])) == ('{\n' ' x += 1;\n' '}') inp_x = Declaration(Variable(x, type=real)) assert ccode(FunctionPrototype(real, 'pwer', [inp_x])) == 'double pwer(double x)' assert ccode( FunctionDefinition( real, 'pwer', [inp_x], [Assignment(x, x**2)])) == ('double pwer(double x){\n' ' x = pow(x, 2);\n' '}') # Elements of CodeBlock are formatted as statements: block = CodeBlock( x, Print([x, y], "%d %d"), FunctionCall('pwer', [x]), Return(x), ) assert ccode(block) == '\n'.join([ 'x;', 'printf("%d %d", x, y);', 'pwer(x);', 'return x;', ])
def newtons_method(expr, wrt, atol=1e-12, delta=None, debug=False, itermax=None, counter=None): """ Generates an AST for Newton-Raphson method (a root-finding algorithm). Returns an abstract syntax tree (AST) based on ``sympy.codegen.ast`` for Netwon's method of root-finding. Parameters ========== expr : expression wrt : Symbol With respect to, i.e. what is the variable. atol : number or expr Absolute tolerance (stopping criterion) delta : Symbol Will be a ``Dummy`` if ``None``. debug : bool Whether to print convergence information during iterations itermax : number or expr Maximum number of iterations. counter : Symbol Will be a ``Dummy`` if ``None``. Examples ======== >>> from sympy import symbols, cos >>> from sympy.codegen.ast import Assignment >>> from sympy.codegen.algorithms import newtons_method >>> x, dx, atol = symbols('x dx atol') >>> expr = cos(x) - x**3 >>> algo = newtons_method(expr, x, atol, dx) >>> algo.has(Assignment(dx, -expr/expr.diff(x))) True References ========== .. [1] https://en.wikipedia.org/wiki/Newton%27s_method """ if delta is None: delta = Dummy() Wrapper = Scope name_d = 'delta' else: Wrapper = lambda x: x name_d = delta.name delta_expr = -expr / expr.diff(wrt) whl_bdy = [ Assignment(delta, delta_expr), AddAugmentedAssignment(wrt, delta) ] if debug: prnt = Print([wrt, delta], r"{}=%12.5g {}=%12.5g\n".format(wrt.name, name_d)) whl_bdy = [whl_bdy[0], prnt] + whl_bdy[1:] req = Gt(Abs(delta), atol) declars = [Declaration(Variable(delta, type=real, value=oo))] if itermax is not None: counter = counter or Dummy(integer=True) v_counter = Variable.deduced(counter, 0) declars.append(Declaration(v_counter)) whl_bdy.append(AddAugmentedAssignment(counter, 1)) req = And(req, Lt(counter, itermax)) whl = While(req, CodeBlock(*whl_bdy)) blck = declars + [whl] return Wrapper(CodeBlock(*blck))