multiarray 0.16.0 → 0.17.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.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'rake/packagetask'
6
6
  require 'rbconfig'
7
7
 
8
8
  PKG_NAME = 'multiarray'
9
- PKG_VERSION = '0.16.0'
9
+ PKG_VERSION = '0.17.0'
10
10
  RB_FILES = FileList[ 'lib/**/*.rb' ]
11
11
  TC_FILES = FileList[ 'test/tc_*.rb' ]
12
12
  TS_FILES = FileList[ 'test/ts_*.rb' ]
data/lib/multiarray.rb CHANGED
@@ -176,6 +176,25 @@ class Object
176
176
  a.is_a?( Proc ) ? a.call : a
177
177
  end
178
178
 
179
+ # Conditional operation
180
+ #
181
+ # @param [Proc] action Action to perform if condition is +true+.
182
+ #
183
+ # @return [Object] The return value should be ignored.
184
+ def if( &action )
185
+ action.call
186
+ end
187
+
188
+ # Conditional operation
189
+ #
190
+ # @param [Proc] action1 Action to perform if condition is +true+.
191
+ # @param [Proc] action2 Action to perform if condition is +false+.
192
+ #
193
+ # @return [Object] The return value should be ignored.
194
+ def if_else( action1, action2 )
195
+ action1.call
196
+ end
197
+
179
198
  end
180
199
 
181
200
  # +NilClass+ is extended with a few methods
@@ -235,6 +254,24 @@ class NilClass
235
254
  b.is_a?( Proc ) ? b.call : b
236
255
  end
237
256
 
257
+ # Conditional operation
258
+ #
259
+ # @param [Proc] action Action to perform if condition is +true+.
260
+ #
261
+ # @return [Object] The return value should be ignored.
262
+ def if( &action )
263
+ end
264
+
265
+ # Conditional operation
266
+ #
267
+ # @param [Proc] action1 Action to perform if condition is +true+.
268
+ # @param [Proc] action2 Action to perform if condition is +false+.
269
+ #
270
+ # @return [Object] The return value should be ignored.
271
+ def if_else( action1, action2 )
272
+ action2.call
273
+ end
274
+
238
275
  # Check whether this term is compilable
239
276
  #
240
277
  # @return [FalseClass,TrueClass] Returns +false+
@@ -305,6 +342,24 @@ class FalseClass
305
342
  b.is_a?( Proc ) ? b.call : b
306
343
  end
307
344
 
345
+ # Conditional operation
346
+ #
347
+ # @param [Proc] action Action to perform if condition is +true+.
348
+ #
349
+ # @return [Object] The return value should be ignored.
350
+ def if( &action )
351
+ end
352
+
353
+ # Conditional operation
354
+ #
355
+ # @param [Proc] action1 Action to perform if condition is +true+.
356
+ # @param [Proc] action2 Action to perform if condition is +false+.
357
+ #
358
+ # @return [Object] The return value should be ignored.
359
+ def if_else( action1, action2 )
360
+ action2.call
361
+ end
362
+
308
363
  end
309
364
 
310
365
  # Some methods of +Fixnum+ are modified
@@ -603,6 +658,8 @@ require 'multiarray/diagonal'
603
658
  require 'multiarray/histogram'
604
659
  require 'multiarray/lut'
605
660
  require 'multiarray/integral'
661
+ require 'multiarray/mask'
662
+ require 'multiarray/unmask'
606
663
  require 'multiarray/operations'
607
664
  require 'multiarray/methods'
608
665
  require 'multiarray/rgb'
@@ -333,6 +333,44 @@ module Hornetseye
333
333
 
334
334
  alias_method_chain :conditional, :complex
335
335
 
336
+ # Generate code for conditional statement
337
+ #
338
+ # @param [Proc] action Block of conditional.
339
+ #
340
+ # @return [Object] Returns +self+.
341
+ #
342
+ # @private
343
+ def if( &action )
344
+ @function << "#{@function.indent}if ( #{self} ) {\n"
345
+ @function.indent_offset +1
346
+ action.call
347
+ @function.indent_offset -1
348
+ @function << "#{@function.indent}};\n"
349
+ self
350
+ end
351
+
352
+ # Generate code for conditional statement
353
+ #
354
+ # @param [Proc] action1 Block to run when condition is fullfilled.
355
+ # @param [Proc] action2 Block to run otherwise.
356
+ #
357
+ # @return [Object] Returns +self+.
358
+ #
359
+ # @private
360
+ def if_else( action1, action2 )
361
+ @function << "#{@function.indent}if ( #{self} ) {\n"
362
+ @function.indent_offset +1
363
+ action1.call
364
+ @function.indent_offset -1
365
+ @function << "#{@function.indent}} else {\n"
366
+ @function.indent_offset +1
367
+ action2.call
368
+ @function.indent_offset -1
369
+ @function << "#{@function.indent}};\n"
370
+ self
371
+ end
372
+
373
+
336
374
  define_unary_op :not, '!'
