multiarray 0.4.1 → 0.5.0

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,100 @@
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 Lambda < Node
21
+
22
+ def initialize( index, term )
23
+ @index = index
24
+ @term = term
25
+ end
26
+
27
+ # Get unique descriptor of this object
28
+ #
29
+ # @param [Hash] hash Labels for any variables.
30
+ #
31
+ # @return [String] Descriptor of this object,
32
+ #
33
+ # @private
34
+ def descriptor( hash )
35
+ hash = hash.merge @index => ( ( hash.values.max || 0 ) + 1 )
36
+ "Lambda(#{@index.descriptor( hash )},#{@term.descriptor( hash )})"
37
+ end
38
+
39
+ def array_type
40
+ Hornetseye::Sequence @term.array_type, @index.size.get
41
+ end
42
+
43
+ def variables
44
+ @term.variables - @index.variables + @index.meta.variables
45
+ end
46
+
47
+ # Strip of all values
48
+ #
49
+ # Split up into variables, values, and a term where all values have been
50
+ # replaced with variables.
51
+ #
52
+ # @return [Array<Array,Node>] Returns an array of variables, an array of
53
+ # values, and the term based on variables.
54
+ #
55
+ # @private
56
+ def strip
57
+ meta_vars, meta_values, var = @index.strip
58
+ vars, values, term = @term.subst( @index => var ).strip
59
+ return vars + meta_vars, values + meta_values,
60
+ Lambda.new( var, term.subst( @index => var ) )
61
+ end
62
+
63
+ def subst( hash )
64
+ subst_var = @index.subst hash
65
+ Lambda.new subst_var, @term.subst( @index => subst_var ).subst( hash )
66
+ end
67
+
68
+ def store( value )
69
+ shape.last.times do |i|
70
+ node = value.dimension == 0 ? value : value.element( INT.new( i ) )
71
+ element( INT.new( i ) ).store node
72
+ end
73
+ value
74
+ end
75
+
76
+ # Lookup element of an array
77
+ #
78
+ # @param [Node] value Index of element.
79
+ # @param [Node] stride Stride for iterating over elements.
80
+ #
81
+ # @return [Lookup,Lambda] Result of lookup.
82
+ #
83
+ # @private
84
+ def lookup( value, stride )
85
+ if value.is_a? Variable
86
+ Lookup.new self, value, stride
87
+ else
88
+ Lambda.new @index, @term.lookup( value, stride )
89
+ end
90
+ end
91
+
92
+ def element( i )
93
+ i = Node.match( i ).new i unless i.is_a? Node
94
+ i.size.store @index.size if @index.size.get and i.is_a? Variable
95
+ @term.subst @index => i
96
+ end
97
+
98
+ end
99
+
100
+ end
@@ -1,71 +1,48 @@
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
1
18
  module Hornetseye
2
-
3
- # Class for creating views on Ruby arrays
4
- #
5
- # @private
19
+
6
20
  class List
7
21
 
8
- # Create view on a Ruby array
9
- #
10
- # @param [Integer] n Number of elements of the view.
11
- # @option options [Array<Object>] :array ([nil] * n) The Ruby array.
12
- # @option options [Integer] :offset (0) Offset of the view.
13
- #
14
- # @private
15
22
  def initialize( n, options = {} )
16
23
  @array = options[ :array ] || [ nil ] * n
17
24
  @offset = options[ :offset ] || 0
18
25
  end
19
26
 
20
- # Display information about this object
21
- #
22
- # @return [String] A string with information about the size of this view.
23
27
  def inspect
24
28
  "List(#{@array.size - @offset})"
25
29
  end
26
30
 
27
- # Retrieve and map element from the array
28
- #
29
- # @param [Class] type Native data type to create
30
- # @return [Type] The mapped element.
31
- def fetch( type )
32
- type.new read
31
+ def to_s
32
+ "List(#{@array[ @offset .. -1 ]})"
33
33
  end
34
34
 
