multiarray 0.22.0 → 0.23.1

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.
Files changed (51) hide show
  1. data/Rakefile +1 -1
  2. data/lib/multiarray.rb +53 -16
  3. data/lib/multiarray/bool.rb +1 -1
  4. data/lib/multiarray/complex.rb +76 -68
  5. data/lib/multiarray/components.rb +11 -10
  6. data/lib/multiarray/composite.rb +1 -1
  7. data/lib/multiarray/diagonal.rb +11 -12
  8. data/lib/multiarray/element.rb +3 -3
  9. data/lib/multiarray/elementwise.rb +14 -14
  10. data/lib/multiarray/field.rb +380 -0
  11. data/lib/multiarray/float.rb +10 -10
  12. data/lib/multiarray/gcccache.rb +1 -1
  13. data/lib/multiarray/gcccontext.rb +35 -54
  14. data/lib/multiarray/gccfunction.rb +12 -19
  15. data/lib/multiarray/gcctype.rb +1 -1
  16. data/lib/multiarray/gccvalue.rb +63 -43
  17. data/lib/multiarray/histogram.rb +17 -19
  18. data/lib/multiarray/index.rb +7 -8
  19. data/lib/multiarray/inject.rb +11 -12
  20. data/lib/multiarray/int.rb +12 -11
  21. data/lib/multiarray/integral.rb +11 -12
  22. data/lib/multiarray/lambda.rb +23 -18
  23. data/lib/multiarray/list.rb +1 -1
  24. data/lib/multiarray/lookup.rb +18 -13
  25. data/lib/multiarray/lut.rb +13 -16
  26. data/lib/multiarray/malloc.rb +1 -1
  27. data/lib/multiarray/mask.rb +11 -8
  28. data/lib/multiarray/methods.rb +10 -10
  29. data/lib/multiarray/multiarray.rb +15 -44
  30. data/lib/multiarray/node.rb +64 -138
  31. data/lib/multiarray/object.rb +2 -6
  32. data/lib/multiarray/operations.rb +116 -134
  33. data/lib/multiarray/pointer.rb +7 -19
  34. data/lib/multiarray/random.rb +11 -8
  35. data/lib/multiarray/rgb.rb +53 -53
  36. data/lib/multiarray/sequence.rb +11 -496
  37. data/lib/multiarray/shortcuts.rb +4 -4
  38. data/lib/multiarray/store.rb +14 -11
  39. data/lib/multiarray/unmask.rb +10 -7
  40. data/lib/multiarray/variable.rb +11 -3
  41. data/test/tc_bool.rb +0 -8
  42. data/test/tc_compile.rb +72 -0
  43. data/test/tc_float.rb +0 -8
  44. data/test/tc_int.rb +0 -8
  45. data/test/tc_lazy.rb +22 -3
  46. data/test/tc_multiarray.rb +100 -126
  47. data/test/tc_object.rb +0 -16
  48. data/test/tc_rgb.rb +0 -16
  49. data/test/tc_sequence.rb +151 -165
  50. data/test/ts_multiarray.rb +2 -0
  51. metadata +7 -4
@@ -1,5 +1,5 @@
1
1
  # multiarray - Lazy multi-dimensional arrays for Ruby
2
- # Copyright (C) 2010 Jan Wedekind
2
+ # Copyright (C) 2010, 2011 Jan Wedekind
3
3
  #
4
4
  # This program is free software: you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -22,30 +22,8 @@ module Hornetseye
22
22
 
23
23
  class << self
24
24
 
