class Flt::Solver::PSolver

Solver with equation parameters passed in a hash

Example: a simple TVM (Time Value of Money) solver

# ln(x+1)
def lnp1(x)
  v = x + 1
  (v == 1) ? x : (x*ln(v) / (v - 1))
end

tvm = Flt::Solver::PSolver.new(Float.context, Flt.Tolerance(3,:decimals)) do |m, t, m0, pmt, i, p|
  i /= 100
  i /= p
  n = -t
  k = exp(lnp1(i)*n) # (i+1)**n
  # Equation: -m*k = m0 + pmt*(1-k)/i
  m0 + pmt*(Num(1)-k)/i + m*k
end
tvm.default_guesses = 1,2
sol = tvm.root :pmt, :t=>240, :m0=>10000, :m=>0, :i=>3, :p=>12 #, :pmt=>[1,2]
puts sol.inspect # => -55.45975978539105

Public Class Methods

new(*args, &blk) click to toggle source
# File lib/solver/psolver.rb, line 27
def initialize(*args, &blk)
  options = Base.extract_options(*args, &blk)

  @solver_class = options[:solver_class] || RFSecantSolver
  @eqn = options[:equation]
  @vars = Function.parameters(@eqn)
  # alternatively, we could keep @eqn = Function[@eqn] and dispense with @vars

  @default_guesses = options[:default_guesses]

  @context = options[:context]
  @tol = options[:tolerance]
  @solver = nil
end

Public Instance Methods

default_guesses=(*g) click to toggle source
# File lib/solver/psolver.rb, line 42
def default_guesses=(*g)
  @default_guesses = g
  @solver = nil
end
equation_value(v) click to toggle source
# File lib/solver/psolver.rb, line 55
def equation_value(v)
  values = @parameters.merge(@var=>v)
  #@context.math(*values.values_at(*@vars).map{|v| @context.Num(v)}, &@eqn)
  @context.math(*@vars.map{|v| values[v] && @context.Num(values[v])}.compact, &@eqn)
  # equivalent to: @context.math(values, &Function[@eqn]) # which doesn't need @vars
end
root(var, parameters) click to toggle source
# File lib/solver/psolver.rb, line 47
def root(var, parameters)
  init_solver
  @var = var
  @parameters = parameters
  guesses = Array(parameters[var])
  @solver.root *guesses
end

Private Instance Methods

init_solver() click to toggle source
# File lib/solver/psolver.rb, line 63
def init_solver
  this = self
  @solver ||= @solver_class.new(
                context: @context,
                default_guesses: @default_guesses,
                tolerance: @tol
              ) { |v| this.equation_value(v) }
end