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(proc { |x,y| x.send op, y }, op,
                              proc { |t,u| t.send coercion, u } ).
        new(self, other).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(proc { |x| x.send op }, op,
                                proc { |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).demand
    else
      GCCFunction.run Store.new(self, value)
    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.



468
469
470
# File 'lib/multiarray/operations.rb', line 468

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.



503
504
505
506
507
508
509
# File 'lib/multiarray/operations.rb', line 503

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, 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.



324
325
326
327
328
329
# File 'lib/multiarray/operations.rb', line 324

def collect(&action)
  var = Variable.new typecode
  block = action.call var
  conversion = proc { |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.



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

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, self, default, target.new(0),
                         labels, rank, 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(proc { |x,y,z| x.conditional y, z }, :conditional,
                            proc { |t,u,v| t.cond u, v }).
      new(self, a, b).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.



616
617
618
619
620
621
# File 'lib/multiarray/operations.rb', line 616

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) { |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:



560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
# File 'lib/multiarray/operations.rb', line 560

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.



642
643
644
645
# File 'lib/multiarray/operations.rb', line 642

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.



921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
# File 'lib/multiarray/operations.rb', line 921

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



390
391
392
393
394
395
396
# File 'lib/multiarray/operations.rb', line 390

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.



401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/multiarray/operations.rb', line 401

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, :and }
      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.



630
631
632
633
# File 'lib/multiarray/operations.rb', line 630

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.



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

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.



863
864
865
866
867
868
869
870
871
872
# File 'lib/multiarray/operations.rb', line 863

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, self)
    retval.demand.get
  else
    retval = allocate
    Store.new(retval, 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.



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

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.



682
683
684
685
686
687
688
689
690
691
692
693
694
# File 'lib/multiarray/operations.rb', line 682

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.



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

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 = {}, &action) ⇒ Object #inject(initial = nil, symbol) ⇒ Object

Perform cummulative operation on array

Overloads:

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

    Parameters:

    • initial (Object) (defaults to: nil)

      Initial value for cummulative operation.

    Options Hash (options):

    • :var1 (Variable)

      First variable defining operation.

    • :var1 (Variable)

      Second variable defining operation.

    • :block (Variable) — default: action.call(var1, var2)

      The operation to apply.

  • #inject(initial = nil, symbol) ⇒ Object

    Parameters:

    • initial (Object) (defaults to: nil)

      Initial value for cummulative operation.

    • symbol (Symbol, String)

      The operation to apply.

Returns:

  • (Object)

    Result of injection.



351
352
353
354
355
356
357
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
# File 'lib/multiarray/operations.rb', line 351

def inject(*args, &action)
  options = args.last.is_a?(Hash) ? args.pop : {}
  unless action or options[:block]
    unless [1, 2].member? args.size
      raise "Inject expected 1 or 2 arguments but got #{args.size}" 
    end
    initial, symbol = args[-2], args[-1]
    action = proc { |a,b| a.send symbol, b }
  else
    raise "Inject expected 0 or 1 arguments but got #{args.size}" if args.size > 1
    initial = args.empty? ? nil : args.first
  end
  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 ] || action.call( 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.



764
765
766
767
768
769
770
771
772
773
# File 'lib/multiarray/operations.rb', line 764

def integral
  left = allocate
  block = Integral.new left, 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.



726
727
728
729
730
731
732
# File 'lib/multiarray/operations.rb', line 726

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.



810
811
812
813
814
815
816
817
818
819
820
821
822
823
# File 'lib/multiarray/operations.rb', line 810

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, self, m, 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.



433
434
435
# File 'lib/multiarray/operations.rb', line 433

def max( initial = nil )
  inject initial, :major
end

#meanObject

Compute average of array

Returns:



454
455
456
# File 'lib/multiarray/operations.rb', line 454

def mean
  sum / size
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, :*
    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.



424
425
426
# File 'lib/multiarray/operations.rb', line 424

def min( initial = nil )
  inject initial, :minor
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.



477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/multiarray/operations.rb', line 477

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

#prodObject

Compute product of array

Returns:

  • (Object)

    Product of array.



447
448
449
# File 'lib/multiarray/operations.rb', line 447

def prod
  Hornetseye::lazy { to_type typecode.maxint }.inject :*
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.



461
462
463
# File 'lib/multiarray/operations.rb', line 461

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 1, :*
  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.



294
295
296
297
298
299
300
301
302
# File 'lib/multiarray/operations.rb', line 294

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.



879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
# File 'lib/multiarray/operations.rb', line 879

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, :*
end

#sobel(direction) ⇒ Node

Sobel operator

Parameters:

  • direction (Integer)

    Orientation of Sobel filter.

Returns:

  • (Node)

    Result of Sobel operator.



652
653
654
655
656
657
658
# File 'lib/multiarray/operations.rb', line 652

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

#stretch(from = 0 .. 0xFF, to = 0 .. 0xFF) ⇒ Node

Stretch values from one range to another

Parameters:

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

    Target range of values.

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

    Source range of values.

Returns:

  • (Node)

    Array with stretched values.



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
# File 'lib/multiarray/operations.rb', line 517

def stretch(from = 0 .. 0xFF, to = 0 .. 0xFF)
  if from.exclude_end?
    raise "Stretching does not support ranges with end value " +
          "excluded (such as #{from})"
  end
  if to.exclude_end?
    raise "Stretching does not support ranges with end value " +
          "excluded (such as #{to})"
  end
  if from.last != from.first
    factor = (to.last - to.first).to_f / (from.last - from.first)
    collect { |x| ((x - from.first) * factor).major(to.first).minor to.last }
  else
    (self <= from.first).conditional to.first, to.last
  end
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:



440
441
442
# File 'lib/multiarray/operations.rb', line 440

def sum
  Hornetseye::lazy { to_type typecode.maxint }.inject :+
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:



597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/multiarray/operations.rb', line 597

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( proc { |x| x.to_type dest }, key,
                             proc { |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
285
286
287
# File 'lib/multiarray/operations.rb', line 275

def transpose(*order)
  if (0 ... dimension).to_a != order.sort
    raise 'Each array index must be specified exactly once!'
  end
  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.



834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
# File 'lib/multiarray/operations.rb', line 834

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, self, m, index, default
  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.



309
310
311
312
313
314
315
316
317
# File 'lib/multiarray/operations.rb', line 309

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.



743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
# File 'lib/multiarray/operations.rb', line 743

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 :and
    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