multiarray 0.5.1 → 0.5.2

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.
@@ -0,0 +1,65 @@
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 Composite < Element
21
+
22
+ class << self
23
+
24
+ attr_accessor :element_type
25
+
26
+ attr_accessor :num_elements
27
+
28
+ def memory
29
+ element_type.memory
30
+ end
31
+
32
+ def storage_size
33
+ element_type.storage_size * num_elements
34
+ end
35
+
36
+ def directive
37
+ element_type.directive * num_elements
38
+ end
39
+
40
+ def descriptor( hash )
41
+ unless element_type.nil?
42
+ inspect
43
+ else
44
+ super
45
+ end
46
+ end
47
+
48
+ def basetype
49
+ element_type
50
+ end
51
+
52
+ def typecodes
53
+ [ element_type ] * num_elements
54
+ end
55
+
56
+ def scalar
57
+ element_type
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
@@ -20,6 +20,14 @@ module Hornetseye
20
20
  # Class for representing diagonal injections
21
21
  class Diagonal < Node
22
22
 
23
+ class << self
24
+
25
+ def finalised?
26
+ false
27
+ end
28
+
29
+ end
30
+
23
31
  # Constructor
24
32
  #
25
33
  # @param [Node] value Initial value of injection
@@ -56,7 +56,7 @@ module Hornetseye
56
56
  #
57
57
  # @param [Object] value Initial value for element.
58
58
  def initialize( value = self.class.default )
59
- if Thread.current[ :function ].nil? or value.is_a? GCCValue
59
+ if Thread.current[ :function ].nil?
60
60
  @value = value
61
61
  else
62
62
  @value = GCCValue.new Thread.current[ :function ], value.to_s
@@ -84,8 +84,8 @@ module Hornetseye
84
84
  def dup
85
85
  if Thread.current[ :function ]
86
86
  value = Thread.current[ :function ].variable self.class, 'v'
87
- value.get.store get
88
- value
87
+ value.store get
88
+ self.class.new value
89
89
  else
90
90
  self.class.new get
91
91
  end
@@ -17,31 +17,30 @@
17
17
  # Namespace of Hornetseye computer vision library
18
18
  module Hornetseye
19
19
 
20
- # Class for applying a unary method to scalars and arrays
21
- class UnaryMethod_ < Node
20
+ class ElementWise_ < Node
22
21
 
23
22
  class << self
24
23
 
25
- # Name of module
26
- #
27
- # @return [Module] The module with the method.
28
- attr_accessor :mod
29
-
30
24
  # Name of operation
31
25
  #
32
- # @return [Symbol,String] The name of this operation.
26
+ # @return [Proc] A closure with the operation.
33
27
  attr_accessor :operation
34
28
 
29
+ # Unique key to identify operation.
30
+ #
31
+ # @return [Symbol,String] A unique key to identify this operation.
32
+ attr_accessor :key
33
+
35
34
  # Name of method for type conversion
36
35
  #
37
- # @return [Symbol,String] The name of the method for type conversion.
36
+ # @return [Proc] A closure for doing the type conversion.
38
37
  attr_accessor :conversion
39
38
 
40
39
  # Get string with information about this class
41
40
  #
42
41
  # @return [String] Return string with information about this class.
43
42
  def inspect
44
- "#{mod.to_s}.#{operation.to_s}"
43
+ key.to_s
45
44
  end
46
45
 
47
46
  # Get unique descriptor of this class
@@ -55,13 +54,18 @@ module Hornetseye
55
54
  inspect
56
55
  end
57
56
 
57
+ def finalised?
58
+ false
59
+ end
60
+
58
61
  end
59
62
 
60
63
  # Initialise unary operation
61
64
  #
62
65
  # @param [Node] value Value to apply operation to.
63
- def initialize( value )
64
- @value = value
66
+ def initialize( *values )
67
+ @values = values
68
+ check_shape *values
65
69
  end
66
70
 
67
71
  # Get unique descriptor of this object
@@ -72,7 +76,8 @@ module Hornetseye
72
76
  #
73
77
  # @private
74
78
  def descriptor( hash )
75
- "#{self.class.descriptor( hash )}(#{@value.descriptor( hash )})"
79
+ "#{self.class.descriptor( hash )}" +
80
+ "(#{@values.collect { |value| value.descriptor( hash ) }.join ','})"
76
81
  end
77
82
 
78
83
  # Array type of this term
@@ -81,7 +86,19 @@ module Hornetseye
81
86
  #
82
87
  # @private
83
88
  def array_type
84
- @value.array_type.send self.class.conversion
89
+ array_types = @values.collect { |value| value.array_type }
90
+ self.class.conversion.call *array_types
91
+ end
92
+
93
+ # Reevaluate computation
94
+ #
95
+ # @return [Node,Object] Result of computation
96
+ #
97
+ # @see #force
98
+ #
99
+ # @private
100
+ def demand
101
+ self.class.operation.call *@values
85
102
  end