35
- # Retrieve an element from the array
36
- #
37
- # @return [Object] The element from the array.
38
- #
39
- # @see #write
40
- # @see Malloc#read
41
- #
42
- # @private
43
- def read
44
- @array[ @offset ]
35
+ def +( offset )
36
+ List.new 0, :array => @array, :offset => @offset + offset
45
37
  end
46
38
 
47
- # Store an element in the array
48
- #
49
- # @param [Object] value The Ruby object to store.
50
- # @return [Object] Returns the parameter +value+.
51
- #
52
- # @see #read
53
- # @see Malloc#write
54
- #
55
- # @private
56
- def write( value )
57
- @array[ @offset ] = value
39
+ def load( typecode )
40
+ @array[ @offset ]
58
41
  end
59
42
 
60
- # Create a new view with the specified offset
61
- #
62
- # @param [Integer] offset A non-negative offset.
63
- # @return [List] A new view for the specified part of the array.
64
- #
65
- # @see Malloc#+
66
- # @private
67
- def +( offset )
68
- List.new 0, :array => @array, :offset => @offset + offset
43
+ def save( value )
44
+ @array[ @offset ] = value.get
45
+ value
69
46
  end
70
47
 
71
48
  end
@@ -0,0 +1,85 @@
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 Lookup < Node
21
+
22
+ def initialize( p, index, stride )
23
+ @p, @index, @stride = p, index, stride
24
+ end
25
+
26
+ # Get unique descriptor of this object
27
+ #
28
+ # @param [Hash] hash Labels for any variables.
29
+ #
30
+ # @return [String] Descriptor of this object,
31
+ #
32
+ # @private
33
+ def descriptor( hash )
34
+ "Lookup(#{@p.descriptor( hash )},#{@index.descriptor( hash )},#{@stride.descriptor( hash )})"
35
+ end
36
+
37
+ def array_type
38
+ @p.array_type
39
+ end
40
+
41
+ def subst( hash )
42
+ @p.subst( hash ).lookup @index.subst( hash ), @stride.subst( hash )
43
+ end
44
+
45
+ def variables
46
+ @p.variables + @index.variables + @stride.variables
47
+ end
48
+
49
+ # Strip of all values
50
+ #
51
+ # Split up into variables, values, and a term where all values have been
52
+ # replaced with variables.
53
+ #
54
+ # @return [Array<Array,Node>] Returns an array of variables, an array of
55
+ # values, and the term based on variables.
56
+ #
57
+ # @private
58
+ def strip
59
+ vars1, values1, term1 = @p.strip
60
+ vars2, values2, term2 = @stride.strip
61
+ return vars1 + vars2, values1 + values2,
62
+ Lookup.new( term1, @index, term2 )
63
+ end
64
+
65
+ # Lookup element of an array
66
+ #
67
+ # @param [Node] value Index of element.
68
+ # @param [Node] stride Stride for iterating over elements.
69
+ #
70
+ # @private
71
+ def lookup( value, stride )
72
+ if value.is_a? Variable
73
+ Lookup.new self, value, stride
74
+ else
75
+ Lookup.new @p.lookup( value, stride ), @index, @stride
76
+ end
77
+ end
78
+
79
+ def element( i )
80
+ Lookup.new @p.element( i ), @index, @stride
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -1,9 +1,35 @@
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
1
18
  module Hornetseye
2
19
 
3
20
  class Malloc
4
21
 
5
- def fetch( type )
6
- type.import read( type.storage_size )
22
+ def load( typecode )
23
+ read( typecode.storage_size ).unpack( typecode.directive ).first
24
+ end
25
+
26
+ def save( value )
27
+ write [ value.get ].pack( value.typecode.directive )
28
+ value
29
+ end
30
+
31
+ def to_s
32
+ inspect
7
33
  end
8
34
 
9
35
  end
@@ -1,29 +1,54 @@
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
1
18
  module Hornetseye
2
19
 
3
20
  class MultiArray
4
21
 
5
22
  class << self
6
23
 