337
375
  define_unary_op :~
338
376
  define_unary_op :-@, :-
@@ -0,0 +1,147 @@
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 for representing masking operations
21
+ class Mask < Node
22
+
23
+ class << self
24
+
25
+ # Check whether objects of this class are finalised computations
26
+ #
27
+ # @return [Boolean] Returns +false+.
28
+ #
29
+ # @private
30
+ def finalised?
31
+ false
32
+ end
33
+
34
+ end
35
+
36
+ # Constructor
37
+ #
38
+ # @param [Node] dest Target array to write histogram to.
39
+ # @param [Node] source Source array with values to apply mask to.
40
+ # @param [Node] m Boolean array with values of mask.
41
+ # @param [Node] index Counter for maintaining size of result.
42
+ #
43
+ # @private
44
+ def initialize( dest, source, m, index )
45
+ @dest, @source, @m, @index = dest, source, m, index
46
+ end
47
+
48
+ # Get unique descriptor of this object
49
+ #
50
+ # @param [Hash] hash Labels for any variables.
51
+ #
52
+ # @return [String] Descriptor of this object,
53
+ #
54
+ # @private
55
+ def descriptor( hash )
56
+ "Mask(#{@dest.descriptor( hash )},#{@source.descriptor( hash )}," +
57
+ "#{@m.descriptor( hash )},#{@index.descriptor( hash )})"
58
+ end
59
+
60
+ # Get type of result of delayed operation
61
+ #
62
+ # @return [Class] Type of result.
63
+ #
64
+ # @private
65
+ def array_type
66
+ @dest.array_type
67
+ end
68
+
69
+ # Perform masking operation
70
+ #
71
+ # @return [Node] Result of computation
72
+ #
73
+ # @private
74
+ def demand
75
+ if variables.empty?
76
+ index = @index.simplify
77
+ if @m.dimension > 0
78
+ @m.shape.last.times do |i|
79
+ m = @m.element INT.new( i )
80
+ source = @source.element INT.new( i )
81
+ Mask.new( @dest, source, m, index ).demand
82
+ end
83
+ else
84
+ @m.simplify.get.if do
85
+ Store.new( @dest.element( index ), @source ).demand
86
+ index.store index + 1
87
+ end
88
+ end
89
+ @index.store index
90
+ @dest
91
+ else
92
+ super
93
+ end
94
+ end
95
+
96
+ # Substitute variables
97
+ #
98
+ # Substitute the variables with the values given in the hash.
99
+ #
100
+ # @param [Hash] hash Substitutions to apply.
101
+ #
102
+ # @return [Node] Term with substitutions applied.
103
+ #
104
+ # @private
105
+ def subst( hash )
106
+ self.class.new @dest.subst( hash ), @source.subst( hash ), @m.subst( hash ),
107
+ @index.subst( hash )
108
+ end
109
+
110
+ # Get variables contained in this term
111
+ #
112
+ # @return [Set] Returns list of variables.
113
+ #
114
+ # @private
115
+ def variables
116
+ @dest.variables + @source.variables + @m.variables + @index.variables
117
+ end
118
+
119
+ # Strip of all values
120
+ #
121
+ # Split up into variables, values, and a term where all values have been
122
+ # replaced with variables.
123
+ #
124
+ # @return [Array<Array,Node>] Returns an array of variables, an array of
125
+ # values, and the term based on variables.
126
+ #
127
+ # @private
128
+ def strip
129
+ stripped = [ @dest, @source, @m, @index ].collect { |value| value.strip }
130
+ return stripped.inject( [] ) { |vars,elem| vars + elem[ 0 ] },
131
+ stripped.inject( [] ) { |values,elem| values + elem[ 1 ] },
132
+ self.class.new( *stripped.collect { |elem| elem[ 2 ] } )
133
+ end
134
+
135
+ # Check whether this term is compilable
136
+ #
137
+ # @return [Boolean] Returns whether this term is compilable.
138
+ #
139
+ # @private
140
+ def compilable?
141
+ [ @dest, @source, @m, @index ].all? { |value| value.compilable? }
142
+ end
143
+
144
+ end
145
+
146
+ end
147
+
@@ -24,11 +24,13 @@ module Hornetseye
24
24
 