86
103
 
87
104
  # Substitute variables
@@ -94,7 +111,7 @@ module Hornetseye
94
111
  #
95
112
  # @private
96
113
  def subst( hash )
97
- self.class.new @value.subst( hash )
114
+ self.class.new *@values.collect { |value| value.subst( hash ) }
98
115
  end
99
116
 
100
117
  # Get variables contained in this term
@@ -103,7 +120,7 @@ module Hornetseye
103
120
  #
104
121
  # @private
105
122
  def variables
106
- @value.variables
123
+ @values.inject( Set[] ) { |vars,value| vars + value.variables }
107
124
  end
108
125
 
109
126
  # Strip of all values
@@ -116,23 +133,15 @@ module Hornetseye
116
133
  #
117
134
  # @private
118
135
  def strip
119
- vars, values, term = @value.strip
120
- return vars, values, self.class.new( term )
121
- end
122
-
123
- # Reevaluate computation
124
- #
125
- # @return [Node,Object] Result of computation
126
- #
127
- # @see #force
128
- #
129
- # @private
130
- def demand
131
- self.class.mod.send self.class.operation, @value
136
+ stripped = @values.collect { |value| value.strip }
137
+ return stripped.inject( [] ) { |vars,elem| vars + elem[ 0 ] },
138
+ stripped.inject( [] ) { |values,elem| values + elem[ 1 ] },
139
+ self.class.new( *stripped.collect { |elem| elem[ 2 ] } )
132
140
  end
133
141
 
134
142
  def skip( index, start )
135
- self.class.new( @value.skip( index, start ) ).demand
143
+ skipped = *@values.collect { |value| value.skip( index, start ) }
144
+ self.class.new( *skipped ).demand
136
145
  end
137
146
 
138
147
  # Get element of unary operation
@@ -141,11 +150,22 @@ module Hornetseye
141
150
  #
142
151
  # @return [Node,Object] Element of unary operation.
143
152
  def element( i )
144
- self.class.new( @value.element( i ) ).demand
153
+ values = @values.collect do |value|
154
+ value.dimension == 0 ? value : value.element( i )
155
+ end
156
+ self.class.new( *values ).demand
145
157
  end
146
158
 
147
159
  def slice( start, length )
148
- self.class.new( @value.slice( start, length ) ).demand
160
+ values = @values.collect do |value|
161
+ value.dimension == 0 ? value : value.slice( start, length )
162
+ end
163
+ self.class.new( *values ).demand
164
+ end
165
+
166
+ def decompose
167
+ values = @values.collect { |value| value.decompose }
168
+ self.class.new( *values ).demand
149
169
  end
150
170
 
151
171
  # Check whether this term is compilable
@@ -154,32 +174,34 @@ module Hornetseye
154
174
  #
155
175
  # @private
156
176
  def compilable?
157
- @value.compilable?
177
+ array_type.compilable? and @values.all? { |value| value.compilable? }
158
178
  end
159
179
 
160
180
  end
161
181
 
162
- # Create a class deriving from +UnaryMethod_+
182
+ # Create a class deriving from +ElementWise_+
163
183
  #
164
- # @param [Symbol,String] operation Name of operation.
165
- # @param [Symbol,String] conversion Name of method for type conversion.
184
+ # @param [Proc] operation A closure with the operation to perform.
185
+ # @param [Symbol,String] key A unique descriptor to identify this operation.
186
+ # @param [Proc] conversion A closure for performing the type conversion.
166
187
  #
167
- # @return [Class] A class deriving from +UnaryMethod_+.
188
+ # @return [Class] A class deriving from +ElementWise_+.
168
189
  #
169
- # @see UnaryMethod_
170
- # @see UnaryMethod_.operation
171
- # @see UnaryMethod_.conversion
190
+ # @see ElementWise_
191
+ # @see ElementWise_.operation
192
+ # @see ElementWise_.key
193
+ # @see ElementWise_.conversion
172
194
  #
173
195
  # @private
174
- def UnaryMethod( mod, operation, conversion = :contiguous )
175
- retval = Class.new UnaryMethod_
176
- retval.mod = mod
196
+ def ElementWise( operation, key, conversion = lambda { |t| t.send :contiguous } )
197
+ retval = Class.new ElementWise_
177
198
  retval.operation = operation
199
+ retval.key = key
178
200
  retval.conversion = conversion
179
201
  retval
180
202
  end
181
203
 
182
- module_function :UnaryMethod
204
+ module_function :ElementWise
183
205
 
184
206
  end
185
207
 
@@ -21,25 +21,29 @@ module Hornetseye
21
21
 
22
22
  class << self
