Class: Hornetseye::Node

Inherits:
Object show all
Extended by:
BOOL::Match, COMPLEX_::Match, FLOAT_::Match, Field_::Match, INT_::Match, OBJECT::Match, RGB_::Match
Defined in:
lib/multiarray/node.rb,
lib/multiarray/complex.rb,
lib/multiarray/operations.rb,
lib/multiarray/rgb.rb

Overview

Base class for representing native datatypes and operations (terms)

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Field_::Match

align, fit

Methods included from FLOAT_::Match

align, fit

Methods included from OBJECT::Match

align, fit

Methods included from COMPLEX_::Match

align, fit

Methods included from BOOL::Match

fit

Methods included from RGB_::Match

align, fit

Methods included from INT_::Match

fit

Class Method Details

.===(other) ⇒ Boolean

Category operator

Returns:

  • (Boolean)

    Check for equality or kind.



233
234
235
# File 'lib/multiarray/node.rb', line 233

def ===( other )
  ( other == self ) or ( other.is_a? self ) or ( other.class == self )
end

.basetypeClass

Base type of this data type

Returns:

  • (Class)

    Returns element_type.



74
75
76
# File 'lib/multiarray/node.rb', line 74

def basetype
  self
end

.boolClass

Get corresponding boolean-based datatype

Returns:

  • (Class)

    Returns BOOL.



127
128
129
# File 'lib/multiarray/node.rb', line 127

def bool
  BOOL
end

.byteClass

Convert to type based on bytes

Returns:

  • (Class)

    Corresponding type based on bytes.



189
190
191
# File 'lib/multiarray/node.rb', line 189

def byte
  BYTE
end

.coercion_bool(other) ⇒ Class

Get boolean-based datatype for binary operation

Returns:

  • (Class)

    Returns BOOL.



148
149
150
# File 'lib/multiarray/node.rb', line 148

def coercion_bool( other )
  other.coercion( self ).bool
end

.coercion_byte(other) ⇒ Class

Get byte-based datatype for binary operation

Parameters:

  • other (Class)

    The other type.

Returns:

  • (Class)

    Returns type based on bytes.



198
199
200
# File 'lib/multiarray/node.rb', line 198

def coercion_byte( other )
  coercion( other ).byte
end

.coercion_maxint(other) ⇒ Class

Get maximum integer based datatype for binary operation

Returns:

  • (Class)

    Returns type based on maximum integer.



164
165
166
# File 'lib/multiarray/node.rb', line 164

def coercion_maxint( other )
  coercion( other ).maxint
end

.compilable?Boolean

Check whether this term is compilable

Returns:

  • (Boolean)

    Returns true.



268
269
270
# File 'lib/multiarray/node.rb', line 268

def compilable?
  true
end

.cond(a, b) ⇒ Class

Get byte-based datatype for ternary operation

Parameters:

  • a (Class)

    The second type.

  • a (Class)

    The third type.

Returns:

  • (Class)

    Returns type based on bytes.



208
209
210
# File 'lib/multiarray/node.rb', line 208

def cond(a, b)
  a.coercion b
end

.define_binary_op(op, coercion = :coercion) ⇒ Proc

Meta-programming method to define a binary operation

Parameters:

  • op (Symbol, String)

    Name of binary operation.

  • conversion (Symbol, String)

    Name of method for type conversion.

Returns:

  • (Proc)

    The new method.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/multiarray/operations.rb', line 56

def define_binary_op(op, coercion = :coercion)
  define_method op do |other|
    other = Node.match(other, typecode).new other unless other.matched?
    if dimension == 0 and variables.empty? and
        other.dimension == 0 and other.variables.empty?
      target = typecode.send coercion, other.typecode
      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(sexp, other.sexp).force
    end
  end
end

.define_unary_op(op, conversion = :identity) ⇒ Proc

Meta-programming method to define a unary operation

Parameters:

  • op (Symbol, String)

    Name of unary operation.

  • conversion (Symbol, String) (defaults to: :identity)

    Name of method for type conversion.

Returns:

  • (Proc)

    The new method.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/multiarray/operations.rb', line 33

def define_unary_op(op, conversion = :identity)
  Node.class_eval do
    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
end

.descriptor(hash) ⇒ String

Get unique descriptor of this class

Parameters:

  • hash (Hash)

    Labels for any variables.

Returns:

  • (String)

    Descriptor of this class.



45
46
47
# File 'lib/multiarray/node.rb', line 45

def descriptor( hash )
  name
end

.dimensionArray<Integer>

Get dimension of this term

Returns:

  • (Array<Integer>)

    Returns 0.



104
105
106
# File 'lib/multiarray/node.rb', line 104

def dimension
  0
end

.finalised?Boolean

Check whether objects of this class are finalised computations

Returns:

  • (Boolean)

    Returns true.



277
278
279
# File 'lib/multiarray/node.rb', line 277

def finalised?
  true
end

.floatClass

Convert to type based on floating point numbers

Returns:

  • (Class)

    Corresponding type based on floating point numbers.



173
174
175
# File 'lib/multiarray/node.rb', line 173

def float
  DFLOAT
end

.float_scalarClass

Get corresponding type based on floating-point scalars

Returns:

  • (Class)

    Corresponding type based on floating-point scalars.



141
142
143
# File 'lib/multiarray/node.rb', line 141

def float_scalar
  float.scalar
end

.floating(other) ⇒ Class

Get floating point based datatype for binary operation

Returns:

  • (Class)

    Returns type based on floating point numbers.



180
181
182
# File 'lib/multiarray/node.rb', line 180

def floating( other )
  other.coercion( self ).float
end

.identityClass

Get this data type

Returns:

  • (Class)

    Returns self.



113
114
115
# File 'lib/multiarray/node.rb', line 113

def identity
  self
end

.indgen(offset = 0, increment = 1) ⇒ Object

Generate index array of this type

Parameters:

  • offset (Object) (defaults to: 0)

    First value.

  • offset (Object) (defaults to: 0)

    Increment for consecutive values.

Returns:

  • (Object)

    Returns offset.



97
98
99
# File 'lib/multiarray/node.rb', line 97

def indgen( offset = 0, increment = 1 )
  offset
end

.match(value, context = nil) ⇒ Class

Find matching native datatype to a Ruby value

Parameters:

  • value (Object)

    Value to find native datatype for.

Returns:

  • (Class)

    Matching native datatype.



56
57
58
59
60
# File 'lib/multiarray/node.rb', line 56