7
- # Create a multi-dimensional array
8
- #
9
- # Creates a multi-dimensional array with elements of type
10
- # +element_type+ and dimensions +*shape+.
11
- #
12
- # @param [Class] element_type Element type of the array. Should derive
13
- # from +Type+.
14
- # @param [Array<Integer>] *shape The dimensions of the array.
15
- # @return [Type,Sequence_] An array with the specified element type and
16
- # the specified dimensions.
17
- #
18
- # @see #MultiArray
19
- # @see Sequence.new
20
- def new( element_type, *shape )
21
- Hornetseye::MultiArray( element_type, *shape ).new
24
+ def new( typecode, *shape )
25
+ options = shape.last.is_a?( Hash ) ? shape.pop : {}
26
+ count = options[ :count ] || 1
27
+ if shape.empty?
28
+ memory = typecode.memory.new typecode.storage_size * count
29
+ Hornetseye::Pointer( typecode ).new memory
30
+ else
31
+ size = shape.pop
32
+ stride = shape.inject( 1 ) { |a,b| a * b }
33
+ Hornetseye::lazy( size ) do |index|
34
+ pointer = new typecode, *( shape + [ :count => count * size ] )
35
+ Lookup.new pointer, index, INT.new( stride )
36
+ end
37
+ end
22
38
  end
23
39
 
24
40
  def []( *args )
25
- retval = Type.fit( args ).new
26
- retval[] = args
41
+ retval = Node.fit( args ).new
42
+ recursion = proc do |element,args|
43
+ if element.dimension > 0
44
+ args.each_with_index do |arg,i|
45
+ recursion.call element.element( i ), arg
46
+ end
47
+ else
48
+ element[] = args
49
+ end
50
+ end
51
+ recursion.call retval, args
27
52
  retval
28
53
  end
29
54
 
@@ -31,23 +56,12 @@ module Hornetseye
31
56
 
32
57
  end
33
58
 
34
- # Create a multi-dimensional array class
35
- #
36
- # Creates a multi-dimensional array class with elements of type
37
- # +element_type+ and dimensions +*shape+.
38
- #
39
- # @param [Class] element_type Element type of the array type. Should derive
40
- # from +Type+.
41
- # @param [Array<Integer>] *shape The dimensions of the array type.
42
- # @return [Class] A class deriving from +Pointer_+.
43
- #
44
- # @see MultiArray.new
45
- # @see #Sequence
46
59
  def MultiArray( element_type, *shape )
47
60
  if shape.empty?
48
61
  element_type
49
62
  else
50
- MultiArray Sequence( element_type, shape.first ), *shape[ 1 .. -1 ]
63
+ Hornetseye::Sequence MultiArray( element_type, *shape[ 0 ... -1 ] ),
64
+ shape.last
51
65
  end
52
66
  end
53
67
 