23
23
 
24
- def run( block )
24
+ def run( retval, block )
25
25
  keys, values, term = block.strip
26
- labels = Hash[ *keys.zip( ( 0 ... keys.size ).to_a ).flatten ]
27
- retval = block.pointer_type.new
26
+ labels = Hash[ *keys.
27
+ zip( ( 0 ... keys.size ).to_a ).flatten ]
28
28
  retval_keys, retval_values, retval_term = retval.strip
29
- method_name = '_' + term.descriptor( labels ).
30
- tr( '(),+\-*/.@?~&|^<=>',
31
- '0123\456789ABCDEFG' )
29
+ retval_labels = Hash[ *retval_keys.
30
+ zip( ( 0 ... retval_keys.size ).to_a ).flatten ]
31
+ method_name = ( '_' + retval_term.descriptor( retval_labels ) +
32
+ '_' + term.descriptor( labels ) ).
33
+ tr( '(),+\-*/%.@?~&|^<=>',
34
+ '0123\456789ABCDEFGH' )
32
35
  unless GCCCache.respond_to? method_name
33
36
  GCCContext.build do |context|
34
37
  function = new context, method_name,
35
38
  *( retval_keys + keys ).collect { |var| var.meta }
39
+ Thread.current[ :function ] = function
36
40
  term_subst = ( 0 ... keys.size ).collect do |i|
37
41
  { keys[i] => function.param( i + retval_keys.size ) }
38
42
  end.inject( {} ) { |a,b| a.merge b }
39
43
  retval_subst = ( 0 ... retval_keys.size ).collect do |i|
40
44
  { retval_keys[ i ] => function.param( i ) }
41
45
  end.inject( {} ) { |a,b| a.merge b }
42
- Thread.current[ :function ] = function
46
+ # Thread.current[ :function ] = function
43
47
  Hornetseye::lazy do
44
48
  retval_term.subst( retval_subst ).store term.subst( term_subst )
45
49
  end
@@ -76,19 +80,9 @@ module Hornetseye
76
80
  end
77
81
 
78
82
  def variable( typecode, prefix )
79
- #if typecode == INTRGB
80
- # r = GCCValue.new( self, id( prefix ) )
81
- # g = GCCValue.new( self, id( prefix ) )
82
- # b = GCCValue.new( self, id( prefix ) )
83
- # self << "#{indent}#{GCCType.new( INT ).identifier} #{r};\n"
84
- # self << "#{indent}#{GCCType.new( INT ).identifier} #{g};\n"
85
- # self << "#{indent}#{GCCType.new( INT ).identifier} #{b};\n"
86
- # INTRGB.new RGB.new( r, g, b )
87
- #else
88
- retval = typecode.new GCCValue.new( self, id( prefix ) )
89
- self << "#{indent}#{GCCType.new( typecode ).identifiers.first} #{retval.get};\n" # !!!
90
- retval
91
- #end
83
+ retval = GCCValue.new( self, id( prefix ) )
84
+ self << "#{indent}#{GCCType.new( typecode ).identifiers.first} #{retval};\n" # !!!
85
+ retval
92
86
  end
93
87
 
94
88
  def indent
@@ -50,8 +50,8 @@ module Hornetseye
50
50
  [ 'void *' ]
51
51
  elsif @typecode < INDEX_
52
52
  [ 'int' ]
53
- elsif @typecode < RGB_
54
- GCCType.new( @typecode.element_type ).identifiers * 3
53
+ elsif @typecode < Composite
54
+ GCCType.new( @typecode.element_type ).identifiers * @typecode.num_elements
55
55
  else
56
56
  raise "No identifier available for #{@typecode.inspect}"
57
57
  end
@@ -61,16 +61,16 @@ module Hornetseye
61
61
  def r2c
62
62
  case @typecode
63
63
  when BOOL
64
- [ proc { |expr| "( #{expr} ) != Qfalse" } ]
64
+ [ lambda { |expr| "( #{expr} ) != Qfalse" } ]
65
65
  when BYTE, UBYTE, SINT, USINT, INT, UINT
66
- [ proc { |expr| "NUM2INT( #{expr} )" } ]
66
+ [ lambda { |expr| "NUM2INT( #{expr} )" } ]
67
67
  when SFLOAT, DFLOAT
68
- [ proc { |expr| "NUM2DBL( #{expr} )" } ]
68
+ [ lambda { |expr| "NUM2DBL( #{expr} )" } ]
69
69
  else
70
70
  if @typecode < Pointer_
71
- [ proc { |expr| "(#{identifiers.first})mallocToPtr( #{expr} )" } ] # !!!
72
- elsif @typecode < RGB_
73
- GCCType.new( @typecode.element_type ).r2c * 3
71
+ [ lambda { |expr| "(#{identifiers.first})mallocToPtr( #{expr} )" } ] # !!!
72
+ elsif @typecode < Composite
73
+ GCCType.new( @typecode.element_type ).r2c * @typecode.num_elements
74
74
  else
