rucas 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
@@ -0,0 +1,2 @@
1
+ === 0.0.1 2009-12-03
2
+ * initial release
@@ -0,0 +1,14 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ README.txt.erb
6
+ Rakefile
7
+ bin/rucas
8
+ lib/rucas.rb
9
+ lib/rucas/extensions.rb
10
+ lib/rucas/rewrite.rb
11
+ lib/rucas/simplify.rb
12
+ lib/rucas/symbolic.rb
13
+ lib/rucas/utility.rb
14
+ test/test_rucas.rb
@@ -0,0 +1,108 @@
1
+
2
+ = rucas
3
+
4
+ http://github.com/jdleesmiller/rucas
5
+
6
+ == DESCRIPTION
7
+
8
+ The beginnings of a Computer Algebra System in ruby.
9
+ Supports basic simplification of symbolic expressions over the real numbers.
10
+ Expressions can be entered and manipulated using standard ruby.
11
+
12
+ This is at a very early stage; many things may change.
13
+
14
+ == SYNOPSIS
15
+
16
+ require 'rubygems'
17
+ require 'rucas'
18
+
19
+ include Rucas
20
+
21
+ # basic algebraic simplification
22
+ with_rucas {
23
+ var :x
24
+ var :y
25
+ ((x + 1 - x)**y).simplify
26
+ }.to_s #=> "1"
27
+
28
+ # manipulate symbols using standard ruby code
29
+ with_rucas {
30
+ var :x
31
+ var :y
32
+ var :z
33
+ foo = [x,y,z].inject {|s,e| s + e}
34
+ foo ** 2
35
+ }.to_s #=> "(x + y + z)**2"
36
+
37
+ # build symbolics into ruby objects
38
+ class Foo
39
+ include Rucas::Symbolic
40
+ def initialize
41
+ var :p
42
+ var :q
43
+ end
44
+
45
+ def bar
46
+ (p + 1) / (q - p)
47
+ end
48
+ end
49
+ Foo.new.bar.to_s #=> "(p + 1) / (q - p)"
50
+
51
+ # build expression trees
52
+ with_rucas {
53
+ var :p
54
+ 1 + p
55
+ } #=> #<struct Rucas::Symbolic::AddExpr op=:+,
56
+ lhs=#<struct Rucas::Symbolic::ConstExpr value=1>,
57
+ rhs=#<struct Rucas::Symbolic::VarExpr name=:p>>
58
+
59
+ == NOTES
60
+
61
+ * Run an interactive session with the +rucas+ command; the interactive rucas is built on irb.
62
+ * The implementation is based on the source code for Norvig's Paradigms of AI Programming (PAIP), but rucas is not yet as complete as the macsyma in Norvig's book.
63
+
64
+ == PROBLEMS
65
+
66
+ * Simplification is quite dumb, because it doesn't understand much about commutativity and associativity.
67
+ * Doesn't do differentiation or integration (but could in the future).
68
+ * Doesn't support special functions (but could in the future).
69
+ * Doesn't integrate with other CAS systems (e.g. maxima) (but could in the future).
70
+ * Doesn't do anything with logical conditions on variables (e.g. x > 0).
71
+
72
+ == INSTALL
73
+
74
+ On *nix systems,
75
+
76
+ sudo gem install rucas
77
+
78
+ should do it.
79
+
80
+ To run the interactive rucas, you should just be able to type +rucas+. If it doesn't work, you may need to change your PATH settings. The procedure for this is currently to run
81
+ gem env
82
+ and look at the EXECUTABLE DIRECTORY; then run
83
+ echo $PATH
84
+ and make sure that the executable directory is on your path. If it's not, you will have to add it (search for "add directory to path").
85
+
86
+ == LICENSE
87
+
88
+ Copyright (c) 2009 John Lees-Miller
89
+
90
+ Permission is hereby granted, free of charge, to any person obtaining
91
+ a copy of this software and associated documentation files (the
92
+ 'Software'), to deal in the Software without restriction, including
93
+ without limitation the rights to use, copy, modify, merge, publish,
94
+ distribute, sublicense, and/or sell copies of the Software, and to
95
+ permit persons to whom the Software is furnished to do so, subject to
96
+ the following conditions:
97
+
98
+ The above copyright notice and this permission notice shall be
99
+ included in all copies or substantial portions of the Software.
100
+
101
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
102
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
103
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
104
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
105
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
106
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
107
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
108
+
@@ -0,0 +1,157 @@
1
+ <%
2
+ # This is intended to run against the development version.
3
+ for d in %w(lib bin)
4
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), d)
5
+ end
6
+ %>
7
+ = rucas
8
+
9
+ http://github.com/jdleesmiller/rucas
10
+
11
+ == DESCRIPTION
12
+
13
+ The beginnings of a Computer Algebra System in ruby.
14
+ Supports basic simplification of symbolic expressions over the real numbers.
15
+ Expressions can be entered and manipulated using standard ruby.
16
+
17
+ This is at a very early stage; many things may change.
18
+
19
+ == SYNOPSIS
20
+
21
+ require 'rubygems'
22
+ require 'rucas'
23
+
24
+ include Rucas
25
+ <%
26
+ require 'rubygems'
27
+ require 'rucas'
28
+ require 'facets/string/word_wrap'
29
+ include Rucas
30
+
31
+ #
32
+ # Return code (as string) and the resulting output (as string).
33
+ # Make some effort to format nicely.
34
+ #
35
+ def x code
36
+ # It's nice to put the erb line noise on its own line.
37
+ code.sub! /^\n/, ''
38
+ code.rstrip!
39
+ return "" if code == ""
40
+
41
+ output = eval(code).inspect
42
+
43
+ # Try to be smart about respecting line widths.
44
+ code_lines = code.lines.to_a
45
+ indent = code_lines.map {|l| l =~ /^(\s+)/; $1}.min_by {|s| s.length}
46
+
47
+ arrow = "#=> "
48
+ output_col = 25
49
+ max_width = 80
50
+ code_len = code_lines.last.length
51
+
52
+ output_width = max_width - output_col - arrow.length - 1
53
+ wrapped_output = output.word_wrap(output_width)
54
+ wrapped_output = wrapped_output.take(1) +
55
+ wrapped_output.drop(1).map {|l| " "*(arrow.length+1+output_col) + l}
56
+ wrapped_output = wrapped_output.join.rstrip!
57
+ start = code_lines.reverse.drop(1).reverse.join
58
+ "#{start}%-#{output_col}s #{arrow}#{wrapped_output}" % code_lines.last
59
+ end
60
+
61
+ # puts ((x + 1 - x)**y).simplify # ==> 1
62
+ # puts (x + 1).with(x => 2).value # ==> 3
63
+ %>
64
+ # basic algebraic simplification
65
+ <%=x %q{
66
+ with_rucas {
67
+ var :x
68
+ var :y
69
+ ((x + 1 - x)**y).simplify
70
+ }.to_s
71
+ }%>
72
+
73
+ # manipulate symbols using standard ruby code
74
+ <%=x %q{
75
+ with_rucas {
76
+ var :x
77
+ var :y
78
+ var :z
79
+ foo = [x,y,z].inject {|s,e| s + e}
80
+ foo ** 2
81
+ }.to_s
82
+ }%>
83
+
84
+ # build symbolics into ruby objects
85
+ <%=x %q{
86
+ class Foo
87
+ include Rucas::Symbolic
88
+ def initialize
89
+ var :p
90
+ var :q
91
+ end
92
+
93
+ def bar
94
+ (p + 1) / (q - p)
95
+ end
96
+ end
97
+ Foo.new.bar.to_s
98
+ }%>
99
+
100
+ # build expression trees
101
+ <%=x %q{
102
+ with_rucas {
103
+ var :p
104
+ 1 + p
105
+ }
106
+ }%>
107
+
108
+ == NOTES
109
+
110
+ * Run an interactive session with the +rucas+ command; the interactive rucas is built on irb.
111
+ * The implementation is based on the source code for Norvig's Paradigms of AI Programming (PAIP), but rucas is not yet as complete as the macsyma in Norvig's book.
112
+
113
+ == PROBLEMS
114
+
115
+ * Simplification is quite dumb, because it doesn't understand much about commutativity and associativity.
116
+ * Doesn't do differentiation or integration (but could in the future).
117
+ * Doesn't support special functions (but could in the future).
118
+ * Doesn't integrate with other CAS systems (e.g. maxima) (but could in the future).
119
+ * Doesn't do anything with logical conditions on variables (e.g. x > 0).
120
+
121
+ == INSTALL
122
+
123
+ On *nix systems,
124
+
125
+ sudo gem install rucas
126
+
127
+ should do it.
128
+
129
+ To run the interactive rucas, you should just be able to type +rucas+. If it doesn't work, you may need to change your PATH settings. The procedure for this is currently to run
130
+ gem env
131
+ and look at the EXECUTABLE DIRECTORY; then run
132
+ echo $PATH
133
+ and make sure that the executable directory is on your path. If it's not, you will have to add it (search for "add directory to path").
134
+
135
+ == LICENSE
136
+
137
+ Copyright (c) 2009 John Lees-Miller
138
+
139
+ Permission is hereby granted, free of charge, to any person obtaining
140
+ a copy of this software and associated documentation files (the
141
+ 'Software'), to deal in the Software without restriction, including
142
+ without limitation the rights to use, copy, modify, merge, publish,
143
+ distribute, sublicense, and/or sell copies of the Software, and to
144
+ permit persons to whom the Software is furnished to do so, subject to
145
+ the following conditions:
146
+
147
+ The above copyright notice and this permission notice shall be
148
+ included in all copies or substantial portions of the Software.
149
+
150
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
151
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
152
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
153
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
154
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
155
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
156
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
157
+
@@ -0,0 +1,35 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require 'erb'
6
+
7
+ Hoe.spec 'rucas' do |spec|
8
+ developer('John Lees-Miller', 'jdleesmiller@gmail.com')
9
+ spec.description = 'The beginnings of a computer algebra system in ruby.'
10
+ extra_deps << ['facets']
11
+
12
+ # self.rubyforge_name = 'rucasx' # if different than 'rucas'
13
+ end
14
+
15
+ desc "run bin/rucas"
16
+ task :run do
17
+ system "/usr/bin/ruby1.8 -w -Ilib:ext:bin:test -rubygems bin/rucas"
18
+ end
19
+
20
+ desc "patch manifest"
21
+ task :patch_manifest do
22
+ system "rake check_manifest | grep -v \"^(in \" | patch"
23
+ end
24
+
25
+ file "README.txt" => "README.txt.erb" do |t|
26
+ for d in %w(lib bin)
27
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), d)
28
+ end
29
+ File.open(t.name, 'w') do |f|
30
+ f.puts(ERB.new(File.read(t.prerequisites.first)).result)
31
+ end
32
+ end
33
+ task :docs => "README.txt"
34
+
35
+ # vim: syntax=ruby
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Interactive rucas shell based on the standard Interactive Ruby Shell (irb).
5
+ #
6
+
7
+ require 'rucas'
8
+ require 'irb'
9
+
10
+ # Now everything understands symbols.
11
+ include Rucas::Symbolic
12
+ include Rucas
13
+
14
+ # Helper to print example code.
15
+ def rucas_help_example code
16
+ puts "> #{code}"
17
+ puts " #=> #{$rucas_help_scope.rucas{ Kernel::eval(code) }.inspect}"
18
+ end
19
+
20
+ # A short help message.
21
+ def rucas_help
22
+ puts "Interactive rucas is based on the standard Interactive Ruby (irb)."
23
+ puts "Declare symbolic variables using var."
24
+ puts "Then you can manipulate them using standard Ruby code."
25
+ puts ""
26
+ puts "Examples:"
27
+ # Run examples in their own scope to avoid clobbering user's stuff.
28
+ # I was using XMP for this, but it seems to interfere with irb.
29
+ # The only problem with this approach is that it doesn't allow local
30
+ # variables, so we can't demo those; we'd have to use @vars.
31
+ $rucas_help_scope = Scope.new
32
+ rucas_help_example "var :x"
33
+ rucas_help_example "var :y"
34
+ rucas_help_example "var :z"
35
+ rucas_help_example "(x + 1 - x).simplify.to_s"
36
+ rucas_help_example "[x, y, z].inject{|s, x| s + x}.to_s"
37
+ puts ""
38
+ puts "You can use underscore (_) to get the result of the last command."
39
+ end
40
+
41
+ puts "-- interactive rucas --"
42
+ puts "To exit, type exit or quit."
43
+ puts "For help, type rucas_help."
44
+
45
+ #
46
+ # Custom prompt. The best way I've found to do this is to install the RUCAS
47
+ # prompt as the default in irb's initialization routine. Clearly this is not an
48
+ # ideal solution.
49
+ #
50
+ module IRB
51
+ def IRB.init_config_with_rucas ap_path
52
+ init_config_without_rucas(ap_path)
53
+ IRB.conf[:PROMPT][:RUCAS] = {
54
+ :PROMPT_I => "rucas:%03n:%i> ",
55
+ :PROMPT_S => "rucas:%03n:%i%l ",
56
+ :PROMPT_C => "rucas:%03n:%i* ",
57
+ :RETURN => "%s\n"
58
+ }
59
+ IRB.conf[:PROMPT_MODE] = :RUCAS
60
+ end
61
+
62
+ class <<self
63
+ alias_method :init_config_without_rucas, :init_config
64
+ alias_method :init_config, :init_config_with_rucas
65
+ end
66
+ end
67
+
68
+ IRB.start(__FILE__)
69
+
@@ -0,0 +1,48 @@
1
+ require 'rucas/utility'
2
+ require 'rucas/symbolic'
3
+ require 'rucas/extensions'
4
+
5
+ module Rucas
6
+ VERSION = '0.0.1'
7
+
8
+ #
9
+ # Open classes to make constants work.
10
+ #
11
+ Extensions.apply
12
+
13
+ #
14
+ # Scope storing currently declared variables.
15
+ #
16
+ # Note: You can do this using any class; just include the Symbolic module.
17
+ #
18
+ class Scope
19
+ include Symbolic
20
+
21
+ #
22
+ # Create a subscope; this is just a clone of the current scope, so it
23
+ # includes all of the symbols of this scope.
24
+ #
25
+ def subscope
26
+ self.clone
27
+ end
28
+
29
+ #
30
+ # Evaluate given block in this scope.
31
+ #
32
+ def rucas &block
33
+ self.instance_eval(&block)
34
+ end
35
+ end
36
+
37
+ #
38
+ # Interpret code in the block as Rucas code and return the result of the
39
+ # block.
40
+ #
41
+ def with_rucas scope=Scope.new, &block
42
+ scope.rucas(&block)
43
+ end
44
+ end
45
+
46
+ require 'rucas/rewrite'
47
+ require 'rucas/simplify'
48
+