@@ -0,0 +1,596 @@
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
+ # Base class for representing native datatypes and operations (terms)
21
+ class Node
22
+
23
+ class << self
24
+
25
+ # Get string with information about this class
26
+ #
27
+ # @return [String] Returns +'Node'+.
28
+ def inspect
29
+ 'Node'
30
+ end
31
+
32
+ # Get unique descriptor of this class
33
+ #
34
+ # The method calls +descriptor( {} )+.
35
+ #
36
+ # @return [String] Descriptor of this class.
37
+ #
38
+ # @see #descriptor
39
+ #
40
+ # @private
41
+ def to_s
42
+ descriptor( {} )
43
+ end
44
+
45
+ # Get unique descriptor of this class
46
+ #
47
+ # @param [Hash] hash Labels for any variables.
48
+ #
49
+ # @return [String] Descriptor of this class.
50
+ #
51
+ # @private
52
+ def descriptor( hash )
53
+ 'Node'
54
+ end
55
+
56
+ # Find matching native datatype to a Ruby value
57
+ #
58
+ # @param [Object] value Value to find native datatype for.
59
+ #
60
+ # @return [Class] Matching native datatype.
61
+ #
62
+ # @private
63
+ def match( value, context = nil )
64
+ retval = fit value
65
+ retval = retval.align context if context
66
+ retval
67
+ end
68
+
69
+ # Align this native datatype with another
70
+ #
71
+ # @param [Class] Native datatype to align with.
72
+ #
73
+ # @return [Class] Aligned native datatype.
74
+ #
75
+ # @private
76
+ def align( context )
77
+ self
78
+ end
79
+
80
+ # Element-type of this term
81
+ #
82
+ # @return [Class] Element-type of this datatype.
83
+ def typecode
84
+ self
85
+ end
86
+
87
+ # Array type of this term
88
+ #
89
+ # @return [Class] Resulting array type.
90
+ #
91
+ # @private
92
+ def array_type
93
+ self
94
+ end
95
+
96
+ # Convert to pointer type
97
+ #
98
+ # @return [Class] Corresponding pointer type.
99
+ def pointer_type
100
+ Hornetseye::Pointer( self )
101
+ end
102
+
103
+ # Get shape of this term
104
+ #
105
+ # @return [Array<Integer>] Returns +[]+.
106
+ def shape
107
+ []
108
+ end
109
+
110
+ # Get dimension of this term
111
+ #
112
+ # @return [Array<Integer>] Returns +0+.
113
+ def dimension
114
+ 0
115
+ end
116
+
117
+ # Get corresponding contiguous datatype
118
+ #
119
+ # @return [Class] Returns +self+.
120
+ #
121
+ # @private
122
+ def contiguous
123
+ self
124
+ end
125
+
126
+ # Get corresponding boolean-based datatype
127
+ #
128
+ # @return [Class] Returns +BOOL+.
129
+ def bool
130
+ BOOL
131
+ end
132
+
133
+ # Get boolean-based datatype for binary operation
134
+ #
135
+ # @return [Class] Returns +BOOL+.
136
+ def bool_binary( other )
137
+ other.coercion( self ).bool
138
+ end
139
+
140
+ # Get variables contained in this datatype
141
+ #
142
+ # @return [Set] Returns +Set[]+.
143
+ #
144
+ # @private
145
+ def variables
146
+ Set[]
147
+ end
148
+
149
+ # Category operator
150
+ #
151
+ # @return [FalseClass,TrueClass] Check for equality or kind.
152
+ def ===( other )
153
+ ( other == self ) or ( other.is_a? self ) or ( other.class == self )
154
+ end
155
+
156
+ # Strip of all values
157
+ #
158
+ # Split up into variables, values, and a term where all values have been
159
+ # replaced with variables.
160
+ #
161
+ # @return [Array<Array,Node>] Returns an array of variables, an array of
162
+ # values, and the term based on variables.
163
+ #
164
+ # @private
165
+ def strip
166
+ return [], [], self
167
+ end
168
+
169
+ # Substitute variables
170
+ #
171
+ # Substitute the variables with the values given in the hash.
172
+ #
173
+ # @param [Hash] hash Substitutions to apply.
174
+ #
175
+ # @return [Node] Term with substitutions applied.
176
+ #
177
+ # @private
178
+ def subst( hash )
179
+ hash[ self ] || self
180
+ end
181
+
182
+ # Check whether this term is compilable
183
+ #
184
+ # @return [FalseClass,TrueClass] Returns +true+.
185
+ #
186
+ # @private
187
+ def compilable?
188
+ true
189
+ end
190
+
191
+ end
192
+
193
+ # Array type of this term
194
+ #
195
+ # @return [Class] Resulting array type.
196
+ def array_type
197
+ self.class.array_type
198
+ end
199
+
200
+ # Convert to pointer type
201
+ #
202
+ # @return [Class] Corresponding pointer type.
203
+ def pointer_type
204
+ array_type.pointer_type
205
+ end
206
+
207
+ # Element-type of this term
208
+ #
209
+ # @return [Class] Element-type of this datatype.
210
+ def typecode
211
+ array_type.typecode
212
+ end
213
+
214
+ # Get shape of this term
215
+ #
216
+ # @return [Array<Integer>] Returns +array_type.shape+.
217
+ def shape
218
+ array_type.shape
219
+ end
220
+
221
+ # Get dimension of this term
222
+ #
223
+ # @return [Array<Integer>] Returns +array_type.dimension+.
224
+ def dimension
225
+ array_type.dimension
226
+ end
227
+
228
+ # Extract native value if this is an element
229
+ #
230
+ # @return [Node,Object] Returns +self+.
231
+ #
232
+ # @private
233
+ def get
234
+ self
235
+ end
236
+
237
+ # Convert to Ruby array of objects
238
+ #
239
+ # Perform pending computations and convert native array to Ruby array of
240
+ # objects.
241
+ #
242
+ # @return [Array<Object>] Array of objects.
243
+ def to_a
244
+ if dimension == 0
245
+ force
246
+ else
247
+ n = shape.last
248
+ ( 0 ... n ).collect { |i| element( i ).to_a }
249
+ end
250
+ end
251
+
252
+ # Display information about this object
253
+ #
254
+ # @return [String] String with information about this object.
255
+ def inspect( indent = nil, lines = nil )
256
+ if variables.empty?
257
+ if dimension == 0 and not indent
258
+ "#{array_type.inspect}(#{force.inspect})" # !!!
259
+ else
260
+ prepend = indent ? '' : "#{array_type.inspect}:\n"
261
+ indent = 0
262
+ lines = 0
263
+ retval = '[ '
264
+ for i in 0 ... array_type.num_elements
265
+ x = Hornetseye::lazy { element i }
266
+ if x.dimension > 0
267
+ if i > 0
268
+ retval += ",\n "
269
+ lines += 1
270
+ if lines >= 10
271
+ retval += '...' if indent == 0
272
+ break
273
+ end
274
+ retval += ' ' * indent
275
+ end
276
+ str = x.inspect indent + 1, lines
277
+ lines += str.count "\n"
278
+ retval += str
279
+ if lines >= 10
280
+ retval += '...' if indent == 0
281
+ break
282
+ end
283
+ else
284
+ retval += ', ' if i > 0
285
+ str = x.force.inspect # !!!
286
+ if retval.size + str.size >= 74 - '...'.size -
287
+ '[ ]'.size * indent.succ
288
+ retval += '...'
289
+ break
290
+ else
291
+ retval += str
292
+ end
293
+ end
294
+ end
295
+ retval += ' ]' unless lines >= 10
296
+ prepend + retval
297
+ end
298
+ else
299
+ to_s
300
+ end
301
+ end
302
+
303
+ # Get unique descriptor of this object
304
+ #
305
+ # The method calls +descriptor( {} )+.
306
+ #
307
+ # @return [String] Descriptor of this object.
308
+ #
309
+ # @see #descriptor
310
+ #
311
+ # @private
312
+ def to_s
313
+ descriptor( {} )
314
+ end
315
+
316
+ # Get unique descriptor of this object
317
+ #
318
+ # @param [Hash] hash Labels for any variables.
319
+ #
320
+ # @return [String] Descriptor of this object.
321
+ #
322
+ # @private
323
+ def descriptor( hash )
324
+ 'Node()'
325
+ end
326
+
327
+ # Substitute variables
328
+ #
329
+ # Substitute the variables with the values given in the hash.
330
+ #
331
+ # @param [Hash] hash Substitutions to apply.
332
+ #
333
+ # @return [Node] Term with substitutions applied.
334
+ #
335
+ # @private
336
+ def subst( hash )
337
+ hash[ self ] || self
338
+ end
339
+
340
+ # Check whether this term is compilable
341
+ #
342
+ # @return [FalseClass,TrueClass] Returns +typecode.compilable?+.
343
+ #
344
+ # @private
345
+ def compilable?
346
+ typecode.compilable?
347
+ end
348
+
349
+ # Lazy transpose of array
350
+ #
351
+ # Lazily compute transpose by swapping indices according to the specified
352
+ # order.
353
+ #
354
+ # @param [Array<Integer>] order New order of indices.
355
+ #
356
+ # @return [Node] Returns the transposed array.
357
+ def transpose( *order )
358
+ term = self
359
+ variables = shape.reverse.collect do |i|
360
+ var = Variable.new INDEX( i )
361
+ term = term.element var
362
+ var
363
+ end.reverse
364
+ order.collect { |o| variables[o] }.
365
+ inject( term ) { |retval,var| Lambda.new var, retval }
366
+ end
367
+
368
+ # Retrieve value of array element(s)
369
+ #
370
+ # @param [Array<Integer>] *indices Index/indices to select element.
371
+ #
372
+ # @return [Object,Node] Value of array element or a sub-element.
373
+ def []( *indices )
374
+ if indices.empty?
375
+ force
376
+ else
377
+ element( indices.last )[ *indices[ 0 ... -1 ] ]
378
+ end
379
+ end
380
+
381
+ # Assign value to array element(s)
382
+ #
383
+ # @overload []=( *indices, value )
384
+ # Assign a value to an element of an array
385
+ # @param [Array<Integer>] *indices Index/indices to select the element.
386
+ # @param [Object,Node] value Ruby object with new value.
387
+ #
388
+ # @return [Object,Node] Returns the value.
389
+ def []=( *indices )
390
+ value = indices.pop
391
+ value = Node.match( value ).new value unless value.is_a? Node
392
+ if indices.empty?
393
+ store value
394
+ else
395
+ element( indices.last )[ *indices[ 0 ... -1 ] ] = value
396
+ end
397
+ end
398
+
399
+ # Get variables contained in this object
400
+ #
401
+ # @return [Set] Returns +Set[]+.
402
+ #
403
+ # @private
404
+ def variables
405
+ Set[]
406
+ end
407
+
408
+ # Strip of all values
409
+ #
410
+ # Split up into variables, values, and a term where all values have been
411
+ # replaced with variables.
412
+ #
413
+ # @return [Array<Array,Node>] Returns an array of variables, an array of
414
+ # values, and the term based on variables.
415
+ #
416
+ # @private
417
+ def strip
418
+ return [], [], self
419
+ end
420
+
421
+ # Reevaluate computation
422
+ #
423
+ # @return [Node,Object] Result of computation
424
+ #
425
+ # @see #force
426
+ #
427
+ # @private
428
+ def demand
429
+ self
430
+ end
431
+
432
+ # Check whether mode of computation is lazy
433
+ #
434
+ # @see #lazy
435
+ #
436
+ # @private
437
+ def lazy?
438
+ ( dimension > 0 and Thread.current[ :lazy ] ) or not variables.empty?
439
+ end
440
+
441
+ # Force delayed computation unless in lazy mode
442
+ #
443
+ # @return [Node,Object] Result of computation
444
+ #
445
+ # @see #demand
446
+ #
447
+ # @private
448
+ def force
449
+ if lazy?
450
+ self
451
+ else
452
+ unless compilable?
453
+ Hornetseye::lazy do
454
+ retval = array_type.new
455
+ retval[] = self
456
+ retval.get
457
+ end
458
+ else
459
+ GCCFunction.run( self ).get
460
+ end
461
+ end
462
+ end
463
+
464
+ # Reevaluate term
465
+ #
466
+ # @return [Node,Object] Result of simplification
467
+ #
468
+ # @See @demand
469
+ #
470
+ # @private
471
+ def simplify
472
+ dimension == 0 ? demand.dup : demand
473
+ end
474
+
475
+ # Coerce with other object
476
+ #
477
+ # @param [Node,Object] other Other object.
478
+ #
479
+ # @return [Array<Node>] Result of coercion.
480
+ #
481
+ # @private
482
+ def coerce( other )
483
+ if other.is_a? Node
484
+ return other, self
485
+ else
486
+ return Node.match( other, typecode ).new( other ), self
487
+ end
488
+ end
489
+
490
+ def inject( initial = nil, options = {} )
491
+ unless initial.nil?
492
+ initial = Node.match( initial ).new initial unless initial.is_a? Node
493
+ initial_typecode = initial.typecode
494
+ else
495
+ initial_typecode = typecode
496
+ end
497
+ var1 = options[ :var1 ] || Variable.new( initial_typecode )
498
+ var2 = options[ :var2 ] || Variable.new( typecode )
499
+ block = options[ :block ] || yield( var1, var2 )
500
+ if dimension == 0
501
+ if initial
502
+ block.subst( var1 => initial, var2 => self ).simplify
503
+ else
504
+ demand
505
+ end
506
+ else
507
+ index = Variable.new Hornetseye::INDEX( nil )
508
+ value = element( index ).
509
+ inject nil, :block => block, :var1 => var1, :var2 => var2
510
+ Inject.new( value, index, initial, block, var1, var2 ).force
511
+ end
512
+ end
513
+
514
+ # Equality operator
515
+ #
516
+ # @return [FalseClass,TrueClass] Returns result of comparison.
517
+ def ==( other )
518
+ if other.is_a? Node and other.array_type == array_type
519
+ Hornetseye::eager { eq( other ).inject( true ) { |a,b| a.and b } }
520
+ else
521
+ false
522
+ end
523
+ end
524
+
525
+ # Apply accumulative operation over elements diagonally
526
+ #
527
+ # This method is used internally to implement convolutions.
528
+ #
529
+ # @param [Object,Node] initial Initial value.
530
+ # @option options [Variable] :var1 First variable defining operation.
531
+ # @option options [Variable] :var2 Second variable defining operation.
532
+ # @option options [Variable] :block (yield( var1, var2 )) The operation to
533
+ # apply diagonally.
534
+ # @yield Optional operation to apply diagonally.
535
+ #
536
+ # @return [Node] Result of operation.
537
+ #
538
+ # @see #convolve
539
+ #
540
+ # @private
541
+ def diagonal( initial = nil, options = {} )
542
+ if dimension == 0
543
+ demand
544
+ else
545
+ if initial
546
+ initial = Node.match( initial ).new initial unless initial.is_a? Node
547
+ initial_typecode = initial.typecode
548
+ else
549
+ initial_typecode = typecode
550
+ end
551
+ index0 = Variable.new Hornetseye::INDEX( nil )
552
+ index1 = Variable.new Hornetseye::INDEX( nil )
553
+ index2 = Variable.new Hornetseye::INDEX( nil )
554
+ var1 = options[ :var1 ] || Variable.new( initial_typecode )
555
+ var2 = options[ :var2 ] || Variable.new( typecode )
556
+ block = options[ :block ] || yield( var1, var2 )
557
+ value = element( index1 ).element( index2 ).
558
+ diagonal initial, :block => block, :var1 => var1, :var2 => var2
559
+ term = Diagonal.new( value, index0, index1, index2, initial,
560
+ block, var1, var2 )
561
+ index0.size[] ||= index1.size[]
562
+ Lambda.new( index0, term ).force
563
+ end
564
+ end
565
+
566
+ # Compute product table from two arrays
567
+ #
568
+ # Used internally to implement convolutions.
569
+ #
570
+ # @param [Node] filter Filter to form product table with.
571
+ #
572
+ # @return [Node] Result of operation.
573
+ #
574
+ # @see #convolve
575
+ #
576
+ # @private
577
+ def product( filter )
578
+ if dimension == 0
579
+ self * filter
580
+ else
581
+ Hornetseye::lazy { |i,j| self[j].product filter[i] }
582
+ end
583
+ end
584
+
585
+ # Convolution with other array of same dimension
586
+ #
587
+ # @param [Node] filter Filter to convolve with.
588
+ #
589
+ # @return [Node] Result of convolution.
590
+ def convolve( filter )
591
+ product( filter ).diagonal { |s,x| s + x }
592
+ end
593
+
594
+ end
595
+
596
+ end