25
25
  # Create new multi-dimensional array
26
26
  #
27
- # @param [Class] typecode The type of elements
28
- # @param [Array<Integer>] *shape The shape of the multi-dimensional array.
27
+ # @param [Class] element_type The type of the elements.
28
+ # @param [Array<Integer>] *array_shape The shape of the multi-dimensional array.
29
29
  #
30
30
  # @return [Node] Returns uninitialised native array.
31
- def new( typecode, *shape )
31
+ def new( element_type, *array_shape )
32
+ typecode = element_type.typecode
33
+ shape = element_type.shape + array_shape
32
34
  options = shape.last.is_a?( Hash ) ? shape.pop : {}
33
35
  count = options[ :count ] || 1
34
36
  if shape.empty?
@@ -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
@@ -569,6 +569,59 @@ module Hornetseye
569
569
  left
570
570
  end
571
571
 
572
+ # Select values from array using a mask
573
+ #
574
+ # @param [Node] m Mask to apply to this array.
575
+ #
576
+ # @return [Node] The masked array.
577
+ def mask( m )
578
+ check_shape m
579
+ left = MultiArray.new typecode, *( shape.first( dimension - m.dimension ) +
580
+ [ m.size ] )
581
+ index = Hornetseye::Pointer( INT ).new
582
+ index.store INT.new( 0 )
583
+ block = Mask.new left, self, m, index
584
+ if block.compilable?
585
+ GCCFunction.run block
586
+ else
587
+ block.demand
588
+ end
589
+ left[ 0 ... index[] ].roll
590
+ end
591
+
592
+ # Distribute values in a new array using a mask
593
+ #
594
+ # @param [Node] m Mask for inverse masking operation.
595
+ # @option options [Object] :default (typecode.default) Default value for elements
596
+ # where mask is +false+.
597
+ # @option options [Boolean] :safe (true) Ensure that the size of this size is
598
+ # sufficient.
599
+ #
600
+ # @return [Node] The result of the inverse masking operation.
601
+ def unmask( m, options = {} )
602
+ options = { :safe => true, :default => typecode.default }.merge options
603
+ default = options[ :default ]
604
+ default = typecode.new default unless default.is_a? Node
605
+ m.check_shape default
606
+ if options[ :safe ]
607
+ if m.to_ubyte.sum > shape.last
608
+ raise "#{m.to_ubyte.sum} value(s) of the mask are true but the last " +
609
+ "dimension of the array for unmasking only has #{shape.last} value(s)"
610
+ end
611
+ end
612
+ left = Hornetseye::MultiArray( array_type.element_type, *m.shape ).
613
+ coercion( default.array_type ).new
614
+ index = Hornetseye::Pointer( INT ).new
615
+ index.store INT.new( 0 )
616
+ block = Unmask.new left, self, m, index, default
617
+ if block.compilable?
618
+ GCCFunction.run block
619
+ else
620
+ block.demand
621
+ end
622
+ left
623
+ end
624
+
572
625
  # Mirror the array
573
626
  #
574
627
  # @param [Array<Integer>] dimensions The dimensions which should be flipped.
@@ -24,12 +24,12 @@ module Hornetseye
24
24
 
25
25
  # Allocate new uniform array
26
26
  #
27
- # @param [Class] typecode Type of array elements.
27
+ # @param [Class] element_type Type of array elements.
28
28
  # @param [Integer] size Number of elements.
29
29
  #
30
30
  # @return [Node] Returns uninitialised native array.
31
- def new( typecode, size )
32
- MultiArray.new typecode, size
31
+ def new( element_type, size )
32
+ MultiArray.new element_type, size
33
33
  end
34
34
 
35
35
  # Import array from string
@@ -117,6 +117,13 @@ module Hornetseye
117
117
  end
118
118
  end
119
119
 
120
+ # Generate random number array
121
+ #
122
+ # Generate integer or floating point random numbers in the range 0 ... n.
123
+ #
124
+ # @param [Integer,Float] n Upper boundary for random numbers
125
+ #
126
+ # @return [Node] Array with random numbers.
120
127
  def random( n = 1 )