75
75
  raise "No conversion available for #{@typecode.inspect}"
76
76
  end
@@ -62,7 +62,8 @@ module Hornetseye
62
62
  mod.module_eval do
63
63
  define_method( "#{op}_with_gcc" ) do |a,b|
64
64
  if a.is_a? GCCValue or b.is_a? GCCValue
65
- GCCValue.new a.function, "#{opcode}( #{a}, #{b} )"
65
+ function = a.is_a?( GCCValue ) ? a.function : b.function
66
+ GCCValue.new function, "#{opcode}( #{a}, #{b} )"
66
67
  else
67
68
  send "#{op}_without_gcc", a, b
68
69
  end
@@ -117,6 +118,18 @@ module Hornetseye
117
118
  end
118
119
  end
119
120
 
121
+ def conj
122
+ self
123
+ end
124
+
125
+ def abs
126
+ ( self >= 0 ).conditional self, -self
127
+ end
128
+
129
+ def arg
130
+ ( self >= 0 ).conditional 0, Math::PI
131
+ end
132
+
120
133
  def r
121
134
  self
122
135
  end
@@ -129,6 +142,14 @@ module Hornetseye
129
142
  self
130
143
  end
131
144
 
145
+ def real
146
+ self
147
+ end
148
+
149
+ def imag
150
+ 0
151
+ end
152
+
132
153
  def conditional( a, b )
133
154
  GCCValue.new @function, "( #{self} ) ? ( #{a} ) : ( #{b} )"
134
155
  end
@@ -147,6 +168,7 @@ module Hornetseye
147
168
  define_binary_op :-
148
169
  define_binary_op :*
149
170
  define_binary_op :/
171
+ define_binary_op :%
150
172
  define_binary_op :eq, :==
151
173
  define_binary_op :ne, '!='
152
174
  define_binary_op :<
@@ -168,6 +190,34 @@ module Hornetseye
168
190
  define_binary_method Math, :atan2
169
191
  define_binary_method Math, :hypot
170
192
 
193
+ def zero?
194
+ GCCValue.new @function, "( #{self} ) == 0"
195
+ end
196
+
197
+ def nonzero?
198
+ GCCValue.new @function, "( #{self} ) != 0"
199
+ end
200
+
201
+ def floor
202
+ GCCValue.new @function, "floor( #{self} )"
203
+ end
204
+
205
+ def ceil
206
+ GCCValue.new @function, "ceil( #{self} )"
207
+ end
208
+
209
+ def round
210
+ GCCValue.new @function, "round( #{self} )"
211
+ end
212
+
213
+ def **( other )
214
+ if GCCValue.generic? other
215
+ GCCValue.new @function, "pow( #{self}, #{other} )"
216
+ else
217
+ x, y = other.coerce self
218
+ x ** y
219
+ end
220
+ end
171
221
 
172
222
  def major( other )
173
223
  GCCValue.new @function,
@@ -179,20 +229,12 @@ module Hornetseye
179
229
  "( ( #{self} ) <= ( #{other} ) ) ? ( #{self} ) : ( #{other} )"
180
230
  end
181
231
 
182
- def zero?
183
- GCCValue.new @function, "( #{self} ) == 0"
184
- end
185
-
186
- def nonzero?
187
- GCCValue.new @function, "( #{self} ) != 0"
188
- end
189
-
190
232
  def times( &action )
191
233
  i = @function.variable INT, 'i'
192
- @function << "#{@function.indent}for ( #{i.get} = 0; " +
193
- "#{i.get} != #{self}; #{i.get}++ ) {\n"
234
+ @function << "#{@function.indent}for ( #{i} = 0; " +
235
+ "#{i} != #{self}; #{i}++ ) {\n"
194
236
  @function.indent_offset +1
195
- action.call i.get
237
+ action.call i
196
238
  @function.indent_offset -1
197
239
  @function << "#{@function.indent}};\n"
198
240
  self
@@ -200,10 +242,10 @@ module Hornetseye
200
242
 
201
243
  def upto( other, &action )
202
244
  i = @function.variable INT, 'i'
203
- @function << "#{@function.indent}for ( #{i.get} = #{self}; " +
204
- "#{i.get} != #{ other + 1 }; #{i.get}++ ) {\n"
245
+ @function << "#{@function.indent}for ( #{i} = #{self}; " +
246
+ "#{i} != #{ other + 1 }; #{i}++ ) {\n"
205
247
  @function.indent_offset +1
206
- action.call i.get
248
+ action.call i
207
249
  @function.indent_offset -1
208
250
  @function << "#{@function.indent}};\n"
209
251
  self