ragni-cas 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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