E
en.eric.m
I'll try to keep this as brief as possible. I heard about Ruby on
Rails and thought it was interesting, however, it was a bit hard to
work with without knowing ruby itself. So I've started learning ruby.
I had written a simple java (it was actually so simple it might as well
have been written in c) program to brute force solution to a series of
equations in 3 variables. I decided that recrating the program in ruby
would be a good test of what I had learned so far.
The exact equations aren't really the important point, and I've hard
coded the initial conditions more than would be desireable in a general
purpose solution. However, In terms of producing an accurate solution,
the program does quite well. I've got comments in the code that point
out where I think things are going well and where I wasn't as happy
with the solution I came up with.
I'll take any advice on how to make this program take full advantage of
ruby.
Thanks
# From Java program
# x= 8.48550
# y=-4.42140
# z=-2.90655
# From Ruby program
# x= 8.485481
# y=-4.421231
# z=-2.906773
#This class I'm pretty happy with, but there might be a better way to
get it initialized
class Eq3Var
def initialize(xCo, xPow, yCo, yPow, zCo, zPow, const)
@xCo = xCo.to_f
@yCo = yCo.to_f
@zCo = zCo.to_f
@xPow = xPow.to_f
@yPow = yPow.to_f
@zPow = zPow.to_f
@const = const.to_f
end
def eval (x, y, z)
@xCo * x**@xPow + @yCo * y**@yPow + @zCo * z**@zPow + @const
end
end
class Solver
# I think this method does as good a job of providing the initial
conditions as hard coding them gets
# These starting values are actually strangely lucky. Trying to give
the program a better place to start
# often produces worse results.
def initialize()
@eqs = []
@eqs[0] = Eq3Var.new(1, 1, -1, 1, 1, 1, -10)
@eqs[1] = Eq3Var.new(1, 2, 1, 2, 1, 2, -100)
@eqs[2] = Eq3Var.new(1, 3, 1, 3, 1, 3, -500)
@bestSol = [0.0, 0.0, 0.0]
@range = 10.0
@step = 0.5
@factor = 5.0
end
#this is where things get clunky
#even if you aren't at all interested in math you can see the repeated
code
def force()
puts "Starting best solution: #{@bestSol.join(', ')}"
a = @eqs[0].eval(@bestSol[0], @bestSol[1], @bestSol[2])
b = @eqs[1].eval(@bestSol[0], @bestSol[1], @bestSol[2])
c = @eqs[2].eval(@bestSol[0], @bestSol[1], @bestSol[2])
min = a**2.0 + b**2.0 + c**2.0
xInit = @bestSol[0]
yInit = @bestSol[1]
zInit = @bestSol[2]
i = xInit - @range
j = yInit - @range
k = zInit - @range
while i < xInit + @range
while j < yInit + @range
while k < zInit + @range
a = @eqs[0].eval(i, j, k)
b = @eqs[1].eval(i, j, k)
c = @eqs[2].eval(i, j, k)
t = a**2.0 + b**2.0 + c**2.0
if (t < min)
min = t
@bestSol[0] = i
@bestSol[1] = j
@bestSol[2] = k
#puts "new min #{t}"
end
k = k + @step
end
j = j + @step
k = zInit - @range
end
i = i + @step
j = yInit - @range
k = zInit - @range
end
@range = @range / @factor
@step = @step / @factor
puts "a is #{@eqs[0].eval(@bestSol[0], @bestSol[1], @bestSol[2])} - b
is #{@eqs[1].eval(@bestSol[0], @bestSol[1], @bestSol[2])} - c is
#{@eqs[2].eval(@bestSol[0], @bestSol[1], @bestSol[2])}"
return @bestSol
end
def getRange()
return @range
end
def getStep()
return @step
end
end
mySolver = Solver.new()
# there has got to be a way to itterate over this without having to
create a variable like this
# but the class is taking care of itself without any input from this
loop except for how many times to
# keep looking for a better solution
itr = 0
10.times do
guess = mySolver.force()
r = mySolver.getRange()
s = mySolver.getStep()
itr = itr + 1
puts "In #{itr} itterations, the best solution so far: #{guess.join(',
')}. Refine with range of #{r} and step of #{s}"
end
Rails and thought it was interesting, however, it was a bit hard to
work with without knowing ruby itself. So I've started learning ruby.
I had written a simple java (it was actually so simple it might as well
have been written in c) program to brute force solution to a series of
equations in 3 variables. I decided that recrating the program in ruby
would be a good test of what I had learned so far.
The exact equations aren't really the important point, and I've hard
coded the initial conditions more than would be desireable in a general
purpose solution. However, In terms of producing an accurate solution,
the program does quite well. I've got comments in the code that point
out where I think things are going well and where I wasn't as happy
with the solution I came up with.
I'll take any advice on how to make this program take full advantage of
ruby.
Thanks
# From Java program
# x= 8.48550
# y=-4.42140
# z=-2.90655
# From Ruby program
# x= 8.485481
# y=-4.421231
# z=-2.906773
#This class I'm pretty happy with, but there might be a better way to
get it initialized
class Eq3Var
def initialize(xCo, xPow, yCo, yPow, zCo, zPow, const)
@xCo = xCo.to_f
@yCo = yCo.to_f
@zCo = zCo.to_f
@xPow = xPow.to_f
@yPow = yPow.to_f
@zPow = zPow.to_f
@const = const.to_f
end
def eval (x, y, z)
@xCo * x**@xPow + @yCo * y**@yPow + @zCo * z**@zPow + @const
end
end
class Solver
# I think this method does as good a job of providing the initial
conditions as hard coding them gets
# These starting values are actually strangely lucky. Trying to give
the program a better place to start
# often produces worse results.
def initialize()
@eqs = []
@eqs[0] = Eq3Var.new(1, 1, -1, 1, 1, 1, -10)
@eqs[1] = Eq3Var.new(1, 2, 1, 2, 1, 2, -100)
@eqs[2] = Eq3Var.new(1, 3, 1, 3, 1, 3, -500)
@bestSol = [0.0, 0.0, 0.0]
@range = 10.0
@step = 0.5
@factor = 5.0
end
#this is where things get clunky
#even if you aren't at all interested in math you can see the repeated
code
def force()
puts "Starting best solution: #{@bestSol.join(', ')}"
a = @eqs[0].eval(@bestSol[0], @bestSol[1], @bestSol[2])
b = @eqs[1].eval(@bestSol[0], @bestSol[1], @bestSol[2])
c = @eqs[2].eval(@bestSol[0], @bestSol[1], @bestSol[2])
min = a**2.0 + b**2.0 + c**2.0
xInit = @bestSol[0]
yInit = @bestSol[1]
zInit = @bestSol[2]
i = xInit - @range
j = yInit - @range
k = zInit - @range
while i < xInit + @range
while j < yInit + @range
while k < zInit + @range
a = @eqs[0].eval(i, j, k)
b = @eqs[1].eval(i, j, k)
c = @eqs[2].eval(i, j, k)
t = a**2.0 + b**2.0 + c**2.0
if (t < min)
min = t
@bestSol[0] = i
@bestSol[1] = j
@bestSol[2] = k
#puts "new min #{t}"
end
k = k + @step
end
j = j + @step
k = zInit - @range
end
i = i + @step
j = yInit - @range
k = zInit - @range
end
@range = @range / @factor
@step = @step / @factor
puts "a is #{@eqs[0].eval(@bestSol[0], @bestSol[1], @bestSol[2])} - b
is #{@eqs[1].eval(@bestSol[0], @bestSol[1], @bestSol[2])} - c is
#{@eqs[2].eval(@bestSol[0], @bestSol[1], @bestSol[2])}"
return @bestSol
end
def getRange()
return @range
end
def getStep()
return @step
end
end
mySolver = Solver.new()
# there has got to be a way to itterate over this without having to
create a variable like this
# but the class is taking care of itself without any input from this
loop except for how many times to
# keep looking for a better solution
itr = 0
10.times do
guess = mySolver.force()
r = mySolver.getRange()
s = mySolver.getStep()
itr = itr + 1
puts "In #{itr} itterations, the best solution so far: #{guess.join(',
')}. Refine with range of #{r} and step of #{s}"
end