class MM::Space

Constants

VERSION

Attributes

adjacent_points_function[W]
boundaries[R]
cost_function[W]
delta[RW]
max_distance[R]
metric[R]
search_klass[RW]

Public Class Methods

new(metric, opts = {}) click to toggle source

Initialization method for MM::Space

metric - Array of MM::Metrics, where each metric corresponds to a dimension

in the MM::Space.

opts - Hash with additional parameters. (default: {})

:delta - The delta of the MM::Search function used in #morph.
  (default: 0.001)
:boundaries - Array of same size as metric containing pairs [low,
  high], which should be the bounding vectors of a given MM::Space.
:adjacent_points_function - Proc to use as the
  adjacent_points_function for MM::Search in #morph.
:cost_function - Proc to use for cost_function for MM::Search in
  #morph.

Returns an MM::Space object

# File lib/mm/space.rb, line 25
def initialize metric, opts = {}
  @metric = metric
  @search_klass = opts[:search_klass] || MM::Search
  @delta = opts[:delta] || 0.001
  @boundaries = opts[:boundaries]
  @adjacent_points_function = opts[:adjacent_points_function]
  @cost_function = opts[:cost_function]
end

Public Instance Methods

adjacent_points_function() click to toggle source

Default adjacent_points_function. It takes all repeated permutations of a given morph.

Returns the adjacent_points_function Proc.

# File lib/mm/space.rb, line 107
def adjacent_points_function
  @adjacent_points_function ||
  ->(current_point) {
    current_point.repeated_permutation(current_point.size)
  }
end
boundaries=(boundaries) click to toggle source
# File lib/mm/space.rb, line 114
def boundaries= boundaries
  @boundaries = boundaries
  self.max_distance = boundaries.zip(@metric).map {|boundary_metric|
    boundary_metric[1].call(*boundary_metric[0])
  }
end
cost_function(start_morph, to) click to toggle source

Default cost_function to use if no other one is specified. Takes the root of the sum of the squares, or the generalized Euclidean distance.

start_morph - morph to begin the morph from. This should be a valid morph in

the space (i.e., not out of bounds), and should also work with MM::Metric.

to - Destination vector. There should be one dimension in the Array for each

element in @metric

Returns a Proc that calculates how much the current difference vector differs from the requested difference vector.

# File lib/mm/space.rb, line 86
def cost_function start_morph, to
  @cost_function ||
  ->(current_point) {
    @metric.zip(to).inject(0) {|memo, x|
      distance = x[0].call(start_morph, current_point)
      unless @boundaries.nil?
        start_to_lowest = x[0].call(start_morph, @boundaries[0][0])
        current_to_lowest = x[0].call(current_point, @boundaries[0][0])
        if start_to_lowest > current_to_lowest
          distance = distance * -1.0
        end
      end
      memo = memo + (distance - x[1]).abs ** 2
    } ** 0.5
  }
end
enter(locals = {}) click to toggle source

Allows for morphing within a given block.

locals - Hash of key-value pairs where the key is the name of the local

variable to be created and the value is the value of that variable. Note
that it actually creates *methods*, rather than *variables*, and that these
methods refer to instance variables that are then removed. It could get
buggy if you were to try to create a variable that was the same name as an
existing method or class variable. (default: {})

block - Block to evaluate within the context of the instance.

Returns the last element returned by the block.

# File lib/mm/space.rb, line 132
def enter locals = {}, &block
  create_local_variables locals
  output = instance_eval &block
  remove_local_variables locals
  output
end
max_distance=(d) click to toggle source
# File lib/mm/space.rb, line 49
def max_distance= d
  if d.respond_to? :each
    # Assign global maxes to each dimension
    d.zip(@metric).each do |distance_and_metric|
      distance_and_metric[1].scale = MM::Scaling.get_global(distance_and_metric[0])
    end

    @max_distance = d
  elsif d.is_a? Numeric
    # Wrap it in an Array so it can be zipped
    self.max_distance = [d]
  else
    raise ArgumentError, "arg to max_distance= must respond_to? #zip or be Numeric"
  end
end
metric=(m) click to toggle source
# File lib/mm/space.rb, line 65
def metric= m
  if m.respond_to? :each
    @metric = m
  elsif m.respond_to? :call
    # Wrap it in an Array so it can be zipped
    self.metric = [m]
  else
    raise ArgumentError, "arg to metric= must respond_to? #each or #call"
  end
end
morph(start_morph, to: nil, current_point: nil) click to toggle source

Morphs to a given point within the space

start_morph - Enumerable object of things to morph from to - Array to morph to, with one element for each dimension

Returns Array of resulting MM::Ratio objects

# File lib/mm/space.rb, line 40
def morph start_morph, to: nil, current_point: nil
  if current_point
    # puts "Finding from #{current_point.map {|r| r.join ' '}}"
    searcher(start_morph, to).find_from_point current_point
  else
    searcher(start_morph, to).find
  end
end

Protected Instance Methods

searcher(start_morph, to) click to toggle source
# File lib/mm/space.rb, line 141
def searcher start_morph, to
  search = @search_klass.new(start_morph)
  search.cost_function = cost_function start_morph, to
  search.adjacent_points_function = adjacent_points_function
  search.delta = @delta
  search
end

Private Instance Methods

create_local_variables(locals) click to toggle source
# File lib/mm/space.rb, line 151
def create_local_variables locals
  locals.each do |name, value|
    define_singleton_method name do 
      value
    end
  end
end
remove_local_variables(locals) click to toggle source
# File lib/mm/space.rb, line 159
def remove_local_variables locals
  locals.each do |name, value|
    self.singleton_class.class_eval do
      remove_method name
    end
  end
end