25
- # Create new multi-dimensional array
26
- #
27
- # @param [Class] element_type The type of the elements.
28
- # @param [Array<Integer>] *array_shape The shape of the multi-dimensional array.
29
- #
30
- # @return [Node] Returns uninitialised native array.
31
- def new( element_type, *array_shape )
32
- typecode = element_type.typecode
33
- shape = element_type.shape + array_shape
34
- options = shape.last.is_a?( Hash ) ? shape.pop : {}
35
- count = options[ :count ] || 1
36
- if shape.empty?
37
- memory = options[ :memory ] ||
38
- typecode.memory_type.new( typecode.storage_size * count )
39
- Hornetseye::Pointer( typecode ).new memory
40
- else
41
- size = shape.pop
42
- stride = shape.inject( 1 ) { |a,b| a * b }
43
- Hornetseye::lazy( size ) do |index|
44
- pointer = new typecode, *( shape + [ :count => count * size,
45
- :memory => options[ :memory ] ] )
46
- Lookup.new pointer, index, INT.new( stride )
47
- end
48
- end
25
+ def new(typecode, *shape)
26
+ Hornetseye::MultiArray(typecode, shape.size).new *shape
49
27
  end
50
28
 
51
29
  # Import array from string
@@ -53,19 +31,19 @@ module Hornetseye
53
31
  # Create an array from raw data provided as a string.
54
32
  #
55
33
  # @param [Class] typecode Type of the elements in the string.
56
- # @param [String] string String with raw data.
34
+ # @param [String,Malloc] data String or memory object with raw data.
57
35
  # @param [Array<Integer>] shape Array with dimensions of array.
58
36
  #
59
37
  # @return [Node] Multi-dimensional array with imported data.
60
- def import( typecode, string, *shape )
61
- t = Hornetseye::MultiArray typecode, *shape
62
- if string.is_a? Malloc
63
- memory = string
38
+ def import( typecode, data, *shape )
39
+ t = Hornetseye::MultiArray typecode, shape.size
40
+ if data.is_a? Malloc
41
+ memory = data
64
42
  else
65
- memory = Malloc.new t.storage_size
66
- memory.write string
43
+ memory = Malloc.new t.storage_size(*shape)
44
+ memory.write data
67
45
  end
68
- t.new memory
46
+ t.new *(shape + [:memory => memory])
69
47
  end
70
48
 
71
49
  # Convert Ruby array to uniform multi-dimensional array
@@ -118,18 +96,11 @@ module Hornetseye
118
96
 
119
97
  end
120
98
 
121
- # Create multi-dimensional array type
122
- #
123
- # @param [Class] element_type Type of elements.
124
- # @param [Array<Integer>] *shape Shape of array type.
125
- #
126
- # @return [Class] The array type.
127
- def MultiArray( element_type, *shape )
128
- if shape.empty?
129
- element_type
99
+ def MultiArray(typecode, dimension)
100
+ if dimension > 0
101
+ Field_.inherit typecode.typecode, typecode.dimension + dimension
130
102
  else
131
- Hornetseye::Sequence MultiArray( element_type, *shape[ 0 ... -1 ] ),
132
- shape.last
103
+ Hornetseye::Pointer typecode
133
104
  end
134
105
  end
135
106
 
@@ -1,5 +1,5 @@
1
1
  # multiarray - Lazy multi-dimensional arrays for Ruby
2
- # Copyright (C) 2010 Jan Wedekind
2
+ # Copyright (C) 2010, 2011 Jan Wedekind
3
3
  #
4
4
  # This program is free software: you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -84,20 +84,8 @@ module Hornetseye
84
84
  [ self ]
85
85
  end
86
86
 
87
- # Get type of result of delayed operation
88
- #
89
- # @return [Class] Type of result.
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 )
87
+ def shape
88
+ []
101
89
  end
102
90
 
103
91
  # Generate index array of this type
@@ -110,41 +98,6 @@ module Hornetseye
110
98
  offset
111
99
  end
112
100
 
