rucas 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ module Rucas
2
+ #
3
+ # Private utility methods.
4
+ #
5
+ module Utility
6
+ def meta_def name, &block
7
+ (class << self; self; end).instance_eval { define_method(name,&block) }
8
+ end
9
+ private :meta_def
10
+ end
11
+ end
@@ -0,0 +1,216 @@
1
+ require "test/unit"
2
+ require "rucas"
3
+
4
+ class TestRucas < Test::Unit::TestCase
5
+ include Rucas
6
+ include Rucas::Symbolic
7
+
8
+ def setup
9
+ # Some variables to play with.
10
+ @s = Scope.new
11
+ @s.rucas {
12
+ var :x
13
+ var :y
14
+ var :z
15
+ var :a
16
+ var :b
17
+ }
18
+ end
19
+
20
+ # Shorthand for "assert expression equal to string;" block is evaluated in the
21
+ # scope +@s+.
22
+ def axes string, &block
23
+ assert_equal string, @s.rucas(&block).to_s
24
+ end
25
+
26
+ # Shorthand for "assert expression equal to string when simplified;" block is
27
+ # evaluated in the scope +@s+.
28
+ def axes_simplify string, &block
29
+ assert_equal string, @s.rucas(&block).simplify.to_s
30
+ end
31
+
32
+ # Variables in subscope don't appear in parent scope.
33
+ def test_scopes
34
+ s0 = Scope.new
35
+ s0.rucas {
36
+ var :a
37
+ var :b
38
+ }
39
+ s1 = s0.subscope
40
+ s1.rucas {
41
+ var :c
42
+ }
43
+ assert s0.respond_to?(:a)
44
+ assert s0.respond_to?(:b)
45
+ assert !s0.respond_to?(:c)
46
+ assert s1.respond_to?(:a)
47
+ assert s1.respond_to?(:b)
48
+ assert s1.respond_to?(:c)
49
+ end
50
+
51
+ # Basic operations; human-readable string conversions.
52
+ def test_arithmetic
53
+ s = Scope.new; s.rucas { var :p; var :q }
54
+ assert_equal "p + q", s.rucas{ p + q }.to_s
55
+ assert_equal "p - q", s.rucas{ p - q }.to_s
56
+ assert_equal "(p + q)*(p - q)", s.rucas{ (p + q)*(p - q) }.to_s
57
+ assert_equal "(p + q) / (p - q)", s.rucas{ (p + q)/(p - q) }.to_s
58
+ assert_equal "(p + q)**2", s.rucas{ (p + q)**2 }.to_s
59
+ assert_equal "(p + q)**(q + 1)", s.rucas{ (p + q)**(q + 1) }.to_s
60
+ end
61
+
62
+ def test_unary_operators
63
+ axes("-x + 1") { -x + 1 }
64
+ axes("1 + -x") { 1 + -x }
65
+ axes("1 - -x") { 1 - -x }
66
+ axes("x + 1") { +x + 1 }
67
+ axes("1 + x") { 1 + +x }
68
+ end
69
+
70
+ # Simplification identities.
71
+ def test_simplify_add
72
+ axes_simplify("x") {x}
73
+ axes_simplify("x + y") {x + y}
74
+ axes_simplify("x + y + z") {x + y + z}
75
+ axes_simplify("x") {x + 0}
76
+ axes_simplify("x") {0 + x}
77
+ axes_simplify("1 + x") {1 + x + 0}
78
+ axes_simplify("x + 1") {0 + x + 1}
79
+ axes_simplify("1 + x + y") {1 + x + 0 + y}
80
+ axes_simplify("y + x + 1") {y + 0 + x + 1}
81
+ end
82
+
83
+ # Simplification identities.
84
+ def test_simplify_sub
85
+ axes_simplify("x - y") {x - y}
86
+ axes_simplify("-x") {0 - x}
87
+ axes_simplify("x") {x - 0}
88
+ axes_simplify("1") {x + 1 - x}
89
+ axes_simplify("-1") {x - 1 - x}
90
+ end
91
+
92
+ # Simplification identities.
93
+ def test_simplify_mul
94
+ axes_simplify("x*y") {x*y}
95
+ axes_simplify("x") {x*1}
96
+ axes_simplify("x") {1*x}
97
+ axes_simplify("0") {x*0}
98
+ axes_simplify("0") {0*x}
99
+ end
100
+
101
+ # Simplification identities.
102
+ def test_simplify_div
103
+ axes_simplify("x / y") {x/y}
104
+ axes_simplify("x") {x/1}
105
+ axes_simplify("1") {y/y}
106
+ axes_simplify("NaN") {x/0}
107
+ end
108
+
109
+ # Simplification identities.
110
+ def test_simplify_exp
111
+ axes_simplify("x**y") {x**y}
112
+ axes_simplify("1") {x**0}
113
+ axes_simplify("1") {Expr.make(0)**0} # at least according to Ruby
114
+ axes_simplify("1") {0**Expr.make(0)} # at least according to Ruby
115
+ axes_simplify("1 / x") {x**-1}
116
+ end
117
+
118
+ # Some other tests.
119
+ def test_simplify_misc
120
+ axes_simplify("a") {x + a*1 - x}
121
+ axes_simplify("0") {x + a/1 - x - a}
122
+ axes_simplify("x**2 + 2*x + 1") {x*x + x + x + 1}
123
+ axes_simplify("1 + 2*x + x**2") {1 + x + x + x*x}
124
+ axes_simplify("1") {2 ** (x - y - x + y)}
125
+ axes_simplify("y*x**2") {y*x*x}
126
+ end
127
+
128
+ def test_constants
129
+ assert_equal nil, @s.rucas {(x + 1).value}
130
+ assert_equal 3, @s.rucas {(x + 1).with(x => 2).value}
131
+ axes_simplify("x + 2") {(x + 1) + 1}
132
+ axes_simplify("x + 3") {(x + 1) + 2}
133
+ end
134
+
135
+ # The tests from Norvig's Paradigms of AI Programming.
136
+ def test_paip
137
+ # 8.2: Simplification Rules
138
+ axes_simplify("4") {2 + 2}
139
+ axes_simplify("137") {5 * 20 + 30 + 7}
140
+ axes_simplify("0") {5 * x - (4 + 1) * x}
141
+ axes_simplify("0") {y / z * (5 * x - (4 + 1) * x)}
142
+ axes_simplify("x") {(4 - 3) * x + (y / y - 1) * z}
143
+ # ((simp '(1 * f(x) + 0)) => (F X) )
144
+
145
+ # 8.3 Associativity and Commutativity
146
+ # NB: the rest of these PAIP tests fail -- see "things that don't simplify"
147
+ axes_simplify("6*x") {3 * 2 * x}
148
+
149
+ # There are some more when we support logs, trig and differentiation
150
+ end
151
+
152
+ def test_unpatch
153
+ # Patches are initially applied; unapply and then reapply.
154
+ Rucas::Extensions.unapply
155
+ assert_raise(TypeError) { with_rucas { var :x; 1 + x } }
156
+ Rucas::Extensions.apply
157
+ assert_equal "1 + x", with_rucas { var :x; 1 + x }.to_s
158
+ # Do it again to make sure it's really reversible.
159
+ Rucas::Extensions.unapply
160
+ assert_raise(TypeError) { with_rucas { var :x; 1 + x } }
161
+ Rucas::Extensions.apply
162
+ assert_equal "1 + x", with_rucas { var :x; 1 + x }.to_s
163
+ end
164
+
165
+ def test_match
166
+ s = Scope.new;
167
+ s.rucas {
168
+ var :x
169
+ var :y
170
+ var :a
171
+ var :b
172
+ }
173
+
174
+ # Single match.
175
+ binding = s.rucas{ x.match(1) }
176
+ assert_equal 1, binding[s.x]
177
+ binding = s.rucas{ x.match(a) }
178
+ assert_equal s.a, binding[s.x]
179
+ binding = s.rucas{ x.match(-a) }
180
+ assert_equal(-s.a, binding[s.x])
181
+ binding = s.rucas{ x.match(b) }
182
+ assert_equal s.b, binding[s.x]
183
+ binding = s.rucas{ x.match(a + b) }
184
+ assert_equal s.a + s.b, binding[s.x]
185
+
186
+ # Expression matches with distinct variables.
187
+ binding = s.rucas {(x + y).match(a + 1)}
188
+ assert_equal s.a, binding[s.x]
189
+ assert_equal "1", binding[s.y].to_s
190
+ binding = s.rucas {(x + y).match(a + 1)}
191
+ assert_equal "1", binding[s.y].to_s
192
+
193
+ # Matching is left-associative.
194
+ binding = s.rucas {(x + y).match(a + b + 1)}
195
+ assert_equal "a + b", binding[s.x].to_s
196
+ assert_equal "1", binding[s.y].to_s
197
+
198
+ # Expression matches with repeated variable.
199
+ binding = s.rucas {(x + x).match(a + a)}
200
+ assert_equal s.a, binding[s.x]
201
+ binding = s.rucas {(x + x).match(a + b)}
202
+ assert !binding
203
+ binding = s.rucas {(x + x).match(1 + 1)}
204
+ assert !binding # minor gotcha
205
+
206
+ # Expression matches with constants.
207
+ binding = s.rucas {(x + 0).match(a + 0)}
208
+ assert_equal s.a, binding[s.x]
209
+ binding = s.rucas {(0 + x).match(a + 0)}
210
+ assert !binding
211
+ binding = s.rucas {(0 + x).match(0 + a + 1)}
212
+ assert !binding # matching is not currently recursive
213
+ binding = s.rucas {(0 + x).match(0 + (a + 1))}
214
+ assert_equal s.a + 1, binding[s.x]
215
+ end
216
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rucas
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - John Lees-Miller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-03 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: facets
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.3.3
34
+ version:
35
+ description: The beginnings of a computer algebra system in ruby.
36
+ email:
37
+ - jdleesmiller@gmail.com
38
+ executables:
39
+ - rucas
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - README.txt
46
+ files:
47
+ - .autotest
48
+ - History.txt
49
+ - Manifest.txt
50
+ - README.txt
51
+ - README.txt.erb
52
+ - Rakefile
53
+ - bin/rucas
54
+ - lib/rucas.rb
55
+ - lib/rucas/extensions.rb
56
+ - lib/rucas/rewrite.rb
57
+ - lib/rucas/simplify.rb
58
+ - lib/rucas/symbolic.rb
59
+ - lib/rucas/utility.rb
60
+ - test/test_rucas.rb
61
+ has_rdoc: true
62
+ homepage: http://github.com/jdleesmiller/rucas
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --main
66
+ - README.txt
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ requirements: []
82
+
83
+ rubyforge_project: rucas
84
+ rubygems_version: 1.3.1
85
+ signing_key:
86
+ specification_version: 2
87
+ summary: The beginnings of a Computer Algebra System in ruby
88
+ test_files:
89
+ - test/test_rucas.rb