multiarray 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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