113
- # Get shape of this term
114
- #
115
- # @return [Array<Integer>] Returns +[]+.
116
- def shape
117
- []
118
- end
119
-
120
- # Get width of two-dimensional array
121
- #
122
- # @return [Integer] Width of array.
123
- def width
124
- shape[0]
125
- end
126
-
127
- # Get height of two-dimensional array
128
- #
129
- # @return [Integer] Height of array.
130
- def height
131
- shape[1]
132
- end
133
-
134
- # Get size (number of elements) of this value
135
- #
136
- # @return [Integer] Returns +1+.
137
- def size
138
- 1
139
- end
140
-
141
- # Check whether the type is an empty array
142
- #
143
- # @return [Boolean] Returns whether this type represents an empty array.
144
- def empty?
145
- size == 0
146
- end
147
-
148
101
  # Get dimension of this term
149
102
  #
150
103
  # @return [Array<Integer>] Returns +0+.
@@ -252,9 +205,8 @@ module Hornetseye
252
205
  # @param [Class] a The third type.
253
206
  #
254
207
  # @return [Class] Returns type based on bytes.
255
- def cond( a, b )
256
- t = a.coercion b
257
- Hornetseye::MultiArray( t.typecode, *shape ).coercion t
208
+ def cond(a, b)
209
+ a.coercion b
258
210
  end
259
211
 
260
212
  # Convert to different element type
@@ -308,31 +260,6 @@ module Hornetseye
308
260
  hash[ self ] || self
309
261
  end
310
262
 
311
- # Check arguments for compatible shape
312
- #
313
- # The method will throw an exception if one of the arguments has an incompatible
314
- # shape.
315
- #
316
- # @param [Array<Class>] args Arguments to check for compatibility.
317
- #
318
- # @return [Object] The return value should be ignored.
319
- def check_shape( *args )
320
- _shape = shape
321
- args.each do |arg|
322
- _arg_shape = arg.shape
323
- if _shape.size < _arg_shape.size
324
- raise "#{arg.inspect} has #{arg.dimension} dimension(s) " +
325
- "but should not have more than #{dimension}"
326
- end
327
- if ( _shape + _arg_shape ).all? { |s| s.is_a? Integer }
328
- if _shape.last( _arg_shape.size ) != _arg_shape
329
- raise "#{arg.inspect} has shape #{arg.shape.inspect} " +
330
- "(does not match last value(s) of #{shape.inspect})"
331
- end
332
- end
333
- end
334
- end
335
-
336
263
  # Check whether this term is compilable
337
264
  #
338
265
  # @return [Boolean] Returns +true+.
@@ -353,69 +280,47 @@ module Hornetseye
353
280
 
354
281
  end
355
282
 
356
- # Get type of result of delayed operation
357
- #
358
- # @return [Class] Type of result.
359
- #
360
- # @private
361
- def array_type
362
- self.class.array_type
283
+ def matched?
284
+ true
363
285
  end
364
286
 
365
- # Convert to pointer type
366
- #
367
- # @return [Class] Corresponding pointer type.
368
- def pointer_type
369
- array_type.pointer_type
287
+ def allocate
288
+ Hornetseye::MultiArray(typecode, dimension).new *shape
370
289
  end
371
290
 
372
291
  # Element-type of this term
373
292
  #
374
293
  # @return [Class] Element-type of this datatype.
375
294
  def typecode
376
- array_type.typecode
295
+ self.class.typecode
377
296
  end
378
297
 
379
298
  # Base-type of this term
380
299
  #
381
300
  # @return [Class] Base-type of this datatype.
382
301
  def basetype
383
- array_type.basetype
384
- end
385
-
386
- # Get shape of this term
387
- #
388
- # @return [Array<Integer>] Returns +array_type.shape+.
389
- def shape
390
- array_type.shape
302
+ self.class.basetype
391
303
  end
392
304
 
393
305
  # Get width of two-dimensional array
394
306
  #
395
307
  # @return [Integer] Width of array.
396
308
  def width
397
- array_type.width
309
+ shape[0]
398
310
  end
399
311
 
400
312
  # Get height of two-dimensional array
401
313
  #
402
314
  # @return [Integer] Height of array.
