Class: RationalNumber

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/rational_number.rb

Overview

Rational Numbers (tree) in ruby

Read about rational numbers in tree structures here: arxiv.org/pdf/0806.3115v1.pdf

Please note that sibling and child will be identical if you are start at “root” level, with the default values (nv = 0, dv = 1, snv = 1, sdv = 0)

Rational numbers always require a “root” at the bottom of the tree

You can find child values, sibling values, see if a value is parent or child of a given rational number. It is possible to verify child/parent relationships without even checking with a database.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(nv = 0, dv = 1, snv = 1, sdv = 0) ⇒ undefined

Initialize rational number

Parameters:

  • The (Integer)

    nominator value

  • The (Integer)

    denomitaor value

  • The (Integer)

    SNV value

  • The (Integer)

    SDV Value



67
68
69
70
# File 'lib/rational_number.rb', line 67

def initialize(nv = 0, dv = 1, snv = 1, sdv = 0)
  set_values(nv, dv, snv, sdv)
  #super()
end

Instance Attribute Details

#dvObject (readonly)

Returns the value of attribute dv.



17
18
19
# File 'lib/rational_number.rb', line 17

def dv
  @dv
end

#numberObject (readonly)

Returns the value of attribute number.



17
18
19
# File 'lib/rational_number.rb', line 17

def number
  @number
end

#nvObject (readonly)

Returns the value of attribute nv.



17
18
19
# File 'lib/rational_number.rb', line 17

def nv
  @nv
end

#sdvObject (readonly)

Returns the value of attribute sdv.



17
18
19
# File 'lib/rational_number.rb', line 17

def sdv
  @sdv
end

#snvObject (readonly)

Returns the value of attribute snv.



17
18
19
# File 'lib/rational_number.rb', line 17

def snv
  @snv
end

Instance Method Details

#<=>(other) ⇒ Object

Compare to other (Comparable)



22
23
24
25
26
27
28
29
30
31
# File 'lib/rational_number.rb', line 22

def <=>(other)
  return 0 if (@nv === other.nv) and (@dv === other.dv) and (@snv == other.snv) and (@sdv == other.sdv)
  if @number < other.number
    -1
  elsif @number > other.number
    1
  else
    0
  end
end

#child_from_position(_position) ⇒ RationalNumber

Return the child rational number from given position

Parameters:

  • The (Integer)

    position

Returns:



206
207
208
# File 'lib/rational_number.rb', line 206

def child_from_position(_position)
  value_from_parent_and_position(self, _position)
end

#is_child_of?(_parent) ⇒ Boolean

Check if the child is a immediate child of an parent

Parameters:

Returns:

  • (Boolean)

    true if the parent to verify against is the same as the childs parent



217
218
219
220
# File 'lib/rational_number.rb', line 217

def is_child_of?(_parent)
  return false if (self == _parent) or self.root?
  _parent == self.parent
end

#is_descendant_of?(_parent) ⇒ Boolean

Check if the child is a descendant of an parent (at any level)

Parameters:

Returns:

  • (Boolean)

    true if the parent is any parent above in the hierarchy



241
242
243
244
245
246
247
248
249
# File 'lib/rational_number.rb', line 241

def is_descendant_of?(_parent)
  return false if (self == _parent) or self.root?
  verify_parent = self # start with beeing self
  while !verify_parent.root? do
    verify_parent = verify_parent.parent
    return true if _parent == verify_parent
  end
  false
end

#is_parent_of?(_child) ⇒ Boolean

Check if the parent is a immediate parent of a child

Parameters:

Returns:

  • (Boolean)

    true if the parent to verify against is the same as the childs parent



229
230
231
232
# File 'lib/rational_number.rb', line 229

def is_parent_of?(_child)
  return false if self == _child
  _child.is_child_of?(self)
end

#next_siblingRationalNumber

Return the next sibling rational number

Uses this RationalNumber parent values

Returns:

Raises:



158
159
160
161
162
163
164
165
# File 'lib/rational_number.rb', line 158

def next_sibling
  # Raise error in case we are root
  raise RationalNumberIsRootNoSiblingsError if root?

  _parent = self.parent # Get parent already to avoid duplicate calculations
  _position = ((@nv - _parent.nv) / _parent.snv) + 1
  value_from_parent_and_position(_parent, _position)
end

#parentRationalNumber

