ragni-cas 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 84aec56cb941ff1f7b44e118dc3bed327272591d
4
- data.tar.gz: 350d3a2064312c08c3a900633e2b0672bf140aa3
3
+ metadata.gz: 435c49ab6e4a5cbd771acfc5c6afc16a5334141b
4
+ data.tar.gz: 1a94331f8b29fc383ab7f411ff065ff2d9230a22
5
5
  SHA512:
6
- metadata.gz: e2a944fe15271c1ef65184a6ab5dd8610617294648cfdb0d67efd351167f4a4e1bd764eeadb0f0c7bfbaf1c35f9d00ff16ca2cca2458c94039faf4018eb6d00c
7
- data.tar.gz: 519a211ffcc69806c6c8b366a588e0258a73114f73dd0e8fd5445c9118e93c4f9ae2f71b75ff7682f3ad2ed3ae32bb9bf50726e715f8255f371035249d09dcc9
6
+ metadata.gz: d56a2fe673ef2e00b4574a39f683050c034838af81a5b822e0d8c6b87288ef09a5ad40848d57fcb2d5e81ffe7e32f1ebbb05e159eb3af283b7ce1bb34cf2c6e3
7
+ data.tar.gz: ff85830bb67960b656e31a3b6579993f6e40211ad06a3894223029bd99daf4a29210b94053880a9bcaf3c2f2201c76a8e78ed2d9ae753807a6cb8ad510beca4e
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
@@ -1,2 +1 @@
1
- `��O
2
- �֘�� �dT ܦ%��ͱW�O0�Qm���q��bbVY`��}���b��`����悔�~�g��n>A5�]�p�K)��;�������
1
+ Sk���q�8~t��6ci��e�;�tE���m�H��Z��T`�IZ�V�����s�`����m����.��r��L��g��m~�+mE��@"��pC�qD
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  ##
4
- # ragni-cas
5
- # A very simple CAS engine with encapsuled graph
4
+ # Mr.CAS
5
+ # A minmalistic CAS engine with encapsuled graph
6
6
  # representation. This will make impossible to
7
7
  # perform complex high level simplifications, but
8
8
  # it is powerful enough to define simple algorithm
@@ -58,6 +58,7 @@ end
58
58
 
59
59
  %w|operators/op.rb operators/bary-op.rb operators/nary-op.rb
60
60
  numbers/constants.rb numbers/variables.rb numbers/functions.rb
61
+ functions/fnc-sum.rb functions/fnc-prod.rb
61
62
  functions/fnc-base.rb functions/fnc-trig.rb functions/fnc-trsc.rb
62
63
  functions/fnc-conditions.rb functions/fnc-box-conditions.rb functions/fnc-piecewise.rb
63
64
  overloading/fixnum.rb overloading/float.rb
@@ -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
data/lib/Mr.CAS/c.rb ADDED
@@ -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