403
315
  def height
404
- array_type.height
316
+ shape[1]
405
317
  end
406
318
 
407
319
  # Get size (number of elements) of this value
408
320
  #
409
- # @return [Integer] Returns +array_type.size+.
321
+ # @return [Integer] Returns number of elements of this value.
410
322
  def size
411
- array_type.size
412
- end
413
-
414
- # Get memory size of object
415
- #
416
- # @return [Integer] Returns required storage size of this array.
417
- def storage_size
418
- array_type.storage_size
323
+ shape.inject(1) { |a,b| a * b }
419
324
  end
420
325
 
421
326
  # Duplicate array expression if it is not in row-major format
@@ -423,8 +328,8 @@ module Hornetseye
423
328
  # @return [Node] Duplicate of array or +self+.
424
329
  def memorise
425
330
  if memory
426
- contiguous_strides = ( 0 ... dimension ).collect do |i|
427
- shape[ 0 ... i ].inject( 1 ) { |a,b| a * b }
331
+ contiguous_strides = (0 ... dimension).collect do |i|
332
+ shape[0 ... i].inject(1) { |a,b| a * b }
428
333
  end
429
334
  if strides == contiguous_strides
430
335
  self
@@ -465,21 +370,28 @@ module Hornetseye
465
370
  #
466
371
  # @return [Boolean] Returns whether this object is an empty array.
467
372
  def empty?
468
- array_type.empty?
373
+ size == 0
374
+ end
375
+
376
+ # Get shape of this term
377
+ #
378
+ # @return [Array<Integer>] Returns +[]+.
379
+ def shape
380
+ self.class.shape
469
381
  end
470
382
 
471
383
  # Get dimension of this term
472
384
  #
473
- # @return [Array<Integer>] Returns +array_type.dimension+.
385
+ # @return [Array<Integer>] Returns number of dimensions of this term.
474
386
  def dimension
475
- array_type.dimension
387
+ shape.size
476
388
  end
477
389
 
478
390
  # Check whether this object is an RGB value
479
391
  #
480
392
  # @return [Boolean] Returns +false+.
481
393
  def rgb?
482
- array_type.rgb?
394
+ typecode.rgb?
483
395
  end
484
396
 
485
397
  # Extract native value if this is an element
@@ -512,12 +424,12 @@ module Hornetseye
512
424
  def inspect( indent = nil, lines = nil )
513
425
  if variables.empty?
514
426
  if dimension == 0 and not indent
515
- "#{array_type.inspect}(#{force.inspect})" # !!!
427
+ "#{typecode.inspect}(#{force.inspect})"
516
428
  else
517
429
  if indent
518
430
  prepend = ''
519
431
  else
520
- prepend = "#{array_type.inspect}:\n"
432
+ prepend = "#{Hornetseye::MultiArray(typecode, dimension).inspect}:\n"
521
433
  indent = 0
522
434
  lines = 0
523
435
  end
@@ -525,7 +437,7 @@ module Hornetseye
525
437
  retval = '[]'
526
438
  else
527
439
  retval = '[ '
528
- for i in 0 ... array_type.num_elements
440
+ for i in 0 ... shape.last
529
441
  x = element i
530
442
  if x.dimension > 0
531
443
  if i > 0
@@ -546,7 +458,7 @@ module Hornetseye
546
458
  end
547
459
  else
548
460
  retval += ', ' if i > 0
549
- str = x.force.inspect # !!!
461
+ str = x.force.inspect
550
462
  if retval.size + str.size >= 74 - '...'.size -
551
463
  '[ ]'.size * indent.succ
552
464
  retval += '...'
@@ -593,7 +505,7 @@ module Hornetseye
593
505
  #
594
506
  # @return [Node] Duplicate of +self+.
595
507
  def dup
596
- retval = array_type.new
508
+ retval = Hornetseye::MultiArray(typecode, dimension).new *shape
597
509
  retval[] = self