def match( value, context = nil )
  retval = fit value
  retval = retval.align context.basetype if context
  retval
end

.maxintClass

Get corresponding maximal integer type

Returns:

  • (Class)

    Returns self.



157
158
159
# File 'lib/multiarray/node.rb', line 157

def maxint
  self
end

.rgb?Boolean

Check whether this object is an RGB value

Returns:

  • (Boolean)

    Returns false.



120
121
122
# File 'lib/multiarray/node.rb', line 120

def rgb?
  false
end

.scalarClass

Get corresponding scalar type

Returns:

  • (Class)

    Returns self.



134
135
136
# File 'lib/multiarray/node.rb', line 134

def scalar
  self
end

.shapeObject



87
88
89
# File 'lib/multiarray/node.rb', line 87

def shape
  []
end

.stripArray<Array,Node>

Strip of all values

Split up into variables, values, and a term where all values have been replaced with variables.

values, and the term based on variables.

Returns:



246
247
248
# File 'lib/multiarray/node.rb', line 246

def strip
  return [], [], self
end

.subst(hash) ⇒ Node

Substitute variables

Substitute the variables with the values given in the hash.

Parameters:

  • hash (Hash)

    Substitutions to apply.

Returns:

  • (Node)

    Term with substitutions applied.



259
260
261
# File 'lib/multiarray/node.rb', line 259

def subst( hash )
  hash[ self ] || self
end

.to_sString

Get unique descriptor of this class

The method calls descriptor( {} ).

Returns:

  • (String)

    Descriptor of this class.

See Also:



34
35
36
# File 'lib/multiarray/node.rb', line 34

def to_s
  descriptor( {} )
end

.to_type(dest) ⇒ Class

Convert to different element type

Parameters:

  • dest (Class)

    Element type to convert to.

Returns:

  • (Class)

    Type based on the different element type.



217
218
219
# File 'lib/multiarray/node.rb', line 217

def to_type( dest )
  dest
end

.typecodeClass

Element-type of this term

Returns:

  • (Class)

    Element-type of this datatype.



65
66
67
# File 'lib/multiarray/node.rb', line 65

def typecode
  self
end

.typecodesArray<Class>

Get list of types of composite type

Returns:

  • (Array<Class>)

    List of types.



83
84
85
# File 'lib/multiarray/node.rb', line 83

def typecodes
  [ self ]
end

.variablesSet

Get variables contained in this datatype

Returns:

  • (Set)

    Returns Set[].



226
227
228
# File 'lib/multiarray/node.rb', line 226

def variables
  Set[]
end

Instance Method Details

#+@Node

This operation has no effect

Returns:

  • (Node)

    Returns self.



112
113
114
# File 'lib/multiarray/operations.rb', line 112

def +@
  self
end

#<=>(other) ⇒ Node

Element-wise comparison of values

Parameters:

  • other (Node)

    Array with values to compare with.

Returns:

  • (Node)

    Array with results.



261
262
263
264
265
# File 'lib/multiarray/operations.rb', line 261

def <=>(other)
  Hornetseye::lazy do
    (self < other).conditional -1, (self > other).conditional(1, 0)
  end.force
end

#[](*indices) ⇒ Object, Node

Retrieve value of array element(s)

Parameters:

  • *indices (Array<Integer>)

    Index/indices to select element.

Returns:

  • (Object, Node)

    Value of array element or a sub-element.



549
550
551
552
553
554
555
556
557
558
559
560
# File 'lib/multiarray/node.rb', line 549

def []( *indices )
  if indices.empty?
    force
  else
    if indices.last.is_a? Range
      view = slice indices.last.min, indices.last.size
    else
      view = element indices.last
    end
    view[ *indices[ 0 ... -1 ] ]
  end
end

#[]=(*indices, value) ⇒ Object, Node

Assign value to array element(s)

Assign a value to an element of an array

Parameters:

  • *indices (Array<Integer>)

    Index/indices to select the element.

  • value (Object, Node)

    Ruby object with new value.

Returns:



595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
# File 'lib/multiarray/node.rb', line 595

def []=( *indices )
  value = indices.pop
  value = typecode.new value unless value.matched?
  if indices.empty?
    check_shape value
    unless compilable? and value.compilable? and dimension > 0
      Store.new(self, value.sexp).demand
    else
      GCCFunction.run Store.new(self, value.sexp)
    end
    value
  else
    if indices.last.is_a? Range
      view = slice indices.last.min, indices.last.size
    else
      view = element indices.last
    end
    view[*indices[0 ... -1]] = value
  end
end

#allocateObject



287
288
289
# File 'lib/multiarray/node.rb', line 287

def allocate
  Hornetseye::MultiArray(typecode, dimension).new *shape
end

#b=(value) ⇒ Object

Assignment for blue channel values of RGB array

Parameters:

  • Value (Object)

    or array of values to assign to blue channel.

Returns:



612
613
614
615
616
617
618
619
620
621
622
# File 'lib/multiarray/rgb.rb', line 612

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 elements of type #{typecode.inspect}"
  end
end

#b_with_decomposeNode

Fast extraction for blue channel of RGB array

Returns:

  • (Node)

    Array with blue channel.



595
596
597
598
599
600
601
602
603
# File 'lib/multiarray/rgb.rb', line 595

def b_with_decompose
  if typecode == OBJECT or is_a?(Variable) or Thread.current[:lazy]
    b_without_decompose
  elsif typecode < RGB_
    decompose 2
  else
    self
  end
end

#basetypeClass

Base-type of this term

Returns:

  • (Class)

    Base-type of this datatype.



301
302
303
# File 'lib/multiarray/node.rb', line 301

def basetype
  self.class.basetype
end

#between?(a, b) ⇒ Node

Check values against boundaries

Returns:

  • (Node)

    Boolean array with result.



436
437
438
# File 'lib/multiarray/operations.rb', line 436

def between?( a, b )
  Hornetseye::lazy { ( self >= a ).and self <= b }.force
end

#check_shape(*args) ⇒ Object

Check arguments for compatible shape

The method will throw an exception if one of the arguments has an incompatible shape.

Parameters:

  • args (Array<Class>)

    Arguments to check for compatibility.

Returns:

  • (Object)

    The return value should be ignored.



570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
# File 'lib/multiarray/node.rb', line 570

