Julia元编程初探——以简单符号求导为例

Julia语言具有强大的元编程机制,本文用Julia实现《SICP》中文第二版中第 99 页中的实例:符号求导,体验一下Julia元编程。

运行结果如下:

julia> include("deriv.jl")  # 加载代码
multiplicand (generic function with 1 method)

julia> deriv(:(x + 3), :x)  # 求表达式 x + 3 关于 x 的导数
1

julia> deriv(:(x * y), :x)  #对表达式 x * y进行求导
:y

julia> deriv(:((x * y) * (x + 3)), :x)  #对表达式 (x * y) * (x + 3)进行求导
:(x * y + y * (x + 3))

代码如下(deriv.jl):

 1 function deriv(expr, var)
 2     if isa(expr, Number)
 3         return 0
 4     elseif isa(expr, Symbol)
 5         if is_same_variable(expr, var)
 6             return 1
 7         else
 8             return 0
 9         end
10     elseif is_sum(expr)
11         make_sum(deriv(addend(expr), var),
12                  deriv(augend(expr), var))
13     elseif is_product(expr)
14         make_sum(make_product(multiplier(expr),
15                               deriv(multiplicand(expr), var)),
16                  make_product(deriv(multiplier(expr), var),
17                                multiplicand(expr)))
18     else
19         println("unknown expression type -- DERIV", expr)
20     end
21 end
22
23
24 function is_variable(n)
25     return typeof(n) == Symbol
26 end
27
28 function is_same_variable(v1, v2)
29     return isa(v1, Symbol) && isa(v2, Symbol) && (v1 == v2)
30 end
31
32
33 # function make_sum(a1, a2)
34 #     return Expr(:call, :+, a1, a2)
35 # end
36
37 # function make_product(m1, m2)
38 #     return Expr(:call, :*, m1, m2)
39 # end
40
41 function make_sum(a1, a2)
42     if is_eq_number(a1, 0)
43         return a2
44     elseif is_eq_number(a2, 0)
45         return a1
46     elseif isa(a1, Number) && isa(a2, Number)
47         return a1 + a2
48     else
49         return Expr(:call, :+, a1, a2)
50     end
51 end
52
53 function make_product(m1, m2)
54     if is_eq_number(m1, 0) || is_eq_number(m2, 0)
55         return 0
56     elseif is_eq_number(m1, 1)
57         return m2
58     elseif is_eq_number(m2, 1)
59         return m1
60     elseif isa(m1, Number) && isa(m2, Number)
61         return m1 * m2
62     else
63         return Expr(:call, :*, m1, m2)
64     end
65 end
66
67 function is_eq_number(expr, num)
68     return isa(expr, Number) && (expr == num)
69 end
70
71 function is_sum(x)
72     return isa(x, Expr) && x.args[1] == :+
73 end
74
75 function addend(s)
76     return s.args[2]
77 end
78
79 function augend(s)
80     return s.args[3]
81 end
82
83 function is_product(x)
84     return isa(x, Expr) && x.args[1] == :*
85 end
86
87 function multiplier(p)
88     return p.args[2]
89 end
90
91 function multiplicand(p)
92     return p.args[3]
93 end

原文地址:https://www.cnblogs.com/mocuishle/p/12639068.html

时间: 2024-11-08 11:16:37

Julia元编程初探——以简单符号求导为例的相关文章

Python类元编程初探

在<流畅的Python>一书中提到: Classes are first-class object in Python, so a function can be used to create a new class ant any time, without using the class keyword. 在Python中,声明一个类可以有两种方法: >>> class X: ... a = 1 ... >>> X = type('X', (object

scheme 符号求导程序

SICP 习题: #lang scheme ( define ( variable? x ) ( symbol? x ) ) ( define ( same-variable? x y ) ( and ( variable? x ) ( variable? y ) ( eq? x y ) ) ) ( define ( =number? exp num ) ( and ( number? exp ) ( = exp num ) ) ) ;;;;;;;;;;;;;;;;; sum ;;;;;;;;;

C++11模版元编程

1.概述 模版元编程(template metaprogram)是C++中最复杂也是威力最强大的编程范式,它是一种可以创建和操纵程序的程序.模版元编程完全不同于普通的运行期程序,它很独特,因为模版元程序的执行完全是在编译期,并且模版元程序操纵的数据不能是运行时变量,只能是编译期常量,不可修改,另外它用到的语法元素也是相当有限,不能使用运行期的一些语法,比如if-else,for等语句都不能用.因此,模版元编程需要很多技巧,常常需要类型重定义.枚举常量.继承.模板偏特化等方法来配合,因此编写模版元

OO_2019_第一单元总结——表达式求导

一.基于度量的程序结构分析 首先给出Complexity metrics中参数的含义: ev(G):基本复杂度是用来衡量程序非结构化程度的,非结构成分降低了程序的质量,增加了代码的维护难度,使程序难于理解.因此,基本复杂度高意味着非结构化程度高,难以模块化和维护. Iv(G):模块设计复杂度是用来衡量模块判定结构,即模块和其他模块的调用关系.软件模块设计复杂度高意味模块耦合度高,这将导致模块难于隔离.维护和复用.模块设计复杂度是从模块流程图中移去那些不包含调用子模块的判定和循环结构后得出的圈复杂

使用元编程,用最简单的递归构造快速斐波那契数函数。

使用元编程和模板递归技术,既可以使最原始的递归方程具备惊人的快速高效. template <int T> class metafib { public: static const long long fib=metafib<T-1>::fib+metafib<T-2>::fib; }; template <> class metafib<1> { public: static const int fib=1; }; template <&g

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接加载库

基于模板元编程技术的跨平台C++动态链接加载库.通过模板技术,使用者仅需通过简单的宏,即可使编译器在编译期自动生成加载动态链接库导出符号的代码,无任何额外的运行时开销. ASL_LIBRARY_BEGIN(TestLib) ASL_SYMBOL(Proc_test1, test1, false) ASL_SYMBOL(Proc_test2, test2, true) ASL_LIBRARY_END() TestLib theLib; try { theLib.Load("./1.so"

c++模板元编程二:用enum做数值计算

2.1 用enum做数值计算 下面两篇文章都介绍了模板元编程,enum是其最重要的基本工具 http://www.codeproject.com/Articles/3743/A-gentle-introduction-to-Template-Metaprogramming https://www10.informatik.uni-erlangen.de/~pflaum/pflaum/ProSeminar/meta-art.html 因此可以得道以下结论: enum的值由编译器在编译期计算 利用模

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接载入库

基于模板元编程技术的跨平台C++动态链接载入库.通过模板技术,使用者仅需通过简单的宏,就可以使编译器在编译期自己主动生成载入动态链接库导出符号的代码,无不论什么额外的执行时开销. extern "C" { typedef int(*Proc_fnTestDll)(); typedef const char* (*Proc_fnTestDll2)(const char*); } ASL_LIBRARY_BEGIN(Test) // 强制载入名为fnTestDll的接口,假设没有该接口.则

【Scala】Scala函数式编程初探

函数式编程 函数式编程是种编程典范,它将电脑运算视为函数的计算.函数编程语言最重要的基础是 λ 演算(lambda calculus).而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值).和指令式编程相比,函数式编程强调函数的计算比指令的执行重要.和过程化编程相比,函数式编程里,函数的计算可随时调用. 命令式编程是面向计算机硬件的抽象,有变量(对应着存储单元),赋值语句(获取,存储指令),表达式(内存引用和算术运算)和控制语句(跳转指令),一句话,命令式程序就是一个冯诺依曼机的指令序列