Returns parent as a rational number

Returns:

Raises:



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/rational_number.rb', line 121

def parent
  raise NoParentRationalNumberIsRootError if root?
  numerator   = @nv
  denominator = @dv
  _parent    = RationalNumber.new
  compare_key  = RationalNumber.new
  # make sure we break if we get root values! (numerator == 0 + denominator == 0)
  while ((compare_key.nv < @nv) && (compare_key.dv < @dv)) && ((numerator > 0) && (denominator > 0))
    div = numerator / denominator
    mod = numerator % denominator
    # set return values to previous values, as they are the parent values
    _parent.set_from_other(compare_key)

    # temporary calculations (needed)
    parent_nv = _parent.nv + (div * _parent.snv)
    parent_dv = _parent.dv + (div * _parent.sdv)

    compare_key.set_values( parent_nv ,  #nv
                            parent_dv ,  #dv
                            parent_nv + _parent.snv, #snv
                            parent_dv + _parent.sdv) #sdv
    numerator = mod
    if (numerator != 0)
      denominator = denominator % mod
      denominator = 1 if denominator == 0
    end
  end
  _parent
end

#positionInteger

Get the calculated postion at the current “level” for this rational number in a “tree”

Returns:

  • (Integer)

    The position



111
112
113
114
# File 'lib/rational_number.rb', line 111

def position
  _parent = self.parent
  ((@nv - _parent.nv) / _parent.snv)
end

#root?Boolean

See if rational number is root

Returns:

  • (Boolean)


102
103
104
# File 'lib/rational_number.rb', line 102

def root?
  (@nv === 0) and (@dv === 1) and (@snv === 1) and (@sdv === 0)
end

#set_from_other(other) ⇒ undefined

Will set the values from another RationalNumber

Parameters:

Returns:

  • (undefined)


95
96
97
# File 'lib/rational_number.rb', line 95

def set_from_other(other)
  set_values(other.nv, other.dv, other.snv, other.sdv)
end

#set_values(nv, dv, snv, sdv) ⇒ Object

Set the values of nv,dv,snv and sdv directly

Parameters:

  • The (Integer)

    nominator value

  • The (Integer)

    denomitaor value

  • The (Integer)

    SNV value

  • The (Integer)

    SDV Value



80
81
82
83
84
85
86
# File 'lib/rational_number.rb', line 80

def set_values(nv, dv, snv, sdv)
  @nv = nv
  @dv = dv
  @snv = snv
  @sdv = sdv
  @number = Float(nv)/Float(dv)
end

#sibling_from_position(_position) ⇒ RationalNumber

Return the sibling rational number from a given position.

Uses this RationalNumber parent values

Parameters:

  • The (Integer)

    position

Returns:

Raises:



176
177
178
179
180
# File 'lib/rational_number.rb', line 176

def sibling_from_position(_position)
  raise RationalNumberIsRootNoSiblingsError if root?
  _parent = self.parent
  value_from_parent_and_position(_parent, _position)
end

#to_hashHash

Convert to Hash

Returns:

  • (Hash)

    hash containing the rational numbers



47
48
49
50
51
52
53
54
55
# File 'lib/rational_number.rb', line 47

def to_hash
  {
    :nv => @nv,
    :dv => @dv,
    :snv => @snv,
    :sdv => @sdv,
    :number => @number
  }
end

#to_sString

Convert to string

Returns:

  • (String)

    String describing the rational number.



38
39
40
# File 'lib/rational_number.rb', line 38

def to_s
  "RationalNumber: number: #{@number} nv: #{@nv} dv: #{@dv} snv: #{@snv} sdv: #{@sdv}"
end

#value_from_parent_and_position(_parent, _position) ⇒ RationalNumber

Return the rational number from parent and position

Parameters:

  • The (RationalNumber)

    parents RationalNumber for a given RationalNumber and the new sibling

  • The (Integer)

    position

Returns:



190
191
192
193
194
195
196
197
# File 'lib/rational_number.rb', line 190

def value_from_parent_and_position(_parent, _position)
  sibling = RationalNumber.new(
    _parent.nv + (_position * _parent.snv), # nv
    _parent.dv + (_position * _parent.sdv), # dv
    _parent.nv + ((_position + 1) * _parent.snv), # snv
    _parent.dv + ((_position + 1) * _parent.sdv)  # sdv
    )
end