def check_shape(*args)
  _shape = shape
  args.each do |arg|
    _arg_shape = arg.shape
    if _shape.size < _arg_shape.size
      raise "#{arg.inspect} has #{arg.dimension} dimension(s) " +
            "but should not have more than #{dimension}"
    end
    if ( _shape + _arg_shape ).all? { |s| s.is_a? Integer }
      if _shape.last( _arg_shape.size ) != _arg_shape
        raise "#{arg.inspect} has shape #{arg.shape.inspect} " +
              "(does not match last value(s) of #{shape.inspect})"
      end
    end
  end
end

#clip(range = 0 .. 0xFF) ⇒ Node

Clip values to specified range

Parameters:

  • range (Range) (defaults to: 0 .. 0xFF)

    Allowed range of values.

Returns:

  • (Node)

    Array with clipped values.



471
472
473
474
475
476
477
# File 'lib/multiarray/operations.rb', line 471

def clip( range = 0 .. 0xFF )
  if range.exclude_end?
    raise "Clipping does not support ranges with end value " +
          "excluded (such as #{range})"
  end
  collect { |x| x.major( range.begin ).minor range.end }
end

#coerce(other) ⇒ Array<Node>

Coerce with other object

Parameters:

  • other (Object)

    Other object.

Returns:



690
691
692
693
694
695
696
# File 'lib/multiarray/node.rb', line 690

def coerce(other)
  if other.matched?
    return other.sexp, self
  else
    return Node.match(other, self).new(other), self
  end
end

#collect(&action) ⇒ Node Also known as: map

Perform element-wise operation on array

Parameters:

  • action (Proc)

    Operation(s) to perform on elements.

Returns:

  • (Node)

    The resulting array.



321
322
323
324
325
326
# File 'lib/multiarray/operations.rb', line 321

def collect( &action )
  var = Variable.new typecode
  block = action.call var
  conversion = lambda { |t| t.to_type action.call(Variable.new(t.typecode)).typecode }
  Hornetseye::ElementWise( action, block.to_s, conversion ).new( self ).force
end

#compilable?Boolean

Check whether this term is compilable

Returns:

  • (Boolean)

    Returns typecode.compilable?.



531
532
533
# File 'lib/multiarray/node.rb', line 531

def compilable?
  typecode.compilable?
end

#components(options = {}) ⇒ Node

Perform connected component labeling

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :default (Object) — default: typecode.default

    Value of background elements.

  • :target (Class) — default: UINT

    Typecode of labels.

Returns:

  • (Node)

    Array with labels of connected components.



726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
# File 'lib/multiarray/operations.rb', line 726

def components( options = {} )
  if shape.any? { |x| x <= 1 }
    raise "Every dimension must be greater than 1 (shape was #{shape})"
  end
  options = { :target => UINT, :default => typecode.default }.merge options
  target = options[ :target ]
  default = options[ :default ]
  default = typecode.new default unless default.matched?
  left = Hornetseye::MultiArray(target, dimension).new *shape
  labels = Sequence.new target, size; labels[0] = 0
  rank = Sequence.uint size; rank[0] = 0
  n = Hornetseye::Pointer( INT ).new; n.store INT.new( 0 )
  block = Components.new left.sexp, self, default.sexp, target.new(0),
                         labels.sexp, rank.sexp, n
  if block.compilable?
    Hornetseye::GCCFunction.run block
  else
    block.demand
  end
  labels = labels[0 .. n.demand.get]
  left.lut labels.lut(labels.histogram(labels.size, :weight => target.new(1)).
                      minor(1).integral - 1)
end

#conditional(a, b) ⇒ Node

Element-wise conditional selection of values

Parameters:

  • a (Node)

    First array of values.

  • b (Node)

    Second array of values.

Returns:

  • (Node)

    Array with selected values.



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/multiarray/operations.rb', line 212