121
128
  n = typecode.maxint.new n unless n.is_a? Node
122
129
  retval = new
@@ -0,0 +1,154 @@
1
+ # multiarray - Lazy multi-dimensional arrays for Ruby
2
+ # Copyright (C) 2011 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 for representing inverse masking operations
21
+ class Unmask < Node
22
+
23
+ class << self
24
+
25
+ # Check whether objects of this class are finalised computations
26
+ #
27
+ # @return [Boolean] Returns +false+.
28
+ #
29
+ # @private
30
+ def finalised?
31
+ false
32
+ end
33
+
34
+ end
35
+
36
+ # Constructor
37
+ #
38
+ # @param [Node] dest Target array to write histogram to.
39
+ # @param [Node] source Source array with values to apply mask to.
40
+ # @param [Node] m Boolean array with values of mask.
41
+ # @param [Node] default Default value for unaffected elements.
42
+ #
43
+ # @private
44
+ def initialize( dest, source, m, index, default )
45
+ @dest, @source, @m, @index, @default = dest, source, m, index, default
46
+ end
47
+
48
+ # Get unique descriptor of this object
49
+ #
50
+ # @param [Hash] hash Labels for any variables.
51
+ #
52
+ # @return [String] Descriptor of this object,
53
+ #
54
+ # @private
55
+ def descriptor( hash )
56
+ "Unmask(#{@dest.descriptor( hash )},#{@source.descriptor( hash )}," +
57
+ "#{@m.descriptor( hash )},#{@index.descriptor( hash )}," +
58
+ "#{@default.descriptor( hash )})"
59
+ end
60
+
61
+ # Get type of result of delayed operation
62
+ #
63
+ # @return [Class] Type of result.
64
+ #
65
+ # @private
66
+ def array_type
67
+ @dest.array_type
68
+ end
69
+
70
+ # Perform masking operation
71
+ #
72
+ # @return [Node] Result of computation
73
+ #
74
+ # @private
75
+ def demand
76
+ if variables.empty?
77
+ index = @index.simplify
78
+ if @m.dimension > 0
79
+ @m.shape.last.times do |i|
80
+ m = @m.element INT.new( i )
81
+ dest = @dest.element INT.new( i )
82
+ default = @default.dimension > 0 ?
83
+ @default.element( INT.new( i ) ) : @default
84
+ Unmask.new( dest, @source, m, index, default ).demand
85
+ end
86
+ else
87
+ @m.simplify.get.if_else( proc do
88
+ Store.new( @dest, @source.element( index ) ).demand
89
+ index.store index + 1
90
+ end, proc do
91
+ Store.new( @dest, @default ).demand
92
+ end )
93
+ end
94
+ @index.store index
95
+ @dest
96
+ else
97
+ super
98
+ end
99
+ end
100
+
101
+ # Substitute variables
102
+ #
103
+ # Substitute the variables with the values given in the hash.
104
+ #
105
+ # @param [Hash] hash Substitutions to apply.
106
+ #
107
+ # @return [Node] Term with substitutions applied.
108
+ #
109
+ # @private
110
+ def subst( hash )
111
+ self.class.new @dest.subst( hash ), @source.subst( hash ), @m.subst( hash ),
112
+ @index.subst( hash ), @default.subst( hash )
113
+ end
114
+
115
+ # Get variables contained in this term
116
+ #
117
+ # @return [Set] Returns list of variables.
118
+ #
119
+ # @private
120
+ def variables
121
+ @dest.variables + @source.variables + @m.variables + @index.variables +
122
+ @default.variables
123
+ end
124
+
125
+ # Strip of all values
126
+ #
127
+ # Split up into variables, values, and a term where all values have been
128
+ # replaced with variables.
129
+ #
130
+ # @return [Array<Array,Node>] Returns an array of variables, an array of
131
+ # values, and the term based on variables.
132
+ #
133
+ # @private
134
+ def strip
135
+ stripped = [ @dest, @source, @m, @index, @default ].
136
+ 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 ] } )
140
+ end
141
+
142
+ # Check whether this term is compilable
143
+ #
144
+ # @return [Boolean] Returns whether this term is compilable.
145
+ #
146
+ # @private
147
+ def compilable?
148
+ [ @dest, @source, @m, @index, @default ].all? { |value| value.compilable? }
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+
@@ -705,4 +705,31 @@ class TC_MultiArray < Test::Unit::TestCase
705
705
  M( I, 3, 2 )[ [ 1, 2, 3 ], [ 4, 5, 6 ] ].integral
