Mr.CAS 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 62a33629bd1fe8154be4964e99dccd87cd7c060c
4
+ data.tar.gz: 6842feded0a74f326b81a6d5513527df10ab3d96
5
+ SHA512:
6
+ metadata.gz: a3d0c46c099e1bb90d2d5a1087b286d079712777e92ed1d5d9c7a1ab7947fac0f98a82414128eadd92d76b1ead31b3fe704b8f0048ed1686e3ef08220a5614cf
7
+ data.tar.gz: 07ccfad775f154afff75a097b9c0e0b9233ac023452176dbbbc429417da3fb810c02796ab52d601366d672e7025c9cf8ed4fa95ce2527c4cb878e0816887c39b
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,2 @@
1
+ Q��A}E�Vv9�~���Z�V�f+�'}��+Jt(#��&�F��=��W��tH*Z���;(��q��n�� �$_� OD�u��G��ڹj��ݓÍ��ϫ|"\������Lh�Q�/�Đ����1쎇�1[Y�p��m+�I��f�,l]��i�+�q2�Rp�ī�aп��"����{M���DPn��(��}a������BC���*�ʫ���[�"
2
+ �#9� ?�����s �tIn���ErUD�
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ##
4
+ # Mr.CAS
5
+ # A minmalistic CAS engine with encapsuled graph
6
+ # representation. This will make impossible to
7
+ # perform complex high level simplifications, but
8
+ # it is powerful enough to define simple algorithm
9
+ # in a symbolic way.
10
+ #
11
+ # Mathematically, this is an implementation of the
12
+ # forward chain rule for automatic differentiaition.
13
+ # Each function is a container of function and the
14
+ # derivation is in the form:
15
+ #
16
+ # ```
17
+ # d(f(g(x))
18
+ # --------- = g'(x) * f'(g(x))
19
+ # dx
20
+ # ```
21
+ #
22
+ # Author:: Matteo Ragni (mailto:info@ragni.me)
23
+ # Copyright:: Copyright (c) 2016 Matteo Ragni
24
+ # License:: Distributed under MIT license terms
25
+ module CAS
26
+
27
+ # Support functions are in this separate Helper class
28
+ module Help
29
+ # Check input `obj.class` against a `type` class
30
+ # raises an `ArgumentError` if check fails
31
+ #
32
+ # * **argument**: object to be cecked
33
+ # * **argument**: type to be checked against
34
+ # * **returns**: `TrueClass`, or raises an `ArgumentError`
35
+ def self.assert(obj, type)
36
+ raise ArgumentError, "required #{type}, received #{obj.class}" unless obj.is_a? type
37
+ return true
38
+ end
39
+
40
+ # Check if input object is feasible to be a name of a `CAS::Variable` or a `CAS::Function`
41
+ # raise an `ArgumentError` if the check fails. To be feasible the object must be a `String`
42
+ # instance or `Symbol` instance
43
+ #
44
+ # * **argument**: object to be checked
45
+ # * **returns**: `TrueClass` or raises `ArgumentError`
46
+ def self.assert_name(obj)
47
+ raise ArgumentError, "Input name must be a String/Symbol" unless [Symbol, String].include? obj.class
48
+ return true
49
+ end
50
+ end
51
+ end
52
+
53
+ # ___ _
54
+ # | _ \___ __ _ _ _(_)_ _ ___ ___
55
+ # | / -_) _` | || | | '_/ -_|_-<
56
+ # |_|_\___\__, |\_,_|_|_| \___/__/
57
+ # |_|
58
+
59
+ %w|operators/op.rb operators/bary-op.rb operators/nary-op.rb
60
+ numbers/constants.rb numbers/variables.rb numbers/functions.rb
61
+ functions/fnc-sum.rb functions/fnc-prod.rb
62
+ functions/fnc-base.rb functions/fnc-trig.rb functions/fnc-trsc.rb
63
+ functions/fnc-conditions.rb functions/fnc-box-conditions.rb functions/fnc-piecewise.rb
64
+ overloading/fixnum.rb overloading/float.rb
65
+ version.rb|.each do |r|
66
+ require File.expand_path(r, File.dirname(__FILE__))
67
+ end
68
+
69
+ module CAS
70
+ CAS::NumericToConst[-Math::PI] = (-CAS::Pi)
71
+ CAS::NumericToConst[-Math::E] = (-CAS::E)
72
+ CAS::NumericToConst[(-1.0/0.0)] = (CAS::NegInfinity)
73
+ end
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module CAS
4
+ module AutoDiff
5
+ class DualNumber
6
+ include Math
7
+ attr_reader :x, :y
8
+
9
+ def initialize(x, y)
10
+ @x, @y = x, y
11
+ end
12
+
13
+ def +(v)
14
+ DualNumber.new @x + v.x, @y + v.y
15
+ end
16
+
17
+ def -(v)
18
+ DualNumber.new @x - v.x, @y - v.y
19
+ end
20
+
21
+ def *(v)
22
+ DualNumber.new @x * v.x, @y * v.x + @x * v.y
23
+ end
24
+
25
+ def /(v)
26
+ DualNumber.new @x / v.x, (@y * v.x - @x * v.y) / (v.x ** 2)
27
+ end
28
+
29
+ def -@
30
+ DualNumber.new -@x, -@y
31
+ end
32
+
33
+ def **(v)
34
+ t = (v.y == 0 ? 0 : @x * log(@x) * v.y)
35
+ DualNumber.new @x ** v.x, (@x ** (v.x - 1)) * (v.x * @y + t)
36
+ end
37
+
38
+ def abs
39
+ return DualNumber.new(0, 0) if @x == 0
40
+ DualNumber.new @x.abs, @y * (@x <=> 0)
41
+ end
42
+
43
+ def to_s; self.inspect; end
44
+ def inspect; "<#{@x},#{@y}>"; end
45
+ def real; @x; end
46
+ def diff; @y; end
47
+ end # DualNumbers
48
+
49
+ def self.const(x)
50
+ DualNumber.new x, 0
51
+ end
52
+
53
+ def self.vars(x)
54
+ DualNumber.new x, 1
55
+ end
56
+
57
+ Zero = self.const 0
58
+ One = self.const 1
59
+ Two = self.const 2
60
+ E = self.const Math::E
61
+ Pi = self.const Math::PI
62
+ end
63
+
64
+
65
+ {
66
+ # Terminal nodes
67
+ CAS::Variable => Proc.new { |fd| CAS::AutoDiff.vars (fd[CAS::Variable[@name]] || fd[@name]) },
68
+ CAS::Constant => Proc.new { |_fd| CAS::AutoDiff.const @x },
69
+ CAS::Function => Proc.new { |_fd| raise RuntimeError, "Impossible for implicit functions" },
70
+
71
+ # Base functions
72
+ CAS::Sum => Proc.new { |fd| @x.auto_diff(fd) + @y.auto_diff(fd) },
73
+ CAS::Diff => Proc.new { |fd| @x.auto_diff(fd) - @y.auto_diff(fd) },
74
+ CAS::Prod => Proc.new { |fd| @x.auto_diff(fd) * @y.auto_diff(fd) },
75
+ CAS::Pow => Proc.new { |fd| @x.auto_diff(fd) ** @y.auto_diff(fd) },
76
+ CAS::Div => Proc.new { |fd| @x.auto_diff(fd) / @y.auto_diff(fd) },
77
+ CAS::Sqrt => Proc.new { |fd| @x.auto_diff(fd) ** (CAS::AutoDiff::One / CAS::AutoDiff::Two) },
78
+ CAS::Invert => Proc.new { |fd| -@x.auto_diff(fd) },
79
+ CAS::Abs => Proc.new { |fd| @x.auto_diff(fd).abs },
80
+
81
+ # Trigonometric functions
82
+ CAS::Sin => Proc.new { |fd|
83
+ u = @x.auto_diff(fd)
84
+ CAS::AutoDiff::DualNumber.new Math.sin(u.x), Math.cos(u.x) * u.y
85
+ },
86
+ CAS::Asin => Proc.new { |fd|
87
+ u = @x.auto_diff(fd)
88
+ CAS::AutoDiff::DualNumber.new Math.asin(u.x), -(Math.sin(u.x) * u.y)
89
+ },
90
+ CAS::Cos => Proc.new { |fd|
91
+ u = @x.auto_diff(fd)
92
+ CAS::AutoDiff::DualNumber.new Math.cos(u.x), -(Math.sin(u.x) * u.y)
93
+ },
94
+ CAS::Acos => Proc.new { |fd|
95
+ u = @x.auto_diff(fd)
96
+ CAS::AutoDiff::DualNumber.new Math.acos(u.x), -u.y / Math.sqrt(1 + u.x ** 2)
97
+ },
98
+ CAS::Tan => Proc.new { |fd|
99
+ u = @x.auto_diff(fd)
100
+ CAS::AutoDiff::DualNumber.new Math.tan(u.x), u.y / (Math.cos(u.x) ** 2)
101
+ },
102
+ CAS::Atan => Proc.new { |fd|
103
+ u = @x.auto_diff(fd)
104
+ CAS::AutoDiff::DualNumber.new Math.atan(u.x), u.y / (1 + u.x ** 2)
105
+ },
106
+
107
+ # Trascendent functions
108
+ CAS::Exp => Proc.new { |fd| CAS::AutoDiff::E ** @x.auto_diff(fd) },
109
+ CAS::Ln => Proc.new { |fd|
110
+ u = @x.auto_diff(fd)
111
+ CAS::AutoDiff::DualNumber.new Math.log(u.x), u.y / u.x
112
+ },
113
+
114
+ # Piecewise
115
+ CAS::Piecewise => Proc.new { |_fd| raise RuntimeError, "Not implemented auto_diff for Piecewise" },
116
+ CAS::Max => Proc.new { |fd|
117
+ a = @x.auto_diff(fd)
118
+ b = @y.auto_diff(fd)
119
+ (a.x >= b.x ? a : b)
120
+ },
121
+ CAS::Min => Proc.new { |fd|
122
+ a = @x.auto_diff(fd)
123
+ b = @y.auto_diff(fd)
124
+ (a.x >= b.x ? a : b)
125
+ }
126
+ }.each do |cls, blk|
127
+ cls.send(:define_method, "auto_diff", &blk)
128
+ end
129
+ end
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ___ ___ _ _
4
+ # / __| | _ \ |_ _ __ _(_)_ _
5
+ # | (__ | _/ | || / _` | | ' \
6
+ # \___| |_| |_|\_,_\__, |_|_||_|
7
+ # |___/
8
+
9
+ require 'pry'
10
+
11
+ module CAS
12
+ class CLib < Hash
13
+ def self.create(name, &blk)
14
+ a = CLib.new(name)
15
+ a.instance_eval(&blk)
16
+ return a
17
+ end
18
+
19
+ def initialize(name)
20
+ raise ArgumentError, "Name for the library undefined" unless name.is_a? String
21
+ @name = name
22
+ @define = {}
23
+ @include = {}
24
+ @include[:std] = []
25
+ @include[:local] = []
26
+ @type = "double"
27
+
28
+ # Default definitions
29
+ # self.define "M_PI", Math::PI
30
+ # self.define "M_INFINITY","HUGE_VAL"
31
+ # self.define "M_E", Math::E
32
+ # self.define "M_EPSILON", 1E-16
33
+
34
+ # Default inclusions
35
+ self.include "math.h"
36
+ end
37
+
38
+ def as_double; @type = "double"; end
39
+ def as_float; @type = "float"; end
40
+ def as_int; @type = "int"; end
41
+ def as_long_int; @type = "long int"; end
42
+
43
+ def define(k, v)
44
+ raise ArgumentError, "k must be a String, received a #{k.class}" unless k.is_a? String
45
+ @define[k] = v.to_s
46
+ @define
47
+ end
48
+
49
+ def undefine(k)
50
+ @define.delete k
51
+ return @define
52
+ end
53
+
54
+ def include_type(type, lib)
55
+ raise ArgumentError, "type must be a Symbol (:std, :local), received #{type}" unless [:std, :local].include? type
56
+ raise ArgumentError, "lib must be a String, received a #{lib.class}" unless lib.is_a? String
57
+ @include[type] << lib unless @include[type].include? lib
58
+ end
59
+ def include(lib); self.include_type(:std, lib); end
60
+ def include_local(lib); self.include_type(:local, lib); end
61
+
62
+ def implements_as(name, op); self[name] = op; end
63
+
64
+ def header
65
+ <<-TO_HEADER
66
+ // Header file for library: #{@name}.c
67
+
68
+ #ifndef #{@name}_H
69
+ #define #{@name}_H
70
+
71
+ // Standard Libraries
72
+ #{ @include[:std].map { |e| "#include <#{e}>" }.join("\n") }
73
+
74
+ // Local Libraries
75
+ #{ @include[:local].map { |e| "#include \"#{e}\"" }.join("\n") }
76
+
77
+ // Definitions
78
+ #{ @define.map { |k, v| "#define #{k} #{v}" }.join("\n") }
79
+
80
+ // Functions
81
+ #{
82
+ self.keys.map do |fname|
83
+ "#{@type} #{fname}(#{ self[fname].args.map { |x| "#{@type} #{x.name}" }.join(", ")});"
84
+ end.join("\n")
85
+ }
86
+
87
+ #endif // #{@name}_H
88
+ TO_HEADER
89
+ end
90
+
91
+ def source
92
+ functions = []
93
+
94
+ self.each do |fname, op|
95
+ c_op = op.to_c.sort_by { |_k, c| c[:id] }
96
+ nf = <<-NEWFUNCTION
97
+ #{@type} #{fname}(#{ op.args.map { |x| "#{@type} #{x.name}" }.join(", ")}) {
98
+ #{c_op.map { |e| " double #{e[1][:var]} = #{e[1][:def]};"}.join("\n")}
99
+
100
+ return #{c_op[-1][1][:var]};
101
+ }
102
+ NEWFUNCTION
103
+ functions << nf
104
+ end
105
+
106
+ <<-TO_SOURCE
107
+ // Source file for library: #{@name}.c
108
+
109
+ #include "#{@name}.h"
110
+
111
+ #{functions.join("\n")}
112
+ // end of #{@name}.c
113
+ TO_SOURCE
114
+ end
115
+ end
116
+
117
+ {
118
+ # Terminal nodes
119
+ CAS::Constant => Proc.new { |_v| "#{@x}" },
120
+ CAS::Variable => Proc.new { |_v| "#{@name}" },
121
+ CAS::PI_CONSTANT => Proc.new { |_v| "M_PI" },
122
+ CAS::INFINITY_CONSTANT => Proc.new { |_v| "M_INFINITY" },
123
+ CAS::NEG_INFINITY_CONSTANT => Proc.new { |_v| "(-M_INFINITY)" },
124
+ CAS::E_CONSTANT => Proc.new { |_v| "M_E" }
125
+ }.each do |cls, blk|
126
+ cls.send(:define_method, "__to_c", &blk)
127
+ end.each do |cls, _blk|
128
+ cls.send(:define_method, "to_c", &Proc.new do
129
+ v = {}; self.__to_c(v); v
130
+ end)
131
+ end
132
+
133
+ {
134
+ # Base functions
135
+ CAS::Sum => Proc.new { |v| "(#{@x.map { |e| e.__to_c(v) }.join(" + ")})" },
136
+ CAS::Diff => Proc.new { |v| "(#{@x.__to_c(v)} - #{@y.__to_c(v)})" },
137
+ CAS::Prod => Proc.new { |v| "(#{@x.map { |e| e.__to_c(v) }.join(" + ")})" },
138
+ CAS::Pow => Proc.new { |v| "pow(#{@x.__to_c(v)}, #{@y.__to_c(v)})" },
139
+ CAS::Div => Proc.new { |v| "(#{@x.__to_c(v)}) / (#{@y.__to_c(v)} + M_EPSILON)" },
140
+ CAS::Sqrt => Proc.new { |v| "sqrt(#{@x.__to_c(v)})" },
141
+ CAS::Invert => Proc.new { |v| "(-#{@x.__to_c(v)})" },
142
+ CAS::Abs => Proc.new { |v| "fabs(#{@x.__to_c(v)})" },
143
+
144
+ # Trigonometric functions
145
+ CAS::Sin => Proc.new { |v| "sin(#{@x.__to_c(v)})" },
146
+ CAS::Asin => Proc.new { |v| "asin(#{@x.__to_c(v)})" },
147
+ CAS::Cos => Proc.new { |v| "cos(#{@x.__to_c(v)})" },
148
+ CAS::Acos => Proc.new { |v| "acos(#{@x.__to_c(v)})" },
149
+ CAS::Tan => Proc.new { |v| "tan(#{@x.__to_c(v)})" },
150
+ CAS::Atan => Proc.new { |v| "atan(#{@x.__to_c(v)})" },
151
+
152
+ # Trascendent functions
153
+ CAS::Exp => Proc.new { |v| "exp(#{@x.__to_c(v)})" },
154
+ CAS::Ln => Proc.new { |v| "log(#{@x.__to_c(v)})" },
155
+
156
+ # # Box Conditions
157
+ # CAS::BoxConditionOpen => Proc.new {
158
+ # ["double __t_#{x.object_id} = #{x.__to_c(v)};",
159
+ # "(__t_#{x.object_id} > #{lower.latex} && __t_#{x.object_id} < #{upper.latex})"]
160
+ # },
161
+ # CAS::BoxConditionUpperClosed => Proc.new {
162
+ # ["double __t_#{x.object_id} = #{x.__to_c(v)};",
163
+ # "(__t_#{x.object_id} > #{lower.latex} && __t_#{x.object_id} <= #{upper.latex})"]
164
+ # },
165
+ # CAS::BoxConditionLowerClosed => Proc.new {
166
+ # ["double __t_#{x.object_id} = #{x.__to_c(v)};",
167
+ # "(__t_#{x.object_id} >= #{lower.latex} && __t_#{x.object_id} < #{upper.latex})"]
168
+ # },
169
+ # CAS::BoxConditionClosed => Proc.new {
170
+ # ["double __t_#{x.object_id} = #{x.__to_c(v)};",
171
+ # "(__t_#{x.object_id} >= #{lower.latex} && __t_#{x.object_id} <= #{upper.latex})"]
172
+ # },
173
+
174
+ # Conditions
175
+ # CAS::Equal => Proc.new { "(#{x.__to_c(v)} == #{y.__to_c(v)})" },
176
+ # CAS::Smaller => Proc.new { "(#{x.__to_c(v)} < #{y.__to_c(v)})" },
177
+ # CAS::Greater => Proc.new { "(#{x.__to_c(v)} > #{y.__to_c(v)})" },
178
+ # CAS::SmallerEqual => Proc.new { "(#{x.__to_c(v)} <= #{y.__to_c(v)})" },
179
+ # CAS::GreaterEqual => Proc.new { "(#{x.__to_c(v)} >= #{y.__to_c(v)})" },
180
+ # TODO there is no sense in exporting conditions in C...
181
+
182
+ # Piecewise
183
+ # CAS::Piecewise => Proc.new { raise CASError, "Not implemented yet" },
184
+ # CAS::Max => Proc.new { raise CASError, "Not implemented yet" },
185
+ # CAS::Min => Proc.new { raise CASError, "Not implemented yet" }
186
+ CAS::Function => Proc.new { |v| "#{@c_name}(#{@x.map {|e| e.__to_c(v)}.join(", ")})" }
187
+ }.each do |cls, blk|
188
+ cls.send(:define_method, "__to_c_impl", &blk)
189
+ end.each do |cls, _blk|
190
+ cls.send(:define_method, "__to_c", &Proc.new do |v|
191
+ sym = self.to_s.to_sym
192
+ v[sym] = {
193
+ :def => "#{self.__to_c_impl(v)}",
194
+ :var => "__t_#{v.keys.size}",
195
+ :id => v.keys.size
196
+ } unless v[sym] # Pleas note that the order here is foundamental!
197
+ v[sym][:var]
198
+ end)
199
+ end.each do |cls, _blk|
200
+ cls.send(:define_method, "to_c", &Proc.new do
201
+ v = {}; self.__to_c(v); v
202
+ end)
203
+ end
204
+
205
+ class Op
206
+ def to_c_lib(name)
207
+ CAS::Help.assert(name, String)
208
+ [CAS::C_PLUGIN.write_header(self, name), CAS::C_PLUGIN.write_source(self, name)]
209
+ end
210
+ end
211
+
212
+ class Function
213
+ def c_name=(s)
214
+ CAS::Help.assert_name s
215
+ @c_name = s
216
+ end
217
+
218
+ def Function.new(name, *xs)
219
+ a = super
220
+ a.c_name = name
221
+ return a
222
+ end
223
+ end
224
+ Function.list.each do |k, v| v.c_name = k; end
225
+ end
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ___ ___ _ _
4
+ # / __| | _ \ |_ _ __ _(_)_ _
5
+ # | (__ | _/ | || / _` | | ' \
6
+ # \___| |_| |_|\_,_\__, |_|_||_|
7
+ # |___/
8
+
9
+ module CAS
10
+ module C_PLUGIN
11
+ C_STD_LIBRARIES = [
12
+ "math.h"
13
+ ]
14
+
15
+ C_LOCAL_LIBRARIES = [ ]
16
+
17
+ C_DEFINES = {
18
+ "M_PI" => Math::PI.to_s,
19
+ "M_INFINITY" => "HUGE_VAL",
20
+ "M_E" => Math::E.to_s,
21
+ "M_EPSILON" => (1E-16).to_s
22
+ }
23
+
24
+ def self.write_header(op, name)
25
+ <<-TO_HEADER
26
+ #ifndef #{name}_HEADER
27
+ #define #{name}_HEADER
28
+
29
+ // Standard Libraries
30
+ #{ CAS::C_PLUGIN::C_STD_LIBRARIES.map { |e| "#include <#{e}>" }.join("\n") }
31
+
32
+ // Local Libraries
33
+ #{ CAS::C_PLUGIN::C_LOCAL_LIBRARIES.map { |e| "#include <#{e}>" }.join("\n") }
34
+
35
+ // Definitions
36
+ #{ CAS::C_PLUGIN::C_DEFINES.map { |k, v| "#define #{k} #{v}" }.join("\n") }
37
+
38
+ // Function
39
+ double #{name}(#{ op.args.map { |x| "double #{x.name}"}.join(", ") });
40
+
41
+ #endif // #{name}_HEADER
42
+ TO_HEADER
43
+ end
44
+
45
+ def self.write_source(op, name)
46
+ <<-TO_SOURCE
47
+ #include "#{name}.h"
48
+
49
+ double #{name}(#{ op.args.map { |x| "double #{x.name}"}.join(", ") }) {
50
+ return #{op.to_c};
51
+ }
52
+ TO_SOURCE
53
+ end
54
+ end
55
+
56
+ {
57
+ # Terminal nodes
58
+ CAS::Constant => Proc.new { "#{x}" },
59
+ CAS::Variable => Proc.new { "#{name}" },
60
+ CAS::PI_CONSTANT => Proc.new { "M_PI" },
61
+ CAS::INFINITY_CONSTANT => Proc.new { "M_INFINITY" },
62
+ CAS::NEG_INFINITY_CONSTANT => Proc.new { "(-M_INFINITY)" },
63
+ CAS::E_CONSTANT => Proc.new { "M_E" },
64
+ # Base functions
65
+ CAS::Sum => Proc.new { "(#{x.to_c} + #{y.to_c})" },
66
+ CAS::Diff => Proc.new { "(#{x.to_c} - #{y.to_c})" },
67
+ CAS::Prod => Proc.new { "(#{x.to_c} * #{y.to_c})" },
68
+ CAS::Pow => Proc.new { "pow(#{x.to_c}, #{y.to_c})" },
69
+ CAS::Div => Proc.new { "(#{x.to_c}) / (#{y.to_c} + )" },
70
+ CAS::Sqrt => Proc.new { "sqrt(#{x.to_c})" },
71
+ CAS::Invert => Proc.new { "(-#{x.to_c})" },
72
+ CAS::Abs => Proc.new { "fabs(#{x.to_c})" },
73
+
74
+ # Trigonometric functions
75
+ CAS::Sin => Proc.new { "sin(#{x.to_c})" },
76
+ CAS::Asin => Proc.new { "asin(#{x.to_c})" },
77
+ CAS::Cos => Proc.new { "cos(#{x.to_c})" },
78
+ CAS::Acos => Proc.new { "acos(#{x.to_c})" },
79
+ CAS::Tan => Proc.new { "tan(#{x.to_c})" },
80
+ CAS::Atan => Proc.new { "atan(#{x.to_c})" },
81
+
82
+ # Trascendent functions
83
+ CAS::Exp => Proc.new { "exp(#{x.to_c})" },
84
+ CAS::Ln => Proc.new { "log(#{x.to_c})" },
85
+
86
+ # Box Conditions
87
+ CAS::BoxConditionOpen => Proc.new {
88
+ ["double __t_#{x.object_id} = #{x.to_c};",
89
+ "(__t_#{x.object_id} > #{lower.latex} && __t_#{x.object_id} < #{upper.latex})"]
90
+ },
91
+ CAS::BoxConditionUpperClosed => Proc.new {
92
+ ["double __t_#{x.object_id} = #{x.to_c};",
93
+ "(__t_#{x.object_id} > #{lower.latex} && __t_#{x.object_id} <= #{upper.latex})"]
94
+ },
95
+ CAS::BoxConditionLowerClosed => Proc.new {
96
+ ["double __t_#{x.object_id} = #{x.to_c};",
97
+ "(__t_#{x.object_id} >= #{lower.latex} && __t_#{x.object_id} < #{upper.latex})"]
98
+ },
99
+ CAS::BoxConditionClosed => Proc.new {
100
+ ["double __t_#{x.object_id} = #{x.to_c};",
101
+ "(__t_#{x.object_id} >= #{lower.latex} && __t_#{x.object_id} <= #{upper.latex})"]
102
+ },
103
+
104
+ # Conditions
105
+ CAS::Equal => Proc.new { "(#{x.to_c} == #{y.to_c})" },
106
+ CAS::Smaller => Proc.new { "(#{x.to_c} < #{y.to_c})" },
107
+ CAS::Greater => Proc.new { "(#{x.to_c} > #{y.to_c})" },
108
+ CAS::SmallerEqual => Proc.new { "(#{x.to_c} <= #{y.to_c})" },
109
+ CAS::GreaterEqual => Proc.new { "(#{x.to_c} >= #{y.to_c})" },
110
+
111
+ # Piecewise
112
+ CAS::Piecewise => Proc.new { raise CASError, "Not implemented yet" },
113
+ CAS::Max => Proc.new { raise CASError, "Not implemented yet" },
114
+ CAS::Min => Proc.new { raise CASError, "Not implemented yet" }
115
+ }.each do |cls, blk|
116
+ cls.send(:define_method, "to_c", &blk)
117
+ end
118
+
119
+ class Op
120
+ def to_c_lib(name)
121
+ CAS::Help.assert(name, String)
122
+ [CAS::C_PLUGIN.write_header(self, name), CAS::C_PLUGIN.write_source(self, name)]
123
+ end
124
+ end
125
+
126
+ end