Module: Hornetseye::Operations
- Included in:
- Node
- Defined in:
- lib/multiarray/complex.rb,
lib/multiarray/operations.rb,
lib/multiarray/rgb.rb
Class Method Summary collapse
- .define_binary_op(op, coercion = :coercion) ⇒ Object
- .define_unary_op(op, conversion = :contiguous) ⇒ Object
Instance Method Summary collapse
- #+@ ⇒ Object
- #<=>(other) ⇒ Object
- #b=(value) ⇒ Object
- #b_with_decompose ⇒ Object
- #collect(&action) ⇒ Object (also: #map)
- #conditional(a, b) ⇒ Object
-
#convolve(filter) ⇒ Node
Convolution with other array of same dimension.
-
#diagonal(initial = nil, options = {}) { ... } ⇒ Node
Apply accumulative operation over elements diagonally.
-
#eq_with_multiarray(other) ⇒ Boolean
Equality operator.
- #fill!(value = typecode.default) ⇒ Object
- #g=(value) ⇒ Object
- #g_with_decompose ⇒ Object
- #histogram(*ret_shape) ⇒ Object
- #imag=(value) ⇒ Object
- #imag_with_decompose ⇒ Object
- #inject(initial = nil, options = {}) ⇒ Object
-
#integral ⇒ Object
alias_method_chain :lut, :composite.
-
#lut(table, options = {}) ⇒ Object
alias_method_chain :histogram, :composite.
- #max ⇒ Object
- #min ⇒ Object
- #normalise(range = 0 .. 0xFF) ⇒ Object
-
#product(filter) ⇒ Node
Compute product table from two arrays.
- #r=(value) ⇒ Object
- #r_with_decompose ⇒ Object
- #range ⇒ Object
- #real=(value) ⇒ Object
- #real_with_decompose ⇒ Object
- #roll(n = 1) ⇒ Object
- #sum ⇒ Object
- #to_type(dest) ⇒ Object
- #to_type_with_rgb(dest) ⇒ Object
-
#transpose(*order) ⇒ Node
Lazy transpose of array.
- #unroll(n = 1) ⇒ Object
Class Method Details
.define_binary_op(op, coercion = :coercion) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/multiarray/operations.rb', line 37 def define_binary_op( op, coercion = :coercion ) define_method( op ) do |other| unless other.is_a? Node other = Node.match( other, typecode ).new other end if dimension == 0 and variables.empty? and other.dimension == 0 and other.variables.empty? target = array_type.send coercion, other.array_type target.new simplify.get.send( op, other.simplify.get ) else Hornetseye::ElementWise( lambda { |x,y| x.send op, y }, op, lambda { |t,u| t.send coercion, u } ). new( self, other ).force end end end |
.define_unary_op(op, conversion = :contiguous) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/multiarray/operations.rb', line 22 def define_unary_op( op, conversion = :contiguous ) define_method( op ) do if dimension == 0 and variables.empty? target = typecode.send conversion target.new simplify.get.send( op ) else Hornetseye::ElementWise( lambda { |x| x.send op }, op, lambda { |t| t.send conversion } ). new( self ).force end end end |
Instance Method Details
#+@ ⇒ Object
90 91 92 |
# File 'lib/multiarray/operations.rb', line 90 def +@ self end |
#<=>(other) ⇒ Object
140 141 142 143 144 |
# File 'lib/multiarray/operations.rb', line 140 def <=>( other ) Hornetseye::lazy do ( self < other ).conditional -1, ( self > other ).conditional( 1, 0 ) end end |
#b=(value) ⇒ Object
518 519 520 521 522 523 524 525 526 527 528 |
# File 'lib/multiarray/rgb.rb', line 518 def b=( value ) if typecode < RGB_ decompose( 2 )[] = value elsif typecode == OBJECT self[] = Hornetseye::lazy do r * RGB.new( 1, 0, 0 ) + g * RGB.new( 0, 1, 0 ) + value * RGB.new( 0, 0, 1 ) end else raise "Cannot assign blue channel to object of type #{array_type.inspect}" end end |
#b_with_decompose ⇒ Object
506 507 508 509 510 511 512 513 514 |
# File 'lib/multiarray/rgb.rb', line 506 def b_with_decompose if typecode == OBJECT or is_a?( Variable ) b_without_decompose elsif typecode < RGB_ decompose 2 else self end end |
#collect(&action) ⇒ Object Also known as: map
185 186 187 188 189 190 |
# File 'lib/multiarray/operations.rb', line 185 def collect( &action ) var = Variable.new typecode block = action.call var conversion = lambda { |t| t.to_type action.call( Variable.new( t.typecode ) ) } Hornetseye::ElementWise( action, block.to_s, conversion ).new( self ).force end |
#conditional(a, b) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/multiarray/operations.rb', line 121 def conditional( a, b ) unless a.is_a? Node a = Node.match( a, b.is_a?( Node ) ? b : nil ).new a end unless b.is_a? Node b = Node.match( b, a.is_a?( Node ) ? a : nil ).new b end if dimension == 0 and variables.empty? and a.dimension == 0 and a.variables.empty? and b.dimension == 0 and b.variables.empty? target = array_type.cond a.array_type, b.array_type target.new simplify.get.conditional( a.simplify.get, b.simplify.get ) else Hornetseye::ElementWise( lambda { |x,y,z| x.conditional y, z }, :conditional, lambda { |t,u,v| t.cond u, v } ). new( self, a, b ).force end end |
#convolve(filter) ⇒ Node
Convolution with other array of same dimension
353 354 355 356 |
# File 'lib/multiarray/operations.rb', line 353 def convolve( filter ) filter = Node.match( filter, typecode ).new filter unless filter.is_a? Node product( filter ).diagonal { |s,x| s + x } end |
#diagonal(initial = nil, options = {}) { ... } ⇒ Node
Apply accumulative operation over elements diagonally
This method is used internally to implement convolutions.
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/multiarray/operations.rb', line 297 def diagonal( initial = nil, = {} ) if dimension == 0 demand else if initial unless initial.is_a? Node initial = Node.match( initial ).new initial end initial_typecode = initial.typecode else initial_typecode = typecode end index0 = Variable.new Hornetseye::INDEX( nil ) index1 = Variable.new Hornetseye::INDEX( nil ) index2 = Variable.new Hornetseye::INDEX( nil ) var1 = [ :var1 ] || Variable.new( initial_typecode ) var2 = [ :var2 ] || Variable.new( typecode ) block = [ :block ] || yield( var1, var2 ) value = element( index1 ).element( index2 ). diagonal initial, :block => block, :var1 => var1, :var2 => var2 term = Diagonal.new( value, index0, index1, index2, initial, block, var1, var2 ) index0.size[] ||= index1.size[] Lambda.new( index0, term ).force end end |
#eq_with_multiarray(other) ⇒ Boolean
Equality operator
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/multiarray/operations.rb', line 221 def eq_with_multiarray( other ) if other.is_a? Node if variables.empty? if other.array_type == array_type Hornetseye::eager { eq( other ).inject( true ) { |a,b| a.and b } } else false end else eq_without_multiarray other end else false end end |
#fill!(value = typecode.default) ⇒ Object
276 277 278 279 |
# File 'lib/multiarray/operations.rb', line 276 def fill!( value = typecode.default ) self[] = value self end |
#g=(value) ⇒ Object
494 495 496 497 498 499 500 501 502 503 504 |
# File 'lib/multiarray/rgb.rb', line 494 def g=( value ) if typecode < RGB_ decompose( 1 )[] = value elsif typecode == OBJECT self[] = Hornetseye::lazy do r * RGB.new( 1, 0, 0 ) + value * RGB.new( 0, 1, 0 ) + b * RGB.new( 0, 0, 1 ) end else raise "Cannot assign green channel to object of type #{array_type.inspect}" end end |
#g_with_decompose ⇒ Object
482 483 484 485 486 487 488 489 490 |
# File 'lib/multiarray/rgb.rb', line 482 def g_with_decompose if typecode == OBJECT or is_a?( Variable ) g_without_decompose elsif typecode < RGB_ decompose 1 else self end end |
#histogram(*ret_shape) ⇒ Object
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/multiarray/operations.rb', line 358 def histogram( *ret_shape ) = ret_shape.last.is_a?( Hash ) ? ret_shape.pop : {} = { :target => UINT, :safe => true }.merge if [ :safe ] if shape.first != 1 and ret_shape.size == 1 right = Hornetseye::lazy( 1 ) { |i| self }.unroll else if shape.first != ret_shape.size raise "First dimension of array (#{shape.first}) differs from number of " + "dimensions of histogram (#{ret_shape.size})" end right = self end else right = self end if [ :safe ] for i in 0 ... right.shape.first range = right.roll[ i ].range if range.begin < 0 raise "#{i+1}th dimension of index must be in 0 ... #{ret_shape[i]} " + "(but was #{range.begin})" end if range.end >= ret_shape[ i ] raise "#{i+1}th dimension of index must be in 0 ... #{ret_shape[i]} " + "(but was #{range.end})" end end end left = MultiArray.new [ :target ], *ret_shape left[] = 0 block = Histogram.new left, right if block.compilable? GCCFunction.run block else block.demand end left end |
#imag=(value) ⇒ Object
733 734 735 736 737 738 739 740 741 742 743 |
# File 'lib/multiarray/complex.rb', line 733 def imag=( value ) if typecode < COMPLEX_ decompose( 1 )[] = value elsif typecode == OBJECT self[] = Hornetseye::lazy do real + value * Complex::I end else raise "Cannot assign imaginary values to object of type #{array_type.inspect}" end end |
#imag_with_decompose ⇒ Object
721 722 723 724 725 726 727 728 729 |
# File 'lib/multiarray/complex.rb', line 721 def imag_with_decompose if typecode == OBJECT or is_a?( Variable ) imag_without_decompose elsif typecode < COMPLEX_ decompose 1 else Hornetseye::lazy( *shape ) { typecode.new( 0 ) } end end |
#inject(initial = nil, options = {}) ⇒ Object
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/multiarray/operations.rb', line 194 def inject( initial = nil, = {} ) unless initial.nil? initial = Node.match( initial ).new initial unless initial.is_a? Node initial_typecode = initial.typecode else initial_typecode = typecode end var1 = [ :var1 ] || Variable.new( initial_typecode ) var2 = [ :var2 ] || Variable.new( typecode ) block = [ :block ] || yield( var1, var2 ) if dimension == 0 if initial block.subst( var1 => initial, var2 => self ).simplify else demand end else index = Variable.new Hornetseye::INDEX( nil ) value = element( index ). inject nil, :block => block, :var1 => var1, :var2 => var2 Inject.new( value, index, initial, block, var1, var2 ).force end end |
#integral ⇒ Object
alias_method_chain :lut, :composite
450 451 452 453 454 455 456 457 458 459 |
# File 'lib/multiarray/operations.rb', line 450 def integral left = pointer_type.new block = Integral.new left, self if block.compilable? GCCFunction.run block else block.demand end left end |
#lut(table, options = {}) ⇒ Object
alias_method_chain :histogram, :composite
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/multiarray/operations.rb', line 404 def lut( table, = {} ) = { :safe => true }.merge if [ :safe ] if shape.first != 1 and table.dimension == 1 source = Hornetseye::lazy( 1 ) { |i| self }.unroll else if shape.first > table.dimension raise "First dimension of array (#{shape.first}) is greater than the " + " number of dimensions of LUT (#{table.dimension})" end source = self end else source = self end if [ :safe ] for i in 0 ... source.shape.first range = source.roll[ i ].range if range.begin < 0 raise "#{i+1}th dimension of index must be in 0 ... #{table.shape[i]} " + "(but was #{range.begin})" end offset = table.dimension - source.shape.first if range.end >= table.shape[ i + offset ] raise "#{i+1}th dimension of index must be in 0 ... " + "#{table.shape[ i + offset ]} (but was #{range.end})" end end end if source.dimension <= 1 and variables.empty? result = table ( table.dimension - 1 ).downto( 0 ) do |i| result = result.element source.element( INT.new( i ) ).demand end result else Lut.new( source, table, [ :n ] ).force end end |
#max ⇒ Object
243 244 245 |
# File 'lib/multiarray/operations.rb', line 243 def max inject { |a,b| a.major b } end |
#min ⇒ Object
239 240 241 |
# File 'lib/multiarray/operations.rb', line 239 def min inject { |a,b| a.minor b } end |
#normalise(range = 0 .. 0xFF) ⇒ Object
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/multiarray/operations.rb', line 255 def normalise( range = 0 .. 0xFF ) if range.exclude_end? raise "Normalisation does not support ranges with end value " + "excluded (such as #{range})" end lower, upper = min, max if lower.is_a? RGB or upper.is_a? RGB current = [ lower.r, lower.g, lower.b ].min .. [ upper.r, upper.g, upper.b ].max else current = min .. max end if current.last != current.first factor = ( range.last - range.first ).to_f / ( current.last - current.first ) self * factor + ( range.first - current.first * factor ) else self + ( range.first - current.first ) end end |
#product(filter) ⇒ Node
Compute product table from two arrays
Used internally to implement convolutions.
335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/multiarray/operations.rb', line 335 def product( filter ) filter = Node.match( filter, typecode ).new filter unless filter.is_a? Node if dimension != filter.dimension raise "Filter has #{filter.dimension} dimension(s) but should " + "have #{dimension}" end if dimension == 0 self * filter else Hornetseye::lazy { |i,j| self[j].product filter[i] } end end |
#r=(value) ⇒ Object
470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/multiarray/rgb.rb', line 470 def r=( value ) if typecode < RGB_ decompose( 0 )[] = value elsif typecode == OBJECT self[] = Hornetseye::lazy do value * RGB.new( 1, 0, 0 ) + g * RGB.new( 0, 1, 0 ) + b * RGB.new( 0, 0, 1 ) end else raise "Cannot assign red channel to object of type #{array_type.inspect}" end end |
#r_with_decompose ⇒ Object
458 459 460 461 462 463 464 465 466 |
# File 'lib/multiarray/rgb.rb', line 458 def r_with_decompose if typecode == OBJECT or is_a?( Variable ) r_without_decompose elsif typecode < RGB_ decompose 0 else self end end |
#range ⇒ Object
251 252 253 |
# File 'lib/multiarray/operations.rb', line 251 def range min .. max end |
#real=(value) ⇒ Object
709 710 711 712 713 714 715 716 717 718 719 |
# File 'lib/multiarray/complex.rb', line 709 def real=( value ) if typecode < COMPLEX_ decompose( 0 )[] = value elsif typecode == OBJECT self[] = Hornetseye::lazy do value + imag * Complex::I end else self[] = value end end |
#real_with_decompose ⇒ Object
697 698 699 700 701 702 703 704 705 |
# File 'lib/multiarray/complex.rb', line 697 def real_with_decompose if typecode == OBJECT or is_a?( Variable ) real_without_decompose elsif typecode < COMPLEX_ decompose 0 else self end end |
#roll(n = 1) ⇒ Object
165 166 167 168 169 170 171 172 173 |
# File 'lib/multiarray/operations.rb', line 165 def roll( n = 1 ) if n < 0 unroll -n else order = ( 0 ... dimension ).to_a n.times { order = order[ 1 .. -1 ] + [ order.first ] } transpose *order end end |
#sum ⇒ Object
247 248 249 |
# File 'lib/multiarray/operations.rb', line 247 def sum inject { |a,b| a + b } end |
#to_type(dest) ⇒ Object
94 95 96 97 98 99 100 101 102 103 |
# File 'lib/multiarray/operations.rb', line 94 def to_type( dest ) if dimension == 0 and variables.empty? target = typecode.to_type dest target.new simplify.get else key = "to_#{dest.to_s.downcase}" Hornetseye::ElementWise( lambda { |x| x.to_type dest }, key, lambda { |t| t.to_type dest } ).new( self ).force end end |
#to_type_with_rgb(dest) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/multiarray/operations.rb', line 105 def to_type_with_rgb( dest ) if typecode < RGB_ if dest < FLOAT_ lazy { r * 0.299 + g * 0.587 + b * 0.114 }.to_type dest elsif dest < INT_ lazy { ( r * 0.299 + g * 0.587 + b * 0.114 ).round }.to_type dest else to_type_without_rgb dest end else to_type_without_rgb dest end end |
#transpose(*order) ⇒ Node
Lazy transpose of array
Lazily compute transpose by swapping indices according to the specified order.
154 155 156 157 158 159 160 161 162 163 |
# File 'lib/multiarray/operations.rb', line 154 def transpose( *order ) term = self variables = shape.reverse.collect do |i| var = Variable.new Hornetseye::INDEX( i ) term = term.element var var end.reverse order.collect { |o| variables[o] }. inject( term ) { |retval,var| Lambda.new var, retval } end |
#unroll(n = 1) ⇒ Object
175 176 177 178 179 180 181 182 183 |
# File 'lib/multiarray/operations.rb', line 175 def unroll( n = 1 ) if n < 0 roll -n else order = ( 0 ... dimension ).to_a n.times { order = [ order.last ] + order[ 0 ... -1 ] } transpose *order end end |