class Musicality::Function::Piecewise

Combine functions that are each applicable for a non-overlapping domain.

@author James Tunnell

Attributes

pieces[R]

Public Class Methods

new() click to toggle source

Take an array of points (each point is a two-element array pair) and create a piecewise function to calculate values in-between.

# File lib/musicality/notation/util/piecewise_function.rb, line 12
def initialize
  @pieces = { }
end

Public Instance Methods

==(other) click to toggle source
# File lib/musicality/notation/util/piecewise_function.rb, line 16
def ==(other)
  @pieces == other.pieces
end
add_piece(domain, func) click to toggle source

Add a function piece, which covers the given domain (includes domain start but not the end). @param [Range] domain The function domain. If this overlaps an existing domain,

the existing domain will be split with the non-
overlapping pieces kept and the overlapping old piece
discarded.
# File lib/musicality/notation/util/piecewise_function.rb, line 26
def add_piece domain, func
  
  raise ArgumentError, "domain is not a Range" unless domain.is_a? Range
  raise ArgumentError, "func is not a Function" unless func.is_a? Function
  
  contains_domain_completely = @pieces.select { |d,f| d.include?(domain.begin) && d.include?(domain.end) }
  if contains_domain_completely.any?
    contains_domain_completely.each do |d,f|
      l = d.begin...domain.begin
      if d.exclude_end?
        r = domain.end...d.end
      else
        r = domain.end..d.end
      end
      
      @pieces.delete d
      
      if domain.begin != d.begin
        @pieces[l] = f
      end
      if domain.end == d.end
        @pieces[domain.begin..domain.end] = func
      else
        @pieces[domain.begin...domain.end] = func
        @pieces[r] = f
      end
    end
  else
    delete_completely = @pieces.select { |d,f| domain.include?(d.begin) && domain.include?(d.end) }
    delete_completely.each do |d,f|
      @pieces.delete d
    end
    
    # should only be one
    move_end = @pieces.select { |d,f| domain.include?(d.end) }
    move_end.each do |d,f|
      @pieces.delete d
      @pieces[d.begin...domain.begin] = f
    end
    
    # should only be one
    move_begin = @pieces.select { |d,f| domain.include?(d.begin) }
    move_begin.each do |d,f|
      @pieces.delete d
      if d.exclude_end?
        @pieces[domain.end...d.end] = f
      else
        @pieces[domain.end..d.end] = f
      end
    end
    
    if move_begin.any?
      @pieces[domain.begin...domain.end] = func
    else
      @pieces[domain] = func
    end
  end
end
at(x) click to toggle source

Evaluate the piecewise function by finding a function piece whose domain includes the given independent value.

# File lib/musicality/notation/util/piecewise_function.rb, line 91
def at x
  @pieces.each do |domain, func|
    if domain.include? x
      return func.at(x)
    end
  end
  raise DomainError, "The input #{x} is not in the domain."
end
domain_include?(x) click to toggle source
# File lib/musicality/notation/util/piecewise_function.rb, line 85
def domain_include? x
  !@pieces.keys.detect {|domain| domain.include?(x)}.nil?
end