multiarray 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -6,12 +6,14 @@ require 'rake/packagetask'
6
6
  require 'rbconfig'
7
7
 
8
8
  PKG_NAME = 'multiarray'
9
- PKG_VERSION = '0.5.0'
9
+ PKG_VERSION = '0.5.1'
10
10
  RB_FILES = FileList[ 'lib/**/*.rb' ]
11
11
  TC_FILES = FileList[ 'test/tc_*.rb' ]
12
12
  TS_FILES = FileList[ 'test/ts_*.rb' ]
13
13
  PKG_FILES = [ 'Rakefile', 'README.md', 'COPYING', 'TODO', '.document' ] +
14
14
  RB_FILES + TS_FILES + TC_FILES
15
+ BIN_FILES = [ 'README.md', 'COPYING', '.document' ] +
16
+ RB_FILES + TS_FILES + TC_FILES
15
17
  SUMMARY = %q{Multi-dimensional and uniform Ruby arrays}
16
18
  DESCRIPTION = %q{This Ruby-extension defines Hornetseye::MultiArray and other native datatypes. Hornetseye::MultiArray provides multi-dimensional Ruby arrays with elements of same type. The extension is designed to be mostly compatible with Masahiro Tanaka's NArray. However it allows the definition of custom element types and operations on them. This work was also inspired by Ronald Garcia's boost::multi_array and by Todd Veldhuizen's Blitz++.}
17
19
  AUTHOR = %q{Jan Wedekind}
@@ -88,16 +90,48 @@ begin
88
90
  s.add_development_dependency %q{rake}
89
91
  end
90
92
  GEM_SOURCE = "#{PKG_NAME}-#{PKG_VERSION}.gem"
93
+ $BINSPEC = Gem::Specification.new do |s|
94
+ s.name = PKG_NAME
95
+ s.version = PKG_VERSION
96
+ s.platform = Gem::Platform::CURRENT
97
+ s.date = Date.today.to_s
98
+ s.summary = SUMMARY
99
+ s.description = DESCRIPTION
100
+ s.author = AUTHOR
101
+ s.email = EMAIL
102
+ s.homepage = HOMEPAGE
103
+ s.files = BIN_FILES
104
+ s.test_files = TC_FILES
105
+ s.require_paths = [ 'lib' ]
106
+ s.rubyforge_project = %q{hornetseye}
107
+ s.has_rdoc = 'yard'
108
+ s.extra_rdoc_files = []
109
+ s.rdoc_options = %w{--no-private}
110
+ s.add_dependency %q<malloc>, [ '~> 1.0' ]
111
+ end
112
+ GEM_BINARY = "#{PKG_NAME}-#{PKG_VERSION}-#{$BINSPEC.platform}.gem"
91
113
  desc "Build the gem file #{GEM_SOURCE}"
92
114
  task :gem => [ "pkg/#{GEM_SOURCE}" ]
93
115
  file "pkg/#{GEM_SOURCE}" => [ 'pkg' ] + $SPEC.files do
94
- Gem::Builder.new( $SPEC ).build
95
- verbose true do
96
- FileUtils.mv GEM_SOURCE, "pkg/#{GEM_SOURCE}"
116
+ when_writing 'Creating GEM' do
117
+ Gem::Builder.new( $SPEC ).build
118
+ verbose true do
119
+ FileUtils.mv GEM_SOURCE, "pkg/#{GEM_SOURCE}"
120
+ end
121
+ end
122
+ end
123
+ desc "Build the gem file #{GEM_BINARY}"
124
+ task :gem_binary => [ "pkg/#{GEM_BINARY}" ]
125
+ file "pkg/#{GEM_BINARY}" => [ 'pkg' ] + $BINSPEC.files do
126
+ when_writing 'Creating binary GEM' do
127
+ Gem::Builder.new( $BINSPEC ).build
128
+ verbose true do
129
+ FileUtils.mv GEM_BINARY, "pkg/#{GEM_BINARY}"
130
+ end
97
131
  end
98
132
  end
99
133
  rescue LoadError
100
134
  STDERR.puts 'Please install \'rubygems\' if you want to create Gem packages'
101
135
  end
102
136
 
103
- CLOBBER.include 'doc'
137
+ CLOBBER.include 'doc', '.yardoc'
data/TODO CHANGED
@@ -1,25 +1,22 @@
1
- # test for multiarray-indgen
2
- # accept ranges for element access
3
- # compile Convolve#demand
4
- # inject without initial is [ 1 .. -1 ].inject with [ 0 ] as initial value
5
- # Composite numbers?
6
- # pointer-increments for better efficiency
7
- # How does contiguous work here? typecasts?
8
- # separate secondary operations like equality
9
- # preload cache
10
- # Sequence( UBYTE, 3 )[ ... ]
1
+ # type alignment for operators and methods, Math.sqrt( SFLOAT )
2
+ # test floor, ceil, ..., factor out common stuff of UnaryOp and UnaryMethod
3
+ # complex numbers, factor out composite numbers
4
+ # Fast filling of arrays, duplication, type conversions
5
+ # use descriptors ('c','f',...)?
6
+ # pointer-increments for better efficiency, optimize Node#diagonal
7
+ # implement typecasts, how does contiguous work here?
8
+ # documentation!
11
9
 
12
10
  # histogram (implement using injection)
13
- # inject: min, max, equal, n-d clips for warp
11
+ # inject: n-d clips for warp
14
12
  # block(var1,var2,...) with smart subst?
15
- # lazy( 5 ) { |i| 0 } # but lazy { 0 }
16
- # lazy( 3, 2 ) { |i,j| i }
17
13
  # lazy( 3, 2 ) { |i,j| j.to_object }
18
14
 
19
15
  # RSpec
20
16
 
21
17
  # downsampling after correlation?
22
- # README.rdoc, YARD documentation with pictures, demo video
18
+ # YARD documentation with pictures, demo video
19
+ # CK_Thesis.pdf: tensor voting
23
20
 
24
21
  # f(g(i)) # g(i), f(g(i)) all can be vectors and all can be lazy
25
22
  # lut(g(i))
@@ -44,9 +41,6 @@
44
41
  # binary operations, equality: ( a == b ).inject( true ) { |e,b| e && b }
45
42
  # inject: min, max, equal, n-d clips for warp
46
43
  # block(var1,var2,...) with smart subst?
47
- # lazy( 5 ) { |i| 0 }
48
- # lazy( 3, 2 ) { |i,j| i }
49
- # lazy( 3, 2 ) { |i,j| j }
50
44
 
51
45
  # downsampling after correlation?
52
46
  # ruby -Ilib -rrubygems -rmultiarray -rtest test/tc_sequence.rb
@@ -61,45 +55,12 @@
61
55
  # end
62
56
  #end
63
57
 
64
-
65
- lazy { a * b } -> lazy { |i,j| lazy { |i,j| a[i,j] * b[i,j] }[i,j] } # ?
66
- lazy { s } -> s
67
- lazy { -s } -> lazy { |i| -s[i] }
68
- lazy { |i,j| s[i,j] }
69
- lazy { |i| lazy { |j| s[i,j] } }
70
- lazy( n ) { |i| i }
71
- lazy( n, m ) { |i,j| i + j }
72
- lazy( n ) { |i| lazy( m ) { |j| i + j } }
73
- eager( n ) { |i| i }
74
- ...
75
-
76
- tensor indices to enable transpose of lazy array
77
58
  ranges (rolling, lazy rolling, lazy ranges)
78
- test lazyness
79
- sums/injections (equality for arrays)? nesting? tensors?
80
- JIT?
81
59
  test type conversions
82
- fancy README
83
60
 
84
- a = lazy( 16 ) { |i| i }
85
- a = lazy( 16 ) { |i| i }[ 4 ... 12 ] # offsets: apply sel-operation to all
86
- members; index array?
87
61
  a = lazy( 16, 32 ) { |i,j| Sequence[ i, j ] } # ???
88
62
  a = lazy( 8, 8 ) { |i,j| Sequence[ i, a[j] * sin( i + b[j] ) ] }.hist 8, 8
89
- a = b.class.new.op { |x| set -x }
90
- a = lazy { |i| -b[i] }
91
- a = lazy { -b }
92
- a = array { -b }
93
- a = array { |i| -b[i] }
94
- a = array( :dim => [ b.size ] ) { |i| -b[i] }
95
- a = -b
96
- array { |i| sum { |j| a[i,j] } }
97
- lazy { |i| sum { |j| a[i,j] } }
98
63
  parallel { ... }
99
- lazy { |i| lazy { |j| a[i,j] } }
100
- array { lazy { |i| sum { |j| a[i,j] } } }
101
-
102
- correlate?
103
64
 
104
65
  lines:
105
66
  [ i, a[j] * sin( i + b[j] ) ].hist
@@ -122,19 +83,3 @@ Lazy( Sequence( INT, 3 ) )
122
83
 
123
84
  interpretation: type coercion, actual operation, jit,
124
85
  collection of jit arguments (e.g. tensor)
125
-
126
- proc { |i| proc { |j| i+j } }.call( 5 ).call 3
127
-
128
- gem install flay: http://ruby.sadi.st/Flay.html
129
-
130
- # donate to yardoc
131
-
132
- How to nest/cascade mode-environments?
133
- (how to specify nested modes for recursive algorithms and called algorithms?)
134
- ruby and jit compiles, lazy and parallel forwards
135
-
136
- * Ruby
137
- * Lazy (Lazy histogram -> hough transform, lazy transpose, unused indices?)
138
- * Multithreading
139
- * JIT
140
- * GCC
data/lib/multiarray.rb CHANGED
@@ -375,36 +375,36 @@ end
375
375
  # +Range+ is extended with a few methods
376
376
  class Range
377
377
 
378
- alias_method :orig_min, :min
379
-
380
- alias_method :orig_max, :max
381
-
382
378
  # For performance reasons a specialised method for integers is added
383
379
  #
384
380
  # @return [Object] Minimum value of range.
385
381
  #
386
382
  # @private
387
- def min
383
+ def min_with_hornetseye
388
384
  if self.begin.is_a? Integer
389
385
  self.begin
390
386
  else
391
- orig_min
387
+ min_without_hornetseye
392
388
  end
393
389
  end
394
390
 
391
+ alias_method_chain :min, :hornetseye
392
+
395
393
  # For performance reasons a specialised method for integers is added
396
394
  #
397
395
  # @return [Object] Maximum value of range.
398
396
  #
399
397
  # @private
400
- def max
398
+ def max_with_hornetseye
401
399
  if self.end.is_a? Integer
402
400
  exclude_end? ? self.end - 1 : self.end
403
401
  else
404
- orig_max
402
+ max_without_hornetseye
405
403
  end
406
404
  end
407
405
 
406
+ alias_method_chain :max, :hornetseye
407
+
408
408
  # Compute the size of a range
409
409
  #
410
410
  # @return [Integer] Number of discrete values within range.
@@ -414,6 +414,48 @@ class Range
414
414
 
415
415
  end
416
416
 
417
+ class Numeric
418
+
419
+ def r
420
+ self
421
+ end
422
+
423
+ def g
424
+ self
425
+ end
426
+
427
+ def b
428
+ self
429
+ end
430
+
431
+ def major( other )
432
+ if other.is_a? Numeric
433
+ ( self >= other ).conditional self, other
434
+ else
435
+ x, y = other.coerce self
436
+ x.major other
437
+ end
438
+ end
439
+
440
+ def minor( other )
441
+ if other.is_a? Numeric
442
+ ( self <= other ).conditional self, other
443
+ else
444
+ x, y = other.coerce self
445
+ x.minor other
446
+ end
447
+ end
448
+
449
+ end
450
+
451
+ class Array
452
+
453
+ def collect_with_index( &action )
454
+ zip( ( 0 ... size ).to_a ).collect &action
455
+ end
456
+
457
+ end
458
+
417
459
  require 'malloc'
418
460
  require 'rbconfig'
419
461
  require 'set'
@@ -426,13 +468,18 @@ require 'multiarray/object'
426
468
  require 'multiarray/index'
427
469
  require 'multiarray/bool'
428
470
  require 'multiarray/int'
471
+ require 'multiarray/float'
472
+ require 'multiarray/rgb'
429
473
  require 'multiarray/pointer'
430
474
  require 'multiarray/variable'
431
475
  require 'multiarray/lambda'
432
476
  require 'multiarray/lookup'
433
- require 'multiarray/unary'
434
- require 'multiarray/binary'
477
+ require 'multiarray/unaryop'
478
+ require 'multiarray/unarymethod'
479
+ require 'multiarray/binaryop'
480
+ require 'multiarray/binarymethod'
435
481
  require 'multiarray/operations'
482
+ require 'multiarray/methods'
436
483
  require 'multiarray/inject'
437
484
  require 'multiarray/diagonal'
438
485
  require 'multiarray/sequence'
@@ -458,7 +505,7 @@ module Hornetseye
458
505
  Thread.current[ :lazy ] = true
459
506
  begin
460
507
  options = shape.last.is_a?( Hash ) ? shape.pop : {}
461
- arity = options[ :arity ] || action.arity
508
+ arity = options[ :arity ] || [ action.arity, shape.size ].max
462
509
  if arity <= 0
463
510
  action.call
464
511
  else
@@ -506,7 +553,7 @@ module Hornetseye
506
553
  # @return [Object,Node] Sum of values.
507
554
  def sum( *shape, &action )
508
555
  options = shape.last.is_a?( Hash ) ? shape.pop : {}
509
- arity = options[ :arity ] || action.arity
556
+ arity = options[ :arity ] || [ action.arity, shape.size ].max
510
557
  if arity <= 0
511
558
  action.call
512
559
  else
@@ -0,0 +1,195 @@
1
+ # multiarray - Lazy multi-dimensional arrays for Ruby
2
+ # Copyright (C) 2010 Jan Wedekind
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ # Namespace of Hornetseye computer vision library
18
+ module Hornetseye
19
+
20
+ # Class for representing binary operations on scalars and arrays
21
+ class BinaryMethod_ < Node
22
+
23
+ class << self
24
+
25
+ # Name of module
26
+ #
27
+ # @return [Module] The module with the method.
28
+ attr_accessor :mod
29
+
30
+ # Name of operation
31
+ #
32
+ # @return [Symbol,String] The name of this operation.
33
+ attr_accessor :operation
34
+
35
+ # Name of method for type conversion
36
+ #
37
+ # @return [Symbol,String] The name of the method for type conversion.
38
+ attr_accessor :coercion
39
+
40
+ # Get string with information about this class
41
+ #
42
+ # @return [String] Return string with information about this class.
43
+ def inspect
44
+ "#{mod.to_s}.#{operation.to_s}"
45
+ end
46
+
47
+ # Get unique descriptor of this class
48
+ #
49
+ # @param [Hash] hash Labels for any variables.
50
+ #
51
+ # @return [String] Descriptor of this class.
52
+ #
53
+ # @private
54
+ def descriptor( hash )
55
+ inspect
56
+ end
57
+
58
+ end
59
+
60
+ # Initialise binary operation
61
+ #
62
+ # @param [Node] value1 First operand to apply operation to.
63
+ # @param [Node] value2 Second operand to apply operation to.
64
+ def initialize( value1, value2 )
65
+ @value1, @value2 = value1, value2
66
+ end
67
+
68
+ # Get unique descriptor of this object
69
+ #
70
+ # @param [Hash] hash Labels for any variables.
71
+ #
72
+ # @return [String] Descriptor of this object,
73
+ #
74
+ # @private
75
+ def descriptor( hash )
76
+ "#{self.class.descriptor( hash )}(#{@value1.descriptor( hash )})," +
77
+ "(#{@value2.descriptor( hash )})"
78
+ end
79
+
80
+ # Array type of this term
81
+ #
82
+ # @return [Class] Resulting array type.
83
+ #
84
+ # @private
85
+ def array_type
86
+ @value1.array_type.send self.class.coercion, @value2.array_type
87
+ end
88
+
89
+ # Substitute variables
90
+ #
91
+ # Substitute the variables with the values given in the hash.
92
+ #
93
+ # @param [Hash] hash Substitutions to apply.
94
+ #
95
+ # @return [Node] Term with substitutions applied.
96
+ #
97
+ # @private
98
+ def subst( hash )
99
+ self.class.new @value1.subst( hash ), @value2.subst( hash )
100
+ end
101
+
102
+ # Get variables contained in this term
103
+ #
104
+ # @return [Set] Returns set of variables.
105
+ #
106
+ # @private
107
+ def variables
108
+ @value1.variables + @value2.variables
109
+ end
110
+
111
+ # Strip of all values
112
+ #
113
+ # Split up into variables, values, and a term where all values have been
114
+ # replaced with variables.
115
+ #
116
+ # @return [Array<Array,Node>] Returns an array of variables, an array of
117
+ # values, and the term based on variables.
118
+ #
119
+ # @private
120
+ def strip
121
+ vars1, values1, term1 = @value1.strip
122
+ vars2, values2, term2 = @value2.strip
123
+ return vars1 + vars2, values1 + values2, self.class.new( term1, term2 )
124
+ end
125
+
126
+ # Reevaluate computation
127
+ #
128
+ # @return [Node,Object] Result of computation
129
+ #
130
+ # @see #force
131
+ #
132
+ # @private
133
+ def demand
134
+ self.class.mod.send self.class.operation, @value1, @value2
135
+ end
136
+
137
+ def skip( index, start )
138
+ element1 = @value1.skip( index, start )
139
+ element2 = @value2.skip( index, start )
140
+ self.class.new( element1, element2 ).demand
141
+ end
142
+
143
+ # Get element of unary operation
144
+ #
145
+ # @param [Integer,Node] i Index of desired element.
146
+ #
147
+ # @return [Node,Object] Element of unary operation.
148
+ def element( i )
149
+ element1 = @value1.dimension == 0 ? @value1 : @value1.element( i )
150
+ element2 = @value2.dimension == 0 ? @value2 : @value2.element( i )
151
+ self.class.new( element1, element2 ).demand
152
+ end
153
+
154
+ def slice( start, length )
155
+ element1 = @value1.dimension == 0 ? @value1 :
156
+ @value1.slice( start, length )
157
+ element2 = @value2.dimension == 0 ? @value2 :
158
+ @value2.slice( start, length )
159
+ self.class.new( element1, element2 ).demand
160
+ end
161
+
162
+ # Check whether this term is compilable
163
+ #
164
+ # @return [FalseClass,TrueClass] Returns whether this term is compilable.
165
+ #
166
+ # @private
167
+ def compilable?
168
+ @value1.compilable? and @value2.compilable?
169
+ end
170
+
171
+ end
172
+
173
+ # Create a class deriving from +BinaryMethod_+
174
+ #
175
+ # @param [Symbol,String] operation Name of operation.
176
+ # @param [Symbol,String] conversion Name of method for type conversion.
177
+ #
178
+ # @return [Class] A class deriving from +BinaryMethod_+.
179
+ #
180
+ # @see BinaryMethod_
181
+ # @see BinaryMethod_.operation
182
+ # @see BinaryMethod_.coercion
183
+ #
184
+ # @private
185
+ def BinaryMethod( mod, operation, coercion = :coercion )
186
+ retval = Class.new BinaryMethod_
187
+ retval.mod = mod
188
+ retval.operation = operation
189
+ retval.coercion = coercion
190
+ retval
191
+ end
192
+
193
+ module_function :BinaryMethod
194
+
195
+ end