multiarray 0.16.0 → 0.17.0

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