cartesian 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,42 @@
1
+ === 0.5.0 2011-01-03
2
+
3
+ * 1 major enhancements:
4
+ * Workaround for weird splat behaviour on Ruby <= 1.8.7, so now all tests (100% coverage)
5
+ now run with 100% pass with the following Ruby versions:
6
+ * MRI 1.8.6-p399, 1.8.7-p22, 1.8.7-p330, 1.9.1-p378, and 1.9.2-p136
7
+ * JRuby 1.5.3, 1.5.5, and 1.5.6
8
+ * Ruby Enterprise Edition 1.8.7-2010.02
9
+ * rubinius 1.2.0
10
+
11
+ * 5 minor enhancements:
12
+ * gem "renamed" (changed from Cartesian to cartesian)
13
+ * removed unused alias to CartesianIterator#to_a method (#to_ary)
14
+ * removed own #to_a implementation
15
+ + #to_a and others are now provided by Enumerable mixin
16
+ * removed unused Iterable#start alias for #restart (conflicted with Array#start provided by Rubinius)
17
+ * now build with newgem 1.5.3
18
+
19
+ === 0.4.1 04-11-2008 03:18
20
+
21
+ * 1 major enhancement:
22
+ * mainly bugfixes and some refactoring. new features: left_product and non-destructive #product methods
23
+
24
+ === 0.3.0 29-10-2007 05:49
25
+
26
+ [undocumented changes]
27
+
28
+ === 0.2.3 13-01-2007 20:50
29
+
30
+ * 1 minor enhancement:
31
+ * power! (aliased as "**") method added
32
+
33
+ === 0.2.1 13-01-2007 01:44
34
+
35
+ * 1 major enhancement:
36
+ * Method ".x(enum)" added, which has constant memory requirements, in contrast with the exponential memory usage of the conventional approach.
37
+
38
+ === 0.1.0 24-11-2006 05:35
39
+
40
+ * 1 major enhancement:
41
+ * first public release
42
+
data/Manifest.txt ADDED
@@ -0,0 +1,25 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ Wishlist.txt
7
+ config/hoe.rb
8
+ config/requirements.rb
9
+ lib/cartesian.rb
10
+ lib/cartesian/grid_search.rb
11
+ lib/cartesian/version.rb
12
+ lib/cartesian_iterator.rb
13
+ lib/grid_search.rb
14
+ lib/recursive.rb
15
+ script/console
16
+ script/destroy
17
+ script/generate
18
+ test/benchmark.rb
19
+ test/extensions.rb
20
+ test/test_cartesian.rb
21
+ test/test_cartesian_iterator.rb
22
+ test/test_extensions.rb
23
+ test/test_grid_search.rb
24
+ test/test_helper.rb
25
+ test/test_suite.rb
data/PostInstall.txt ADDED
@@ -0,0 +1,7 @@
1
+
2
+ For more information on cartesian, see http://cartesian.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
data/README.rdoc ADDED
@@ -0,0 +1,81 @@
1
+ = cartesian
2
+
3
+ * http://github.com/adrianomitre/cartesian
4
+
5
+ == DESCRIPTION:
6
+
7
+ Provides methods for the calculation of the cartesian producted between two
8
+ or more enumerable objects. Includes grid search optimization methods.
9
+ It can also be easily and conveniently mixed in into any enumerable class.
10
+
11
+ == FEATURES:
12
+
13
+ The module is automatically mixed in Array class, but the names of the methods for mixin are different.
14
+
15
+ Module:
16
+ Cartesian::product(foo, bar)
17
+ Mixin:
18
+ foo.cartesian( bar )
19
+
20
+ == SYNOPSIS:
21
+
22
+ One can use the Cartesian module directly
23
+ require 'cartesian'
24
+ foo = [1, 2]
25
+ bar = ["a", "b"]
26
+ Cartesian::product(foo, bar) #=> [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
27
+
28
+ or use the methods provided by the mixin in the Array classees
29
+ require 'cartesian'
30
+ foo = [1, 2]
31
+ bar = ["a", "b"]
32
+ foo.cartesian(bar) #=> [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
33
+
34
+ which include the short and sweet _x_ method
35
+ v = [] #=> []
36
+ for a,b in [1,2].x [3,4]
37
+ v << [a,b]
38
+ end #=> true
39
+ v #=> [[1, 3], [1, 4], [2, 3], [2, 4]]
40
+
41
+ The '**' operator provides a convenient way of iterating multi-dimensionally over the same array or range
42
+ v = [0,1]**3 #=> #<CartesianIterator:0x7f2fb8e54978 @tot_iter=8, @lists=[[0, 1], [0, 1], [0, 1]]>
43
+ v.to_a #=> [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
44
+
45
+ Finally, the grid search methods
46
+ require 'grid_search'
47
+ [-1, 0, 1, 2].argmax {|x| x**2 } #=> 2
48
+ [-1, 0, 1, 2].argmin {|x| x.abs } #=> 0
49
+
50
+ == REQUIREMENTS:
51
+
52
+ * None, besides the Ruby interpreter and standard library. This gems was successfully tested on all relevant Ruby versions: MRI/YARV, JRuby, Rubinius, and REE. For details, see History.txt.
53
+
54
+ == INSTALL:
55
+
56
+ * sudo gem install cartesian
57
+
58
+ == LICENSE:
59
+
60
+ (The MIT License)
61
+
62
+ Copyright (c) 2011 Adriano Mitre <adriano.mitre@gmail.com>
63
+
64
+ Permission is hereby granted, free of charge, to any person obtaining
65
+ a copy of this software and associated documentation files (the
66
+ 'Software'), to deal in the Software without restriction, including
67
+ without limitation the rights to use, copy, modify, merge, publish,
68
+ distribute, sublicense, and/or sell copies of the Software, and to
69
+ permit persons to whom the Software is furnished to do so, subject to
70
+ the following conditions:
71
+
72
+ The above copyright notice and this permission notice shall be
73
+ included in all copies or substantial portions of the Software.
74
+
75
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
76
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
77
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
78
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
79
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
80
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
81
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/cartesian'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'cartesian' do
14
+ self.developer 'Adriano Mitre', 'adriano.mitre@gmail.com'
15
+ self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
16
+ self.rubyforge_name = self.name # TODO this is default value
17
+ # self.extra_deps = [['activesupport','>= 2.0.2']]
18
+
19
+ end
20
+
21
+ require 'newgem/tasks'
22
+ Dir['tasks/**/*.rake'].each { |t| load t }
23
+
24
+ # TODO - want other tests/tasks run by default? Add them to the list
25
+ # remove_task :default
26
+ # task :default => [:spec, :features]
data/Wishlist.txt ADDED
@@ -0,0 +1 @@
1
+ * Release GridSearch as a separate, independent gem. Note that 'lib/grid_search.rb' is already independent.
data/config/hoe.rb ADDED
@@ -0,0 +1,81 @@
1
+ require 'cartesian/version'
2
+
3
+ AUTHOR = 'Adriano Mitre' # can also be an array of Authors
4
+ EMAIL = "adriano@mitre.com.br"
5
+ DESCRIPTION = <<EOS
6
+ Provides methods for the calculation of the cartesian producted between two
7
+ or more enumerable objects. Includes grid search optimization methods.
8
+ It can also be easily and conveniently mixed in into any enumerable class.
9
+ EOS
10
+ GEM_NAME = 'cartesian' # what ppl will type to install your gem
11
+ RUBYFORGE_PROJECT = 'cartesian' # The unix name for your project
12
+ HOMEPATH = "http://adrianomitre.github.com/cartesian/website/index.html"
13
+ DOWNLOAD_PATH = "https://github.com/adrianomitre/cartesian/archives/master"
14
+ EXTRA_DEPENDENCIES = [
15
+ # ['activesupport', '>= 1.3.1']
16
+ ] # An array of rubygem dependencies [name, version]
17
+
18
+ @config_file = "~/.rubyforge/user-config.yml"
19
+ @config = nil
20
+ RUBYFORGE_USERNAME = "unknown"
21
+ def rubyforge_username
22
+ unless @config
23
+ begin
24
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
25
+ rescue
26
+ puts <<-EOS
27
+ ERROR: No rubyforge config file found: #{@config_file}
28
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
29
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
30
+ EOS
31
+ exit
32
+ end
33
+ end
34
+ RUBYFORGE_USERNAME.replace @config["username"]
35
+ end
36
+
37
+
38
+ REV = nil
39
+ # UNCOMMENT IF REQUIRED:
40
+ # REV = YAML.load(`svn info`)['Revision']
41
+ VERS = Cartesian::VERSION::STRING + (REV ? ".#{REV}" : "")
42
+ RDOC_OPTS = ['--quiet', '--title', 'cartesian documentation',
43
+ "--opname", "index.html",
44
+ "--line-numbers",
45
+ "--main", "README",
46
+ "--inline-source"]
47
+
48
+ class Hoe
49
+ def extra_deps
50
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
51
+ @extra_deps
52
+ end
53
+ end
54
+
55
+ # Generate all the Rake tasks
56
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
57
+ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
58
+ p.developer(AUTHOR, EMAIL)
59
+ p.description = DESCRIPTION
60
+ p.summary = DESCRIPTION
61
+ p.url = HOMEPATH
62
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
63
+ p.test_globs = ["test/**/test_*.rb", "test/**/tc_*.rb"]
64
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
65
+
66
+ #~ p.files = FileList["{tests,lib}/**/*"].exclude("rdoc").to_a
67
+
68
+
69
+ # == Optional
70
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
71
+ #p.extra_deps = EXTRA_DEPENDENCIES
72
+
73
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
74
+ p.spec_extras = {:files => FileList["{tests,lib}/**/*"].exclude("rdoc").to_a}
75
+ end
76
+
77
+ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
78
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
79
+ $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
80
+ $hoe.rsync_args = '-av --delete --ignore-errors'
81
+ #~ $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
data/lib/cartesian.rb ADDED
@@ -0,0 +1,166 @@
1
+ #
2
+ # The CartesianProduct module provide methods for the calculation
3
+ # of the cartesian producted between two enumerable objects.
4
+ #
5
+ # It can also be easily mixed in into any enumerable class,
6
+ # i.e. any class with Enumerable module mixed in.
7
+ # Notice that the names of the methods for mixin are different.
8
+ #
9
+ # Module:
10
+ # Cartesian::product(foo, bar)
11
+ #
12
+ # Mixin:
13
+ # foo.cartesian( bar )
14
+ #
15
+ # The module is automatically mixed in Array class.
16
+ #
17
+ # == Author
18
+ # Adriano MITRE <adriano.mitre@gmail.com>
19
+ #
20
+ # == Example
21
+ #
22
+ # as module
23
+ # require 'cartesian'
24
+ # foo = [1, 2]
25
+ # bar = ["a", "b"]
26
+ # Cartesian::product(foo, bar) #=> [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
27
+ # as mixin
28
+ # require 'cartesian'
29
+ # foo = [1, 2]
30
+ # bar = ["a", "b"]
31
+ # foo.cartesian(bar) #=> [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
32
+ #
33
+
34
+ $:.unshift(File.dirname(__FILE__)) unless
35
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
36
+
37
+ require 'cartesian_iterator'
38
+
39
+ module Cartesian
40
+
41
+ VERSION = '0.5.0'
42
+
43
+ # Produces the cartesian product of self and other.
44
+ # The result is an array of pairs (i.e. two-element arrays).
45
+ #
46
+ # Cartesian::product( [1,2], %w(A B) ) #=> [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
47
+ #
48
+ # or, if mixed in into Array,
49
+ #
50
+ # [1,2].cartesian %w(A B) #=> [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
51
+ #
52
+ def Cartesian.product(first, second)
53
+ first.x(second).to_a
54
+ end
55
+
56
+ # Behaves as product, except for the elements are joined.
57
+ #
58
+ # Cartesian::joined_cartesian( [1,2], %w(A B) ) #=> ["1A", "1B", "2A", "2B"]
59
+ #
60
+ # or, if mixed in into Array,
61
+ #
62
+ # [1,2].joined_cartesian %w(A B) #=> ["1A", "1B", "2A", "2B"]
63
+ #
64
+ def Cartesian.joined_product(first, second)
65
+ product(first, second).map {|pair| pair.join }
66
+ end
67
+
68
+ # Cartesian.joined_product for mixin.
69
+ #
70
+ def joined_cartesian(other)
71
+ Cartesian.joined_product(self, other)
72
+ end
73
+
74
+ # Convenient way of iterating over the elements.
75
+ # Preferable when the cartesian product array
76
+ # is not needed, for the consumption of memory
77
+ # is fixed and very small, in contrast with the
78
+ # exponential memory requirements of the
79
+ # conventional approach.
80
+ #
81
+ # for row, col in (1..10).x(1..30)
82
+ # Matrix[row, col] = row**2 + col**3
83
+ # end
84
+ #
85
+ # Of course, calls can be chained as in
86
+ #
87
+ # for x, y, z in (1..10).x(1..10).x(1..10)
88
+ # # ... do something ...
89
+ # end
90
+ #
91
+ #--
92
+ # for letter, number in %w{a b c}.x(1..3)
93
+ # ... do something ...
94
+ # end
95
+ #++
96
+ #
97
+ # Beware that both +self+ and +other+ must implement
98
+ # +to_a+, i.e., be convertible to array.
99
+ #
100
+ def x(other)
101
+ case other
102
+ when CartesianIterator
103
+ other.left_product(self)
104
+ else
105
+ CartesianIterator.new(self, other)
106
+ end
107
+ end
108
+ alias cartesian x
109
+ alias right_product x
110
+
111
+ def left_product(other)
112
+ case other
113
+ when CartesianIterator
114
+ other.right_product(self)
115
+ else
116
+ CartesianIterator.new(other, self)
117
+ end
118
+ end
119
+
120
+ # Concise way of iterating multi-dimensionally
121
+ # over the same array or range.
122
+ #
123
+ # For instance,
124
+ #
125
+ # for x,y,z in [0,1]**3
126
+ # puts [x, y, z].join(',')
127
+ # end
128
+ #
129
+ # produces the following output
130
+ #
131
+ # 0,0,0
132
+ # 0,0,1
133
+ # 0,1,0
134
+ # 0,1,1
135
+ # 1,0,0
136
+ # 1,0,1
137
+ # 1,1,0
138
+ # 1,1,1
139
+ #
140
+ # It also works with Range objects.
141
+ #
142
+ def **(fixnum)
143
+ if fixnum < 0
144
+ raise ArgumentError, "negative power"
145
+ elsif fixnum == 0
146
+ return []
147
+ elsif fixnum == 1
148
+ return self
149
+ else
150
+ iter = CartesianIterator.new(self, self)
151
+ (fixnum-2).times do
152
+ iter.product!(self)
153
+ end
154
+ iter
155
+ end
156
+ end
157
+ alias :power! :**
158
+ end
159
+
160
+ class Array
161
+ include Cartesian
162
+ end
163
+
164
+ class Range
165
+ include Cartesian
166
+ end
@@ -0,0 +1,10 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..'))
2
+
3
+ require 'cartesian'
4
+ require 'grid_search'
5
+
6
+ class CartesianIterator
7
+ include GridSearch
8
+ end
9
+
10
+
@@ -0,0 +1,9 @@
1
+ module Cartesian #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 5
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,99 @@
1
+ class CartesianIterator
2
+
3
+ def initialize(foo, bar)
4
+ @lists = []
5
+ @tot_iter = 1
6
+ product!(foo)
7
+ product!(bar)
8
+ end
9
+
10
+ def dup
11
+ Marshal.load(Marshal.dump(self))
12
+ end
13
+
14
+ def equal(other)
15
+ self.instance_variables.each do |var_name|
16
+ return false if self.instance_variable_get(var_name) != other.instance_variable_get(var_name)
17
+ end
18
+ true
19
+ end
20
+ alias == equal
21
+
22
+ def product!(other)
23
+ @lists << other.to_a.dup
24
+ @tot_iter *= @lists[-1].size
25
+ self
26
+ end
27
+ alias right_product! product!
28
+ alias x! product!
29
+
30
+ def left_product!(other)
31
+ @lists.unshift other.to_a.dup
32
+ @tot_iter *= @lists[-1].size
33
+ self
34
+ end
35
+
36
+ def product(other)
37
+ (result = self.dup).product!(other)
38
+ result
39
+ end
40
+ alias right_product product
41
+ alias x product
42
+
43
+ def left_product(other)
44
+ (result = self.dup).left_product!(other)
45
+ result
46
+ end
47
+
48
+ def each
49
+ return false if @tot_iter < 1
50
+
51
+ elems = []
52
+ for list in @lists
53
+ elems << list.restart_and_raw_next
54
+ end
55
+ if RUBY_VERSION <= '1.9.1'; yield *elems.map {|x| x }; else; yield *elems; end
56
+
57
+ last_list_index = @lists.size-1
58
+ n = last_list_index
59
+ loop do
60
+ if elems[n] = @lists[n].raw_next
61
+ if RUBY_VERSION <= '1.9.1'; yield *elems.map {|x| x }; else; yield *elems; end
62
+ n = last_list_index
63
+ next
64
+ elsif n > 0
65
+ elems[n] = @lists[n].restart_and_raw_next
66
+ n -= 1
67
+ else
68
+ return true
69
+ end
70
+ end
71
+ end
72
+
73
+ include Enumerable
74
+
75
+ end
76
+
77
+ module Iterable
78
+ def restart
79
+ @next_index = -1
80
+ true
81
+ end
82
+
83
+ def next
84
+ restart unless @next_index
85
+ raw_next
86
+ end
87
+
88
+ def raw_next
89
+ self[@next_index += 1]
90
+ end
91
+
92
+ def restart_and_raw_next
93
+ self[@next_index = 0]
94
+ end
95
+ end
96
+
97
+ class Array
98
+ include Iterable
99
+ end
@@ -0,0 +1,40 @@
1
+ module GridSearch
2
+
3
+ # Finds the argument which maximizes the function given in the block trhu grid-search maximization.
4
+ # [-1,0,1,2].argmax {|x| x**2 } #=> 2
5
+ #
6
+ def argmax(&block)
7
+ argbest(:>, &block)
8
+ end
9
+
10
+ # Finds the argument which minimizes the function given in the block trhu grid-search minimization.
11
+ # [-1,0,1,2].argmin {|x| x**2 } #=> 0
12
+ #
13
+ def argmin(&block)
14
+ argbest(:<, &block)
15
+ end
16
+
17
+ private
18
+
19
+ def argbest(cmp)
20
+ best_arg, best_val = nil, nil
21
+ self.each do |*curr_arg|
22
+ curr_val = yield(*curr_arg)
23
+ if best_val.nil? || curr_val.send(cmp, best_val)
24
+ best_val = curr_val
25
+ best_arg = curr_arg
26
+ end
27
+ end
28
+ best_arg
29
+ end
30
+
31
+ end
32
+
33
+ module Enumerable
34
+ include GridSearch
35
+ end
36
+
37
+ class Array
38
+ include GridSearch
39
+ end
40
+
data/lib/recursive.rb ADDED
@@ -0,0 +1,8 @@
1
+ # Code by Brian Schröäer
2
+ # source: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/151857
3
+ #
4
+ def cartprod(base, *others)
5
+ return base.map { |a| [a] } if others.empty?
6
+ others = cartprod(*others)
7
+ base.inject([]) { | r, a | others.inject(r) { | r, b | r << ([a,*b]) } }
8
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/cartesian.rb'}"
9
+ puts "Loading cartesian gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
data/test/benchmark.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'cartesian'
2
+ require 'benchmark'
3
+
4
+ MULTIPLIER = 3
5
+ letras = ("a"*MULTIPLIER.."z"*MULTIPLIER).to_a
6
+ numeros = (0..10**1).to_a
7
+
8
+ Benchmark.bmbm do |x|
9
+ letras_numeros = nil
10
+ x.report("product") { letras_numeros = Cartesian.product(letras, numeros) }
11
+ x.report("product 2") { for x,y in letras_numeros; end }
12
+
13
+ x.report(".x") { letras_numeros = letras.x(numeros) }
14
+ x.report(".x 2") { for x,y in letras_numeros; end }
15
+ end
16
+
17
+ #~ x.report("productZip") { Cartesian.productZip(letras, numeros) }
18
+
19
+ #~ def Cartesian.productZip(first, second)
20
+ #~ result = []
21
+ #~ first.each do |a|
22
+ #~ aaa = Array.new(second.size) { a }
23
+ #~ result += aaa.zip(second)
24
+ #~ end
25
+ #~ result
26
+ #~ end
@@ -0,0 +1,12 @@
1
+ class Object
2
+
3
+ # Syntax sugar for "is this object among this array?"
4
+ #
5
+ # 1.among? [1,2,3] #=> true
6
+ # 0.among? [4,5] #=> false
7
+ #
8
+ def among?(ary)
9
+ ary.include? self
10
+ end
11
+
12
+ end
@@ -0,0 +1,67 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+ require 'cartesian'
3
+
4
+ class TestCartesian < Test::Unit::TestCase
5
+
6
+ def test_arrays
7
+ foo = [1,2,3]
8
+ bar = %w{a b c}
9
+ expected = [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"],
10
+ [2, "c"], [3, "a"], [3, "b"], [3, "c"]]
11
+ assert(foo.x(bar).to_a == expected)
12
+ assert(Cartesian.product(foo,bar) == expected)
13
+ end
14
+
15
+ def test_ranges
16
+ foo = 1..3
17
+ bar = 4..6
18
+ expected = [[1, 4], [1, 5], [1, 6], [2, 4], [2, 5],
19
+ [2, 6], [3, 4], [3, 5], [3, 6]]
20
+ assert(foo.x(bar).to_a == expected)
21
+ assert(Cartesian.product(foo,bar) == expected)
22
+ end
23
+
24
+ def test_product
25
+ c = [1].x([2])
26
+ c.x([3])
27
+ assert_equal [1].x([2]), c
28
+ end
29
+
30
+ def test_left_product
31
+ c = [1].right_product([2])
32
+ d = [1].left_product([2])
33
+ e = [2].left_product([1])
34
+ assert_not_equal c, d
35
+ assert_equal c, e
36
+ c = [1].x([2]).right_product([3])
37
+ d = [1].x([2]).left_product([3])
38
+ e = [2].x([3]).left_product([1])
39
+ assert_not_equal c, d
40
+ assert_equal c, e
41
+ end
42
+
43
+ def test_mixed
44
+ foo = 1..3
45
+ bar = %w{a b c}
46
+ expected = [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"],
47
+ [2, "c"], [3, "a"], [3, "b"], [3, "c"]]
48
+ assert(foo.x(bar).to_a == expected)
49
+ assert(Cartesian.product(foo,bar) == expected) ##################
50
+ end
51
+
52
+ def test_power
53
+ ary = [1,2,3]
54
+ assert_raise(ArgumentError) { ary**(-1) }
55
+ assert_equal [], ary**0
56
+ assert_equal ary, ary**1
57
+ expected = [[0, 0, 0], [0, 0, 1], [0, 1, 0],\
58
+ [0, 1, 1], [1, 0, 0], [1, 0, 1],\
59
+ [1, 1, 0], [1, 1, 1]]
60
+ assert_equal expected, ([0,1]**3).to_a
61
+ end
62
+
63
+ def test_joined_cartesian
64
+ assert_equal ["1A", "1B", "2A", "2B"], [1,2].joined_cartesian(%w<A B>)
65
+ end
66
+
67
+ end
@@ -0,0 +1,29 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+ require 'cartesian'
3
+
4
+ class TestCartesianIterator < Test::Unit::TestCase
5
+
6
+ def test_equal
7
+ assert_equal [1].x([2]), [1].x([2])
8
+ assert_not_equal [1].x([2]), [1].x([3])
9
+ end
10
+
11
+
12
+ def test_dup
13
+ c = [1,2].x([3,4])
14
+ d = c.dup
15
+ e = d.x([5,6])
16
+ assert_not_equal(e, c)
17
+ assert_equal(c, d)
18
+ end
19
+
20
+ def test_iterator_next_and_restart
21
+ foo = [1,2]
22
+ assert_equal 1, foo.next
23
+ assert_equal 2, foo.next
24
+ assert_equal nil, foo.next
25
+ foo.restart
26
+ assert_equal 1, foo.next
27
+ end
28
+
29
+ end
@@ -0,0 +1,10 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+ require File.join(File.dirname(__FILE__), 'extensions.rb')
3
+
4
+ class TestExtensions < Test::Unit::TestCase
5
+ def test_among?
6
+ assert 1.among?([1,2,3])
7
+ assert ! 7.among?([1,2,3])
8
+ assert (3.0).among?([1,2,3])
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+ require File.join(File.dirname(__FILE__), 'extensions.rb')
3
+
4
+ require 'cartesian/grid_search'
5
+
6
+ class TestCartesian < Test::Unit::TestCase
7
+ def test_argmin
8
+ assert_equal 0, *[-1,0,1].argmin {|x| x**2 }
9
+ assert_equal [0,0], ((-3..3)**2).argmin {|x,y| x**2+y**2 }
10
+ end
11
+
12
+ def test_argmax
13
+ assert_equal 0, *[-2,-1,0].argmax {|x| x**3 }
14
+ values = []
15
+ -3.step(3, 0.25) {|val| values << val }
16
+ x, y = (values**2).argmax {|x,y| x**2+y**2 }
17
+ assert x.among?([-3,3])
18
+ assert y.among?([-3,3])
19
+ end
20
+
21
+ end
@@ -0,0 +1,5 @@
1
+ require 'test/unit'
2
+
3
+ require 'rubygems'
4
+
5
+ $:.unshift(File.join(File.dirname(__FILE__), '../lib/'))
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Dir.chdir(File.dirname(__FILE__))
4
+
5
+ class String
6
+ def same_file?(other)
7
+ File.expand_path(self) == File.expand_path(other)
8
+ end
9
+ end
10
+
11
+ candidates = Dir.glob('test_*.rb')
12
+ to_exclude = [__FILE__, 'test_helper.rb']
13
+
14
+ test_files = candidates.reject {|f| to_exclude.any? {|ex| f.same_file?(ex) } }
15
+
16
+ test_files.each do |tf|
17
+ system "ruby #{tf}"
18
+ end
19
+
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cartesian
3
+ version: !ruby/object:Gem::Version
4
+ hash: 11
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
11
+ platform: ruby
12
+ authors:
13
+ - Adriano Mitre
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-04 00:00:00 -02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: hoe
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 47
30
+ segments:
31
+ - 2
32
+ - 8
33
+ - 0
34
+ version: 2.8.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ description: |-
38
+ Provides methods for the calculation of the cartesian producted between two
39
+ or more enumerable objects. Includes grid search optimization methods.
40
+ It can also be easily and conveniently mixed in into any enumerable class.
41
+ email:
42
+ - adriano.mitre@gmail.com
43
+ executables: []
44
+
45
+ extensions: []
46
+
47
+ extra_rdoc_files:
48
+ - History.txt
49
+ - Manifest.txt
50
+ - PostInstall.txt
51
+ - Wishlist.txt
52
+ files:
53
+ - History.txt
54
+ - Manifest.txt
55
+ - PostInstall.txt
56
+ - README.rdoc
57
+ - Rakefile
58
+ - Wishlist.txt
59
+ - config/hoe.rb
60
+ - config/requirements.rb
61
+ - lib/cartesian.rb
62
+ - lib/cartesian/grid_search.rb
63
+ - lib/cartesian/version.rb
64
+ - lib/cartesian_iterator.rb
65
+ - lib/grid_search.rb
66
+ - lib/recursive.rb
67
+ - script/console
68
+ - script/destroy
69
+ - script/generate
70
+ - test/benchmark.rb
71
+ - test/extensions.rb
72
+ - test/test_cartesian.rb
73
+ - test/test_cartesian_iterator.rb
74
+ - test/test_extensions.rb
75
+ - test/test_grid_search.rb
76
+ - test/test_helper.rb
77
+ - test/test_suite.rb
78
+ has_rdoc: true
79
+ homepage: http://github.com/adrianomitre/cartesian
80
+ licenses: []
81
+
82
+ post_install_message: PostInstall.txt
83
+ rdoc_options:
84
+ - --main
85
+ - README.rdoc
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 3
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ hash: 3
103
+ segments:
104
+ - 0
105
+ version: "0"
106
+ requirements: []
107
+
108
+ rubyforge_project: cartesian
109
+ rubygems_version: 1.3.7
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: Provides methods for the calculation of the cartesian producted between two or more enumerable objects
113
+ test_files:
114
+ - test/test_helper.rb
115
+ - test/test_extensions.rb
116
+ - test/test_suite.rb
117
+ - test/test_cartesian_iterator.rb
118
+ - test/test_cartesian.rb
119
+ - test/test_grid_search.rb