598
510
  retval
599
511
  end
@@ -652,14 +564,26 @@ module Hornetseye
652
564
  # The method will throw an exception if one of the arguments has an incompatible
653
565
  # shape.
654
566
  #
655
- # @param [Array<Node>] args Arguments to check for compatibility.
567
+ # @param [Array<Class>] args Arguments to check for compatibility.
656
568
  #
657
569
  # @return [Object] The return value should be ignored.
658
- def check_shape( *args )
659
- array_type.check_shape *args.collect { |arg| arg.array_type }
570
+ def check_shape(*args)
571
+ _shape = shape
572
+ args.each do |arg|
573
+ _arg_shape = arg.shape
574
+ if _shape.size < _arg_shape.size
575
+ raise "#{arg.inspect} has #{arg.dimension} dimension(s) " +
576
+ "but should not have more than #{dimension}"
577
+ end
578
+ if ( _shape + _arg_shape ).all? { |s| s.is_a? Integer }
579
+ if _shape.last( _arg_shape.size ) != _arg_shape
580
+ raise "#{arg.inspect} has shape #{arg.shape.inspect} " +
581
+ "(does not match last value(s) of #{shape.inspect})"
582
+ end
583
+ end
584
+ end
660
585
  end
661
586
 
662
-
663
587
  # Assign value to array element(s)
664
588
  #
665
589
  # @overload []=( *indices, value )
@@ -670,13 +594,13 @@ module Hornetseye
670
594
  # @return [Object,Node] Returns the value.
671
595
  def []=( *indices )
672
596
  value = indices.pop
673
- value = typecode.new value unless value.is_a? Node
597
+ value = typecode.new value unless value.matched?
674
598
  if indices.empty?
675
599
  check_shape value
676
600
  unless compilable? and value.compilable? and dimension > 0
677
- Store.new( self, value ).demand
601
+ Store.new(self, value.sexp).demand
678
602
  else
679
- GCCFunction.run Store.new( self, value )
603
+ GCCFunction.run Store.new(self, value.sexp)
680
604
  end
681
605
  value
682
606
  else
@@ -685,7 +609,7 @@ module Hornetseye
685
609
  else
686
610
  view = element indices.last
687
611
  end
688
- view[ *indices[ 0 ... -1 ] ] = value
612
+ view[*indices[0 ... -1]] = value
689
613
  end
690
614
  end
691
615
 
@@ -732,14 +656,16 @@ module Hornetseye
732
656
  def force
733
657
  if finalised?
734
658
  get
735
- elsif ( dimension > 0 and Thread.current[ :lazy ] ) or not variables.empty?
659
+ elsif (dimension > 0 and Thread.current[:lazy]) or not variables.empty?
736
660
  self
737
661
  elsif compilable?
738
- retval = pointer_type.new
739
- GCCFunction.run Store.new( retval, self )
662
+ retval = allocate
663
+ GCCFunction.run Store.new(retval.sexp, self)
740
664
  retval.demand.get
741
665
  else
742
- Store.new( array_type.new, self ).demand.get
666
+ retval = allocate
667
+ Store.new(retval.sexp, self).demand
668
+ retval.demand.get
743
669
  end
744
670
  end
745
671
 
@@ -756,16 +682,16 @@ module Hornetseye
756
682
 
757
683
  # Coerce with other object
758
684
  #
759
- # @param [Node,Object] other Other object.
685
+ # @param [Object] other Other object.
760
686
  #
761
687
  # @return [Array<Node>] Result of coercion.
762
688
  #
763
689
  # @private
764
- def coerce( other )
765
- if other.is_a? Node
766
- return other, self
690
+ def coerce(other)
691
+ if other.matched?
692
+ return other.sexp, self
767
693
  else
768
- return Node.match( other, self ).new( other ), self
694
+ return Node.match(other, self).new(other), self
769
695
  end
770
696
  end
771
697