multiarray 0.4.1 → 0.5.0

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