706
706
  end
707
707
 
708
+ def test_mask
709
+ [ O, I ].each do |t|
710
+ assert_equal M( O, 2, 2 )[ [ 1, 2 ], [ 5, 7 ] ],
711
+ M( O, 2, 3 )[ [ 1, 2 ], [ 3, 4 ], [ 5, 7 ] ].
712
+ mask( S[ true, false, true ] )
713
+ assert_equal S( O, 3 )[ 2, 5, 7 ], M( O, 3, 2 )[ [ 1, 2, 3 ], [ 4, 5, 7 ] ].
714
+ mask( M[ [ false, true, false ], [ false, true, true ] ] )
715
+ assert_raise( RuntimeError ) do
716
+ M( O, 2, 3 )[ [ 1, 2 ], [ 3, 4 ], [ 5, 7 ] ].mask S[ false, true ]
717
+ end
718
+ end
719
+ end
720
+
721
+ def test_unmask
722
+ [ O, I ].each do |t|
723
+ assert_equal M( t, 2, 3 )[ [ 1, 2 ], [ 4, 4 ], [ 5, 7 ] ],
724
+ M( t, 2, 2 )[ [ 1, 2 ], [ 5, 7 ] ].
725
+ unmask( S[ true, false, true ], :default => S[ 3, 4, 5 ] )
726
+ assert_equal M( t, 3, 2 )[ [ 0, 2, 0 ], [ 0, 5, 7 ] ],
727
+ S( t, 3 )[ 2, 5, 7 ].
728
+ unmask( M[ [ false, true, false ], [ false, true, true ] ],
729
+ :default => 0 )
730
+ assert_raise( RuntimeError ) { S( t, 1 )[ 1 ].unmask M[ [ true, true ] ] }
731
+ end
732
+ end
733
+
708
734
  end
735
+
data/test/tc_sequence.rb CHANGED
@@ -893,4 +893,27 @@ class TC_Sequence < Test::Unit::TestCase
893
893
  assert_equal S( I, 3 )[ 1, 3, 6 ], S( I, 3 )[ 1, 2, 3 ].integral
894
894
  end
895
895
 
896
+ def test_mask
897
+ assert_equal S( O, 2 )[ 2, 5 ], S( O, 3 )[ 2, 3, 5 ].
898
+ mask( S[ true, false, true ] )
899
+ assert_equal S( I, 2 )[ 2, 5 ], S( I, 3 )[ 2, 3, 5 ].
900
+ mask( S[ true, false, true ] )
901
+ assert_raise( RuntimeError ) { S[ 1, 2 ].mask S[ true ] }
902
+ end
903
+
904
+ def test_unmask
905
+ [ O, I ].each do |t|
906
+ assert_equal S( t, 3 )[ 2, 3, 5 ],
907
+ S( t, 2 )[ 2, 5 ].unmask( S[ true, false, true ], :default => 3 )
908
+ assert_equal S( t, 3 )[ 2, 3, 5 ],
909
+ S( t, 2 )[ 2, 5 ].unmask( S[ true, false, true ],
910
+ :default => S[ 2, 3, 4 ] )
911
+ assert_raise( RuntimeError ) do
912
+ S( t, 1 )[ 1 ].unmask S[ true ], :default => S[ 1, 2 ]
913
+ end
914
+ assert_raise( RuntimeError ) { S( t, 1 )[ 1 ].unmask S[ true, true ] }
915
+ end
916
+ end
917
+
896
918
  end
919
+
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 16
7
+ - 17
8
8
  - 0
9
- version: 0.16.0
9
+ version: 0.17.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jan Wedekind
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-21 00:00:00 +00:00
17
+ date: 2011-01-02 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -77,8 +77,10 @@ files:
77
77
  - lib/multiarray/methods.rb
78
78
  - lib/multiarray/integral.rb
79
79
  - lib/multiarray/multiarray.rb
80
+ - lib/multiarray/unmask.rb
80
81
  - lib/multiarray/node.rb
81
82
  - lib/multiarray/histogram.rb
83
+ - lib/multiarray/mask.rb
82
84
  - lib/multiarray/malloc.rb
83
85
  - lib/multiarray/index.rb
84
86
  - lib/multiarray/rgb.rb