symbolic 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/README ADDED
@@ -0,0 +1 @@
1
+ Symbolic math for ruby.
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "symbolic"
8
+ gem.version = '0.0.1'
9
+ gem.summary = %Q{Symbolic math for ruby}
10
+ gem.email = "ravwar@gmail.com"
11
+ gem.homepage = "http://github.com/brainopia/symbolic"
12
+ gem.authors = ["brainopia"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
data/lib/symbolic.rb ADDED
@@ -0,0 +1,310 @@
1
+ module Symbolic
2
+ @enabled = false
3
+ class << self
4
+ def enabled?
5
+ @enabled
6
+ end
7
+
8
+ def enabled=(enable_flag)
9
+ if enable_flag && !@enabled
10
+ enable
11
+ elsif !enable_flag && @enabled
12
+ disable
13
+ end
14
+ end
15
+
16
+ def aliases
17
+ { :* => :non_symbolic_multiplication,
18
+ :+ => :non_symbolic_addition,
19
+ :- => :non_symbolic_substraction }
20
+ end
21
+
22
+ def math_operations
23
+ [:cos, :sin]
24
+ end
25
+
26
+ private
27
+
28
+ def numerical_context(&proc)
29
+ [Fixnum, Bignum, Float].each do |klass|
30
+ klass.class_eval &proc
31
+ end
32
+ end
33
+
34
+ def enable
35
+ @enabled = true
36
+ numerical_context do
37
+ Symbolic.aliases.each do |standard_operation, non_symbolic_operation|
38
+ alias_method non_symbolic_operation, standard_operation
39
+ end
40
+
41
+ def *(value)
42
+ if value.is_a?(Operatable)
43
+ Optimizations.multiply value, self, :reverse
44
+ else
45
+ non_symbolic_multiplication(value)
46
+ end
47
+ end
48
+
49
+ def +(value)
50
+ if value.is_a? Operatable
51
+ Optimizations.plus value, self, :reverse
52
+ else
53
+ non_symbolic_addition value
54
+ end
55
+ end
56
+
57
+ def -(value)
58
+ if value.is_a? Operatable
59
+ Optimizations.minus value, self, :reverse
60
+ else
61
+ non_symbolic_substraction value
62
+ end
63
+ end
64
+ end # numerical_context
65
+
66
+ math_operations.each do |operation|
67
+ Math.module_eval <<-CODE
68
+ class << self
69
+ alias non_symbolic_#{operation} #{operation}
70
+
71
+ def #{operation}(value)
72
+ if value.is_a? Operatable
73
+ Symbolic::Method.new value, :#{operation}
74
+ else
75
+ non_symbolic_#{operation} value
76
+ end
77
+ end
78
+ end
79
+ CODE
80
+ end
81
+ end # enable
82
+
83
+ def disable
84
+ @enabled = false
85
+ numerical_context do
86
+ Symbolic.aliases.each do |standard_operation, non_symbolic_operation|
87
+ alias_method standard_operation, non_symbolic_operation
88
+ remove_method non_symbolic_operation
89
+ end
90
+ end
91
+
92
+ Math.module_eval do
93
+ class << self
94
+ Symbolic.math_operations.each do |operation|
95
+ non_symbolic_operation = "non_symbolic_#{operation}"
96
+ alias_method operation, non_symbolic_operation
97
+ remove_method non_symbolic_operation
98
+ end
99
+ end
100
+ end
101
+ end # disable
102
+ end # class << self
103
+
104
+ class Operatable
105
+ def -@
106
+ UnaryMinus.create self
107
+ end
108
+
109
+ def *(value)
110
+ Optimizations.multiply self, value
111
+ end
112
+
113
+ def +(value)
114
+ Optimizations.plus self, value
115
+ end
116
+
117
+ def -(value)
118
+ Optimizations.minus self, value
119
+ end
120
+ end # Operations
121
+
122
+ module Optimizations
123
+ def self.plus(symbolic_var, var, reverse=false)
124
+ if var == 0
125
+ symbolic_var
126
+ elsif var.is_a? UnaryMinus
127
+ symbolic_var - var.variable
128
+ elsif reverse && symbolic_var.is_a?(UnaryMinus)
129
+ var - symbolic_var.variable
130
+ else
131
+ if reverse
132
+ Expression.new var, symbolic_var, '+'
133
+ else
134
+ Expression.new symbolic_var, var, '+'
135
+ end
136
+ end
137
+ end
138
+
139
+ def self.minus(symbolic_var, var, reverse=false)
140
+ if var == 0
141
+ symbolic_var
142
+ elsif var.is_a? UnaryMinus
143
+ symbolic_var + var.variable
144
+ elsif reverse && symbolic_var.is_a?(UnaryMinus)
145
+ var + symbolic_var.variable
146
+ else
147
+ if reverse
148
+ Expression.new var, symbolic_var, '-'
149
+ else
150
+ Expression.new symbolic_var, var, '-'
151
+ end
152
+ end
153
+ end
154
+
155
+ def self.multiply(symbolic_var, var, reverse=false)
156
+ if var == 0
157
+ var
158
+ elsif var == 1
159
+ symbolic_var
160
+ elsif var == -1
161
+ -symbolic_var
162
+ elsif var.is_a?(Numeric) && var < 0
163
+ -(-var*symbolic_var)
164
+ elsif var.is_a? UnaryMinus
165
+ UnaryMinus.create symbolic_var*var.variable
166
+ elsif symbolic_var.is_a? UnaryMinus
167
+ UnaryMinus.create symbolic_var.variable*var
168
+ else
169
+ if reverse
170
+ Expression.new var, symbolic_var, '*'
171
+ else
172
+ Expression.new symbolic_var, var, '*'
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ class Variable < Operatable
179
+ attr_accessor :value
180
+
181
+ @@index = 0
182
+
183
+ def initialize(options)
184
+ unless @name = options[:name]
185
+ @@index += 1
186
+ @name = "var#{@@index}"
187
+ end
188
+
189
+ @value = options[:value]
190
+ end
191
+
192
+ def to_s
193
+ @name
194
+ end
195
+
196
+ def undefined_variables
197
+ @value ? [] : [self]
198
+ end
199
+ end
200
+
201
+ class Expression < Operatable
202
+ def initialize(var1, var2, operation)
203
+ @var1, @var2, @operation = var1, var2, operation
204
+ end
205
+
206
+ def to_s
207
+ var1 = "#{@var1}"
208
+ var2 = "#{@var2}"
209
+ if @operation == '*'
210
+ var1 = "(#{@var1})" if @var1.is_a?(Expression) && (@var1.plus? || @var1.minus?)
211
+ var2 = "(#{@var2})" if @var2.is_a?(Expression) && (@var2.plus? || @var1.minus?)
212
+ end
213
+ "#{var1}#{@operation}#{var2}"
214
+ end
215
+
216
+ def plus?
217
+ @operation == '+'
218
+ end
219
+
220
+ def minus?
221
+ @operation == '-'
222
+ end
223
+
224
+ def multiply?
225
+ @operation == '*'
226
+ end
227
+
228
+ def value
229
+ if undefined_variables.empty?
230
+ value_of(@var1).send @operation, value_of(@var2)
231
+ end
232
+ end
233
+
234
+ def undefined_variables
235
+ (undefined_variables_of(@var1) + undefined_variables_of(@var2)).uniq
236
+ end
237
+
238
+ private
239
+
240
+ def undefined_variables_of(variable)
241
+ variable.is_a?(Operatable) ? variable.undefined_variables : []
242
+ end
243
+
244
+ def value_of(variable)
245
+ variable.is_a?(Operatable) ? variable.value : variable
246
+ end
247
+ end
248
+
249
+ class Method < Operatable
250
+ def initialize(variable, operation)
251
+ @variable, @operation = variable, operation
252
+ end
253
+
254
+ def to_s
255
+ "#{@operation}(#{@variable})"
256
+ end
257
+
258
+ def value
259
+ Math.send @operation, @variable.value if undefined_variables.empty?
260
+ end
261
+
262
+ def undefined_variables
263
+ @variable.undefined_variables
264
+ end
265
+ end
266
+
267
+ class UnaryMinus < Operatable
268
+ attr_reader :variable
269
+
270
+ def self.create(expression)
271
+ if expression.is_a? UnaryMinus
272
+ expression.variable
273
+ else
274
+ new expression
275
+ end
276
+ end
277
+
278
+ def initialize(variable)
279
+ @variable = variable
280
+ end
281
+
282
+ def to_s
283
+ if @variable.is_a? Variable
284
+ "-#{@variable}"
285
+ else
286
+ "(-#{@variable})"
287
+ end
288
+ end
289
+
290
+ def value
291
+ -@variable.value if undefined_variables.empty?
292
+ end
293
+
294
+ def undefined_variables
295
+ @variable.undefined_variables
296
+ end
297
+ end
298
+ end
299
+
300
+ module Kernel
301
+ def var(options={})
302
+ Symbolic::Variable.new options
303
+ end
304
+
305
+ def symbolic
306
+ Symbolic.enabled = true
307
+ yield
308
+ Symbolic.enabled = false
309
+ end
310
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'symbolic'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Symbolic" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: symbolic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - brainopia
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-17 00:00:00 +03:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ description:
26
+ email: ravwar@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ files:
34
+ - .gitignore
35
+ - README
36
+ - Rakefile
37
+ - lib/symbolic.rb
38
+ - spec/spec.opts
39
+ - spec/spec_helper.rb
40
+ - spec/symbolic_spec.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/brainopia/symbolic
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --charset=UTF-8
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.3.5
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Symbolic math for ruby
69
+ test_files:
70
+ - spec/spec_helper.rb
71
+ - spec/symbolic_spec.rb