rucas 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/.autotest +23 -0
- data/History.txt +2 -0
- data/Manifest.txt +14 -0
- data/README.txt +108 -0
- data/README.txt.erb +157 -0
- data/Rakefile +35 -0
- data/bin/rucas +69 -0
- data/lib/rucas.rb +48 -0
- data/lib/rucas/extensions.rb +99 -0
- data/lib/rucas/rewrite.rb +181 -0
- data/lib/rucas/simplify.rb +102 -0
- data/lib/rucas/symbolic.rb +238 -0
- data/lib/rucas/utility.rb +11 -0
- data/test/test_rucas.rb +216 -0
- metadata +89 -0
data/test/test_rucas.rb
ADDED
@@ -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
|