def conditional(a, b)
  a = Node.match(a, b.matched? ? b : nil).new a unless a.matched?
  b = Node.match(b, a.matched? ? a : nil).new b unless b.matched?
  if dimension == 0 and variables.empty? and
    a.dimension == 0 and a.variables.empty? and
    b.dimension == 0 and b.variables.empty?
    target = typecode.cond a.typecode, b.typecode
    target.new simplify.get.conditional(proc { a.simplify.get },
                                        proc { 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.sexp, b.sexp).force
  end
end

#convolve(filter) ⇒ Node

Convolution with other array of same dimension

Parameters:

  • filter (Node)

    Filter to convolve with.

Returns:

  • (Node)

    Result of convolution.



561
562
563
564
565
566
# File 'lib/multiarray/operations.rb', line 561

def convolve( filter )
  filter = Node.match( filter, typecode ).new filter unless filter.matched?
  array = self
  (dimension - filter.dimension).times { array = array.roll }
  array.table(filter.sexp) { |a,b| a * b }.diagonal { |s,x| s + x }
end

#decompose(i) ⇒ Node

Decompose composite elements

This method decomposes composite elements into array.

Returns:

  • (Node)

    Returns self.



703
704
705
# File 'lib/multiarray/node.rb', line 703

def decompose( i )
  self
end

#demandNode, Object

Reevaluate computation

Returns:

See Also:



645
646
647
# File 'lib/multiarray/node.rb', line 645

def demand
  self
end

#descriptor(hash) ⇒ String

Get unique descriptor of this object

Parameters:

  • hash (Hash)

    Labels for any variables.

Returns:

  • (String)

    Descriptor of this object.



500
501
502
# File 'lib/multiarray/node.rb', line 500

def descriptor( hash )
  'Node()'
end

#diagonal(initial = nil, options = {}) { ... } ⇒ Node

Apply accumulative operation over elements diagonally

This method is used internally to implement convolutions.

Parameters:

  • initial (Object, Node) (defaults to: nil)

    Initial value.

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :var1 (Variable)

    First variable defining operation.

  • :var2 (Variable)

    Second variable defining operation.

  • :block (Variable) — default: yield( var1, var2 )

    The operation to apply diagonally.

Yields:

  • Optional operation to apply diagonally.

Returns:

  • (Node)

    Result of operation.

See Also:



505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
# File 'lib/multiarray/operations.rb', line 505

def diagonal( initial = nil, options = {} )
  if dimension == 0
    demand
  else
    if initial
      initial = Node.match( initial ).new initial unless initial.matched?
      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 = options[ :var1 ] || Variable.new( initial_typecode )
    var2 = options[ :var2 ] || Variable.new( typecode )
    block = options[ :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

#dilate(n = 3) ⇒ Node

Dilation

The dilation operation works on boolean as well as scalar values.

Parameters:

  • n (Integer) (defaults to: 3)

    Size of dilation operator.

Returns:

  • (Node)

    Result of operation.



587
588
589
590
# File 'lib/multiarray/operations.rb', line 587

def dilate( n = 3 )
  filter = Hornetseye::lazy( *( [ n ] * dimension ) ) { 0 }
  table( filter ) { |a,b| a }.diagonal { |m,x| m.major x }
end

#dimensionArray<Integer>

Get dimension of this term

Returns:

  • (Array<Integer>)

    Returns number of dimensions of this term.



386
387
388
# File 'lib/multiarray/node.rb', line 386

def dimension
  shape.size
end

#downsample(*rate, options = {}) ⇒ Node

Downsampling of arrays

Parameters:

  • rate (Array<Integer>)

    The sampling rates for each dimension.

Options Hash (options):

  • :offset (Array<Integer>)

    Sampling offsets for each dimension.

Returns:

  • (Node)

    The downsampled data.



866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
# File 'lib/multiarray/operations.rb', line 866

def downsample( *rate )
  options = rate.last.is_a?( Hash ) ? rate.pop : {}
  options = { :offset => rate.collect { |r| r - 1 } }.merge options
  offset = options[ :offset ]
  if rate.size != dimension
    raise "#{rate.size} sampling rate(s) given but array has " +
          "#{dimension} dimension(s)"
  end
  if offset.size != dimension
    raise "#{offset.size} sampling offset(s) given but array has " +
          "#{dimension} dimension(s)"
  end
  ret_shape = ( 0 ... dimension ).collect do |i|
    ( shape[i] + rate[i] - 1 - offset[i] ).div rate[i]
  end
  field = ( 0 ... dimension ).collect do |i|
    Hornetseye::lazy( *ret_shape ) { |*args| args[i] * rate[i] + offset[i] }
  end
  warp *( field + [ :safe => false ] )
end

#dupNode

Duplicate object

Returns:

  • (Node)

    Duplicate of self.



507
508
509
510
511
# File 'lib/multiarray/node.rb', line 507

def dup
  retval = Hornetseye::MultiArray(typecode, dimension).new *shape
  retval[] = self
  retval
end

#each(&action) ⇒ Object



372
373
374
375
376
377
378
# File 'lib/multiarray/operations.rb', line 372

def each( &action )
  if dimension > 0
    shape.last.times { |i| element( INT.new( i ) ).each &action }
  else
    action.call demand.get
  end
end

#empty?Boolean

Check whether this object is an empty array

Returns:

  • (Boolean)

    Returns whether this object is an empty array.



372
373
374
# File 'lib/multiarray/node.rb', line 372

def empty?
  size == 0
end

#eq_with_multiarray(other) ⇒ Boolean

Equality operator

Returns:

  • (Boolean)

    Returns result of comparison.



383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/multiarray/operations.rb', line 383

def eq_with_multiarray(other)
  if other.matched?
    if variables.empty?
      if other.typecode == typecode and other.shape == shape
        Hornetseye::finalise { eq(other).inject( true ) { |a,b| a.and b } }
      else
        false
      end
    else
      eq_without_multiarray other
    end
  else
    false
  end
end

#erode(n = 3) ⇒ Node

Erosion

The erosion operation works on boolean as well as scalar values.

Parameters:

  • n (Integer) (defaults to: 3)

    Size of erosion operator.

Returns:

  • (Node)

    Result of operation.



575
576
577
578
# File 'lib/multiarray/operations.rb', line 575

def erode( n = 3 )
  filter = Hornetseye::lazy( *( [ n ] * dimension ) ) { 0 }
  table( filter ) { |a,b| a }.diagonal { |m,x| m.minor x }
end

#fill!(value = typecode.default) ⇒ Node

Fill array with a value

Parameters:

  • value (Object) (defaults to: typecode.default)

    Value to fill array with.

Returns:

  • (Node)

    Return self.



484
485
486
487
# File 'lib/multiarray/operations.rb', line 484

def fill!( value = typecode.default )
  self[] = value
  self
end

#finalised?Boolean

Check whether this object is a finalised computation

Returns:

  • (Boolean)

    Returns self.class.finalised?.



540
541
542
# File 'lib/multiarray/node.rb', line 540

def finalised?
  self.class.finalised?
end

#flip(*dimensions) ⇒ Node

Mirror the array

Parameters:

  • dimensions (Array<Integer>)

    The dimensions which should be flipped.

Returns:

  • (Node)

    The result of flipping the dimensions.



808
809
810
811
812
813
814
815
816
817
# File 'lib/multiarray/operations.rb', line 808

def flip( *dimensions )
  field = ( 0 ... dimension ).collect do |i|
    if dimensions.member? i
      Hornetseye::lazy( *shape ) { |*args| shape[i] - 1 - args[i] }
    else
      Hornetseye::lazy( *shape ) { |*args| args[i] }
    end
  end
  warp *( field + [ :safe => false ] )
end

#fmod_with_float(other) ⇒ Node

Modulo operation for floating point numbers

This operation takes account of the problem that ‘%’ does not work with floating-point numbers in C.

Returns:

  • (Node)

    Array with result of operation.



122
123
124
125
126
127
128
129
# File 'lib/multiarray/operations.rb', line 122

def fmod_with_float( other )
  other = Node.match( other, typecode ).new other unless other.matched?
  if typecode < FLOAT_ or other.typecode < FLOAT_
    fmod other
  else
    fmod_without_float other
  end
end

#forceNode, Object

Force delayed computation unless in lazy mode

Returns:

See Also:



656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
# File 'lib/multiarray/node.rb', line 656

def force
  if finalised?
    get
  elsif (dimension > 0 and Thread.current[:lazy]) or not variables.empty?
    self
  elsif compilable?
    retval = allocate
    GCCFunction.run Store.new(retval.sexp, self)
    retval.demand.get
  else
    retval = allocate
    Store.new(retval.sexp, self).demand
    retval.demand.get
  end
end

#g=(value) ⇒ Object

Assignment for green channel values of RGB array

Parameters:

  • Value (Object)

    or array of values to assign to green channel.

Returns:



580
581
582
583
584
585
586
587
588
589
590
# File 'lib/multiarray/rgb.rb', line 580

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 elements of type #{typecode.inspect}"
  end
end

#g_with_decomposeNode

Fast extraction for green channel of RGB array

Returns:

  • (Node)

    Array with green channel.



563
564
565
566
567
568
569
570
571
# File 'lib/multiarray/rgb.rb', line 563

def g_with_decompose
  if typecode == OBJECT or is_a?(Variable) or Thread.current[:lazy]
    g_without_decompose
  elsif typecode < RGB_
    decompose 1
  else
    self
  end
end

#gauss_blur(sigma, max_error = 1.0 / 0x100) ⇒ Node

Gaussian blur

Parameters:

  • sigma (Float)

    Spread of Gauss bell.

  • max_error (Float) (defaults to: 1.0 / 0x100)

    Error of approximated filter.

Returns:

  • (Node)

    Result of filter operation.



611
612
613
614
615
616
617
618
# File 'lib/multiarray/operations.rb', line 611

def gauss_blur( sigma, max_error = 1.0 / 0x100 )
  filter_type = DFLOAT.align typecode
  filter = Sequence[ *Array.gauss_blur_filter( sigma, max_error / dimension ) ].
    to_type filter_type
  ( dimension - 1 ).downto( 0 ).inject self do |retval,i|
    retval.convolve filter
  end
end

#gauss_gradient(sigma, direction, max_error = 1.0 / 0x100) ⇒ Node

Gauss gradient

Parameters:

  • sigma (Float)

    Spread of Gauss gradient.

  • direction (Integer)

    Orientation of Gauss gradient.

  • max_error (Float) (defaults to: 1.0 / 0x100)

    Error of approximated filter.

Returns:

  • (Node)

    Result of filter operation.



627
628
629
630
631
632
633
634
635
636
637
638
639
# File 'lib/multiarray/operations.rb', line 627

def gauss_gradient( sigma, direction, max_error = 1.0 / 0x100 )
  filter_type = DFLOAT.align typecode
  gradient =
    Sequence[ *Array.gauss_gradient_filter( sigma, max_error / dimension ) ].
    to_type filter_type
  blur =
    Sequence[ *Array.gauss_blur_filter( sigma, max_error / dimension ) ].
    to_type filter_type
  ( dimension - 1 ).downto( 0 ).inject self do |retval,i|
    filter = i == direction ? gradient : blur
    retval.convolve filter
  end.force
end

#getNode, Object

Extract native value if this is an element

Returns:



402
403
404
# File 'lib/multiarray/node.rb', line 402

def get
  self
end

#heightInteger

Get height of two-dimensional array

Returns:

  • (Integer)

    Height of array.



315
316
317
# File 'lib/multiarray/node.rb', line 315

def height
  shape[1]
end

#histogram(*ret_shape, options = {}) ⇒ Node

Compute histogram of this array

Parameters:

  • ret_shape (Array<Integer>)

    Dimensions of resulting histogram.

Options Hash (options):

  • :weight (Node) — default: UINT(1)

    Weights for computing the histogram.

  • :safe (Boolean) — default: true

    Do a boundary check before creating the histogram.

Returns:

  • (Node)

    The histogram.



650
651
652
653
654
655
656
657
658
659
660
661
662
# File 'lib/multiarray/operations.rb', line 650

def histogram( *ret_shape )
  options = ret_shape.last.is_a?( Hash ) ? ret_shape.pop : {}
  options = { :weight => UINT.new( 1 ), :safe => true }.merge options
  unless options[:weight].matched?
    options[:weight] = Node.match(options[:weight]).maxint.new options[:weight]
  end
  if ( shape.first != 1 or dimension == 1 ) and ret_shape.size == 1
    [ self ].histogram *( ret_shape + [ options ] )
  else
    ( 0 ... shape.first ).collect { |i| unroll[i] }.
      histogram *( ret_shape + [ options ] )
  end
end

#histogram(*ret_shape, options = {}) ⇒ Node

Compute colour histogram of this array

The array is decomposed to its colour channels and a histogram is computed.

Parameters:

  • ret_shape (Array<Integer>)

    Dimensions of resulting histogram.

Options Hash (options):

  • :weight (Node) — default: Hornetseye::UINT(1)

    Weights for computing the histogram.

  • :safe (Boolean) — default: true

    Do a boundary check before creating the histogram.

Returns:

  • (Node)

    The histogram.



649
650
651
652
653
654
655
# File 'lib/multiarray/rgb.rb', line 649

def histogram_with_rgb( *ret_shape )
  if typecode < RGB_
    [ r, g, b ].histogram *ret_shape
  else
    histogram_without_rgb *ret_shape
  end
end

#if(&action) ⇒ Object

Conditional operation

Parameters:

  • action (Proc)

    Action to perform if condition is true.

Returns:

  • (Object)

    The return value should be ignored.



242
243
244
# File 'lib/multiarray/operations.rb', line 242

def if( &action )
  simplify.get.if &action
end

#if_else(action1, action2) ⇒ Object

Conditional operation

Parameters:

  • action1 (Proc)

    Action to perform if condition is true.

  • action2 (Proc)

    Action to perform if condition is false.

Returns:

  • (Object)

    The return value should be ignored.



252
253
254
# File 'lib/multiarray/operations.rb', line 252

def if_else( action1, action2 )
  simplify.get.if_else action1, action2
end

#imag=(value) ⇒ Object

Assignment for imaginary values of complex array

Parameters:

  • Value (Object)

    or array of values to assign to imaginary components.

Returns:



1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
# File 'lib/multiarray/complex.rb', line 1039

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 elements of type #{typecode.inspect}"
  end
end

#imag_with_decomposeNode

Fast extraction of imaginary values of complex array

Returns:

  • (Node)

    Array with imaginary values.



1022
1023
1024
1025
1026
1027
1028
1029
1030
# File 'lib/multiarray/complex.rb', line 1022

def imag_with_decompose
  if typecode == OBJECT or is_a?(Variable) or Thread.current[:lazy]
    imag_without_decompose
  elsif typecode < COMPLEX_
    decompose 1
  else
    Hornetseye::lazy( *shape ) { typecode.new( 0 ) }
  end
end

#inject(initial = nil, options = {}) ⇒ Object

Perform cummulative operation on array

Parameters:

  • initial (Object) (defaults to: nil)

    Initial value for cummulative operation.

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :var1 (Variable)

    First variable defining operation.

  • :var1 (Variable)

    Second variable defining operation.

  • :block (Variable) — default: yield( var1, var2 )

    The operation to apply.

Returns:

  • (Object)

    Result of injection.



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/multiarray/operations.rb', line 344

def inject( initial = nil, options = {} )
  unless initial.nil?
    initial = Node.match( initial ).new initial unless initial.matched?
    initial_typecode = initial.typecode
  else
    initial_typecode = typecode
  end
  var1 = options[ :var1 ] || Variable.new( initial_typecode )
  var2 = options[ :var2 ] || Variable.new( typecode )
  block = options[ :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
    value = typecode.new value unless value.matched?
    if initial.nil? and index.size.get == 0
      raise "Array was empty and no initial value for injection was given"
    end
    Inject.new( value, index, initial, block, var1, var2 ).force
  end
end

#inspect(indent = nil, lines = nil) ⇒ String

Display information about this object

Returns:

  • (String)

    String with information about this object.



424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/multiarray/node.rb', line 424

def inspect( indent = nil, lines = nil )
  if variables.empty?
    if dimension == 0 and not indent
      "#{typecode.inspect}(#{force.inspect})"
    else
      if indent
        prepend = ''
      else
        prepend = "#{Hornetseye::MultiArray(typecode, dimension).inspect}:\n"
        indent = 0
        lines = 0
      end
      if empty?
        retval = '[]'
      else
        retval = '[ '
        for i in 0 ... shape.last
          x = element i
          if x.dimension > 0
            if i > 0
              retval += ",\n  "
              lines += 1
              if lines >= 10
                retval += '...' if indent == 0
                break
              end
              retval += '  ' * indent
            end
            str = x.inspect indent + 1, lines
            lines += str.count "\n"
            retval += str
            if lines >= 10
              retval += '...' if indent == 0
              break
            end
          else
            retval += ', ' if i > 0
            str = x.force.inspect
            if retval.size + str.size >= 74 - '...'.size -
                '[  ]'.size * indent.succ
              retval += '...'
              break
            else
              retval += str
            end
          end
        end
        retval += ' ]' unless lines >= 10
      end
      prepend + retval
    end
  else
    to_s
  end
end

#integralNode

Compute integral image

Returns:

  • (Node)

    The integral image of this array.



709
710
711
712
713
714
715
716
717
718
# File 'lib/multiarray/operations.rb', line 709

def integral
  left = allocate
  block = Integral.new left.sexp, self
  if block.compilable?
    GCCFunction.run block
  else
    block.demand
  end
  left
end

#lut(table, options = {}) ⇒ Node

Perform element-wise lookup

Parameters:

  • table (Node)

    The lookup table (LUT).

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :safe (Boolean) — default: true

    Do a boundary check before creating the element-wise lookup.

Returns:

  • (Node)

    The result of the lookup operation.



671
672
673
674
675
676
677
# File 'lib/multiarray/operations.rb', line 671

def lut( table, options = {} )
  if ( shape.first != 1 or dimension == 1 ) and table.dimension == 1
    [ self ].lut table, options
  else
    ( 0 ... shape.first ).collect { |i| unroll[i] }.lut table, options
  end
end

#lut_with_rgb(table, options = {}) ⇒ Node

Perform element-wise lookup with colour values

Parameters:

  • table (Node)

    The lookup table (LUT).

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :safe (Boolean) — default: true

    Do a boundary check before creating the element-wise lookup.

Returns:

  • (Node)

    The result of the lookup operation.



666
667
668
669
670
671
672
# File 'lib/multiarray/rgb.rb', line 666

def lut_with_rgb( table, options = {} )
  if typecode < RGB_
    [ r, g, b ].lut table, options
  else
    lut_without_rgb table, options
  end
end

#mallocGCCValue

Generate code for memory allocation

Returns:

  • (GCCValue)

    C value referring to result.



233
234
235
# File 'lib/multiarray/operations.rb', line 233

def malloc
  get.malloc 
end

#mask(m) ⇒ Node

Select values from array using a mask

Parameters:

  • m (Node)

    Mask to apply to this array.

Returns:

  • (Node)

    The masked array.



755
756
757
758
759
760
761
762
763
764
765
766
767
768
# File 'lib/multiarray/operations.rb', line 755

def mask( m )
  check_shape m
  left = MultiArray.new typecode, *( shape.first( dimension - m.dimension ) +
                                     [ m.size ] )
  index = Hornetseye::Pointer( INT ).new
  index.store INT.new( 0 )
  block = Mask.new left.sexp, self, m.sexp, index
  if block.compilable?
    GCCFunction.run block
  else
    block.demand
  end
  left[0 ... index[]].roll
end

#matched?Boolean

Returns:

  • (Boolean)


283
284
285
# File 'lib/multiarray/node.rb', line 283

def matched?
  true
end

#max(initial = nil) ⇒ Object

Find maximum value of array

Parameters:

  • initial (Object) (defaults to: nil)

    Only consider values greater than this value.

Returns:

  • (Object)

    Maximum value of array.



415
416
417
# File 'lib/multiarray/operations.rb', line 415

def max( initial = nil )
  inject( initial ) { |a,b| a.major b }
end

#memoriseNode

Duplicate array expression if it is not in row-major format

Returns:

  • (Node)

    Duplicate of array or self.



329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/multiarray/node.rb', line 329

def memorise
  if memory
    contiguous_strides = (0 ... dimension).collect do |i|
      shape[0 ... i].inject(1) { |a,b| a * b }
    end
    if strides == contiguous_strides
      self
    else
      dup
    end
  else
    dup
  end
end

#memoryMalloc, ...

Get memory object

Returns:



347
348
349
# File 'lib/multiarray/node.rb', line 347

def memory
  nil
end

#min(initial = nil) ⇒ Object

Find minimum value of array

Parameters:

  • initial (Object) (defaults to: nil)

    Only consider values less than this value.

Returns:

  • (Object)

    Minimum value of array.



406
407
408
# File 'lib/multiarray/operations.rb', line 406

def min( initial = nil )
  inject( initial ) { |a,b| a.minor b }
end

#normalise(range = 0 .. 0xFF) ⇒ Node

Normalise values of array

Parameters:

  • range (Range) (defaults to: 0 .. 0xFF)

    Target range of normalisation.

Returns:

  • (Node)

    Array with normalised values.



445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/multiarray/operations.rb', line 445

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 )
    collect { |x| x * factor + ( range.first - current.first * factor ) }
  else
    self + ( range.first - current.first )
  end
end

#r=(value) ⇒ Object

Assignment for red channel values of RGB array

Parameters:

  • Value (Object)

    or array of values to assign to red channel.

Returns:



548
549
550
551
552
553
554
555
556
557
558
# File 'lib/multiarray/rgb.rb', line 548

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 elements of type #{typecode.inspect}"
  end
end

#r_with_decomposeNode

Fast extraction for red channel of RGB array

Returns:

  • (Node)

    Array with red channel.



531
532
533
534
535
536
537
538
539
# File 'lib/multiarray/rgb.rb', line 531

def r_with_decompose
  if typecode == OBJECT or is_a?(Variable) or Thread.current[:lazy]
    r_without_decompose
  elsif typecode < RGB_
    decompose 0
  else
    self
  end
end

#range(initial = nil) ⇒ Object

Find range of values of array

Returns:

  • (Object)

    Range of values of array.



429
430
431
# File 'lib/multiarray/operations.rb', line 429

def range( initial = nil )
  min( initial ? initial.min : nil ) .. max( initial ? initial.max : nil )
end

#real=(value) ⇒ Object

Assignment for real values of complex array

Parameters:

  • Value (Object)

    or array of values to assign to real components.

Returns:



1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
# File 'lib/multiarray/complex.rb', line 1007

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_decomposeNode

Fast extraction for real values of complex array

Returns:

  • (Node)

    Array with real values.



990
991
992
993
994
995
996
997
998
# File 'lib/multiarray/complex.rb', line 990

def real_with_decompose
  if typecode == OBJECT or is_a?(Variable) or Thread.current[:lazy]
    real_without_decompose
  elsif typecode < COMPLEX_
    decompose 0
  else
    self
  end
end

#reshape(*ret_shape) ⇒ Node

Get array with same elements but different shape

The method returns an array with the same elements but with a different shape. The desired shape must have the same number of elements.

Parameters:

  • ret_shape (Array<Integer>)

    Desired shape of return value

Returns:

  • (Node)

    Array with desired shape.



197
198
199
200
201
202
203
204
# File 'lib/multiarray/operations.rb', line 197

def reshape(*ret_shape)
  target_size = ret_shape.inject { |a,b| a * b }
  if target_size != size
    raise "Target is of size #{target_size} but should be of size #{size}"
  end
  Hornetseye::MultiArray(typecode, ret_shape.size).
    new *(ret_shape + [:memory => memorise.memory])
end

#rgb?Boolean

Check whether this object is an RGB value

Returns:

  • (Boolean)

    Returns false.



393
394
395
# File 'lib/multiarray/node.rb', line 393

def rgb?
  typecode.rgb?
end

#roll(n = 1) ⇒ Node

Cycle indices of array

Parameters:

  • n (Integer) (defaults to: 1)

    Number of times to cycle indices of array.

Returns:

  • (Node)

    Resulting array expression with different order of indices.



291
292
293
294
295
296
297
298
299
# File 'lib/multiarray/operations.rb', line 291

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

#shapeArray<Integer>

Get shape of this term

Returns:

  • (Array<Integer>)

    Returns [].



379
380
381
# File 'lib/multiarray/node.rb', line 379

def shape
  self.class.shape
end

#shift(*offset) ⇒ Node

Create array with shifted elements

Parameters:

  • offset (Array<Integer>)

    Array with amount of shift for each dimension.

Returns:

  • (Node)

    The result of the shifting operation.



824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
# File 'lib/multiarray/operations.rb', line 824

def shift( *offset )
  if offset.size != dimension
    raise "#{offset.size} offset(s) were given but array has " +
          "#{dimension} dimension(s)"
  end
  retval = Hornetseye::MultiArray(typecode, dimension).new *shape
  target, source, open, close = [], [], [], []
  ( shape.size - 1 ).step( 0, -1 ) do |i|
    callcc do |pass|
      delta = offset[i] % shape[i]
      source[i] = 0 ... shape[i] - delta
      target[i] = delta ... shape[i]
      callcc do |c|
        open[i] = c
        pass.call
      end
      source[i] = shape[i] - delta ... shape[i]
      target[i] = 0 ... delta
      callcc do |c|
        open[i] = c
        pass.call
      end
      close[i].call
    end
  end
  retval[ *target ] = self[ *source ]
  for i in 0 ... shape.size
    callcc do |c|
      close[i] = c
      open[i].call
    end
  end
  retval
end

#simplifyNode, Object

Reevaluate term

Returns:

See Also:



679
680
681
# File 'lib/multiarray/node.rb', line 679

def simplify
  dimension == 0 ? demand.dup : demand
end

#sizeInteger

Get size (number of elements) of this value

Returns:

  • (Integer)

    Returns number of elements of this value.



322
323
324
# File 'lib/multiarray/node.rb', line 322

def size
  shape.inject(1) { |a,b| a * b }
end

#sobel(direction) ⇒ Node

Sobel operator

Parameters:

  • direction (Integer)

    Orientation of Sobel filter.

Returns:

  • (Node)

    Result of Sobel operator.



597
598
599
600
601
602
603
# File 'lib/multiarray/operations.rb', line 597

def sobel( direction )
  ( dimension - 1 ).downto( 0 ).inject self do |retval,i|
    filter = i == direction ? Hornetseye::Sequence(SINT)[1, 0, -1] :
                              Hornetseye::Sequence(SINT)[1, 2,  1]
    Hornetseye::lazy { retval.convolve filter }
  end.force
end

#stride(index) ⇒ Integer, NilClass

Get stride for specific index

Returns:

  • (Integer, NilClass)

    Array stride of this index.



365
366
367
# File 'lib/multiarray/node.rb', line 365

def stride( index )
  nil
end

#stridesArray<Integer>, NilClass

Get strides of array

Returns:



356
357
358
# File 'lib/multiarray/node.rb', line 356

def strides
  nil
end

#stripArray<Array,Node>

Strip of all values

Split up into variables, values, and a term where all values have been replaced with variables.

values, and the term based on variables.

Returns:



634
635
636
# File 'lib/multiarray/node.rb', line 634

def strip
  return [], [], self
end

#subst(hash) ⇒ Node

Substitute variables

Substitute the variables with the values given in the hash.

Parameters:

  • hash (Hash)

    Substitutions to apply.

Returns:

  • (Node)

    Term with substitutions applied.



522
523
524
# File 'lib/multiarray/node.rb', line 522

def subst( hash )
  hash[ self ] || self
end

#sumObject

Compute sum of array

Returns:



422
423
424
# File 'lib/multiarray/operations.rb', line 422

def sum
  Hornetseye::lazy { to_type typecode.maxint }.inject { |a,b| a + b }
end

#swap_rgb_with_scalarNode

Swapping colour channels for scalar values

Returns:

  • (Node)

    Array with swapped colour channels.



627
628
629
630
631
632
633
# File 'lib/multiarray/rgb.rb', line 627

def swap_rgb_with_scalar
  if typecode == OBJECT or typecode < RGB_
    swap_rgb_without_scalar
  else
    self
  end
end

#table(filter, &action) ⇒ Node

Compute table from two arrays

Used internally to implement convolutions and other operations.

Parameters:

  • filter (Node)

    Filter to form table with.

  • action (Proc)

    Operation to make table for.

Returns:

  • (Node)

    Result of operation.

See Also:



542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/multiarray/operations.rb', line 542

def table( filter, &action )
  filter = Node.match( filter, typecode ).new filter unless filter.matched?
  if filter.dimension > dimension
    raise "Filter has #{filter.dimension} dimension(s) but should " +
          "not have more than #{dimension}"
  end
  filter = Hornetseye::lazy( 1 ) { filter } while filter.dimension < dimension
  if filter.dimension == 0
    action.call self, filter
  else
    Hornetseye::lazy { |i,j| self[j].table filter[i], &action }
  end
end

#to_aArray<Object>

Convert to Ruby array of objects

Perform pending computations and convert native array to Ruby array of objects.

Returns:



412
413
414
415
416
417
418
419
# File 'lib/multiarray/node.rb', line 412

def to_a
  if dimension == 0
    force
  else
    n = shape.last
    ( 0 ... n ).collect { |i| element( i ).to_a }
  end
end

#to_sString

Get unique descriptor of this object

The method calls descriptor( {} ).

Returns:

  • (String)

    Descriptor of this object.

See Also:



489
490
491
# File 'lib/multiarray/node.rb', line 489

def to_s
  descriptor( {} )
end

#to_type(dest) ⇒ Node

Convert array elements to different element type

Parameters:

  • dest (Class)

    Element type to convert to.

Returns:

  • (Node)

    Array based on the different element type.



138
139
140
141
142
143
144
145
146
147
# File 'lib/multiarray/operations.rb', line 138

def to_type(dest)
  if dimension == 0 and variables.empty?
    target = typecode.to_type dest
    target.new(simplify.get).simplify
  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_identity(dest) ⇒ Node

Skip type conversion if it has no effect

This operation is a special case handling type conversions to the same type.

Parameters:

  • dest (Class)

    Element type to convert to.

Returns:

  • (Node)

    Array based on the different element type.



179
180
181
182
183
184
185
# File 'lib/multiarray/operations.rb', line 179

def to_type_with_identity( dest )
  if dest == typecode
    self
  else
    to_type_without_identity dest
  end
end

#to_type_with_rgb(dest) ⇒ Node

Convert RGB array to scalar array

This operation is a special case handling colour to greyscale conversion.

Parameters:

  • dest (Class)

    Element type to convert to.

Returns:

  • (Node)

    Array based on the different element type.



156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/multiarray/operations.rb', line 156

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.

Parameters:

  • order (Array<Integer>)

    New order of indices.

Returns:

  • (Node)

    Returns the transposed array.



275
276
277
278
279
280
281
282
283
284
# File 'lib/multiarray/operations.rb', line 275

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

#typecodeClass

Element-type of this term

Returns:

  • (Class)

    Element-type of this datatype.



294
295
296
# File 'lib/multiarray/node.rb', line 294

def typecode
  self.class.typecode
end

#unmask(m, options = {}) ⇒ Node

Distribute values in a new array using a mask

Parameters:

  • m (Node)

    Mask for inverse masking operation.

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :default (Object) — default: typecode.default

    Default value for elements where mask is false.

  • :safe (Boolean) — default: true

    Ensure that the size of this size is sufficient.

Returns:

  • (Node)

    The result of the inverse masking operation.



779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
# File 'lib/multiarray/operations.rb', line 779

def unmask( m, options = {} )
  options = { :safe => true, :default => typecode.default }.merge options
  default = options[:default]
  default = typecode.new default unless default.matched?
  m.check_shape default
  if options[ :safe ]
    if m.to_ubyte.sum > shape.last
      raise "#{m.to_ubyte.sum} value(s) of the mask are true but the last " +
        "dimension of the array for unmasking only has #{shape.last} value(s)"
    end
  end
  left = Hornetseye::MultiArray(typecode, dimension - 1 + m.dimension).
    coercion(default.typecode).new *(shape[1 .. -1] + m.shape)
  index = Hornetseye::Pointer(INT).new
  index.store INT.new(0)
  block = Unmask.new left.sexp, self, m.sexp, index, default.sexp
  if block.compilable?
    GCCFunction.run block
  else
    block.demand
  end
  left
end

#unroll(n = 1) ⇒ Node

Reverse-cycle indices of array

Parameters:

  • n (Integer) (defaults to: 1)

    Number of times to cycle back indices of array.

Returns:

  • (Node)

    Resulting array expression with different order of indices.



306
307
308
309
310
311
312
313
314
# File 'lib/multiarray/operations.rb', line 306

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

#variablesSet

Get variables contained in this object

Returns:

  • (Set)

    Returns Set[].



621
622
623
# File 'lib/multiarray/node.rb', line 621

def variables
  Set[]
end

#warp(*field, options = {}) ⇒ Node

Warp an array

Parameters:

  • ret_shape (Array<Integer>)

    Dimensions of resulting histogram.

Options Hash (options):

  • :default (Object) — default: typecode.default

    Default value for out of range warp vectors.

  • :safe (Boolean) — default: true

    Apply clip to warp vectors.

Returns:

  • (Node)

    The result of the lookup operation.



688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
# File 'lib/multiarray/operations.rb', line 688

def warp( *field )
  options = field.last.is_a?( Hash ) ? field.pop : {}
  options = { :safe => true, :default => typecode.default }.merge options
  if options[ :safe ]
    if field.size > dimension
      raise "Number of arrays for warp (#{field.size}) is greater than the " +
            "number of dimensions of source (#{dimension})"
    end
    Hornetseye::lazy do
      ( 0 ... field.size ).
        collect { |i| ( field[i] >= 0 ).and( field[i] < shape[i] ) }.
        inject { |a,b| a.and b }
    end.conditional Lut.new( *( field + [ self ] ) ), options[ :default ]
  else
    field.lut self, :safe => false
  end
end

#widthInteger

Get width of two-dimensional array

Returns:

  • (Integer)

    Width of array.



308
309
310
# File 'lib/multiarray/node.rb', line 308

def width
  shape[0]
end