The program below is a substantial simplification of one that worked but in spite of hours of effort I can't identify why the following bug occurs:
Everything works as expected except that when the line "if behavior[2,0] > t then goright(brain,stimulus) end" is executed, the line "stimulus.each {|n| stimulus[n,0]=0 }" does NOT reset all of the elements of the stimulus vector to 0 as it does otherwise. Instead the "1" placed there by the previous trip through the "for c in (0..$Choices)" remains thereby generating double behaviors (both a left and right turn) when only one is expected. I've commented out everything that I believe is irrelevant yet it still happens.
class Matrix
def []=(i, j, x)
#rows[i][j] = x
end
end #code to allow putting individual elements in matrix at i,j
brain= Matrix[ [90,0,0,0,0,0,0,0,0,0,0],
[0,90,0,10,10,10,10,0,0,0,0],
[0,0,90,10,10,10,10,0,0,0,0] ]
longmem=Matrix[ [90,0,0,0,0,0,0,0,0,0,0],
[0,90,0,10,10,10,10,0,0,0,0],
[0,0,90,10,10,10,10,0,0,0,0] ]
stimulus=Matrix.column_vector([0,0,0,0,0,0,0,0,0,0,0])
behavior=Matrix.column_vector([0,0,0])
t=89 # t=threshold
# decay_rate=2
$Stimmax=10
$Behavmax=2
$Choices=2
# begin defining behavioral methods
def learn(ix, brain, stimulus)
psp=20
for j in (8..$Stimmax)
if brain[ix,j] > 0 then brain[ix,j]+= 20 end #modified hunting for bug
end # for j
end # learn
#def positive_fixer(brain,stimulus,longmem,energy)
# reinf=0.9
# for i in (0..$Behavmax)
# for j in (7..$Stimmax)
# if longmem[i,j]>0 then longmem[i,j]+=(reinf*(brain[i,j]-longmem[i,j])).round end
# end
# end
# learn(0, brain, stimulus)
#end #positive fixer comment out in bug hunt
def goleft(brain,stimulus)
puts " Left Turn"
learn(1,brain,stimulus)
end # def left
def goright(brain,stimulus)
puts " Right Turn"
learn(2,brain,stimulus)
end # def right
# end defining behavioral methods
# begin MAIN PROGRAM
for c in (0..$Choices)
stimulus.each {|n| stimulus[n,0]=0 }
# SET ALL STIMS TO O
puts "Should by all 0s"
stimulus.to_a.each {|r| puts r.inspect} # aid in bug hunt
stimulus[rand(1..2),0]= 1
#add print stimulus vector for debugging
puts "Should by just a single 1"
stimulus.to_a.each {|r| puts r.inspect} # aid in bug hunt
# memory decay
#for i in (0..$Behavmax)
#for j in (7..$Stimmax)
# if brain[i,j]>longmem[i,j] then brain[i,j]+=-(brain[i,j]-longmem[i,j])/decay_rate end
# if brain[i,j]<longmem[i,j] then brain[i,j]+=-1*((brain[i,j]+longmem[i,j])/decay_rate) end
#end #for j
#end #for i
# memory decay commented out in search for bug
behavior=brain*stimulus
if behavior[0,0] > t then positive_fixer(brain, stimulus, longmem, energy) end
if behavior[1,0] > t then goleft(brain,stimulus) end
if behavior[2,0] > t then goright(brain,stimulus) end
end #for c
puts
brain.to_a.each {|r| puts r.inspect}
# end main program```
the line "stimulus.each {|n| stimulus[n,0]=0 }" does NOT reset all of the elements of the stimulus vector to 0 as it does otherwise
One of the way how to reset vector:
require 'matrix'
vector = Matrix.column_vector([1, 2, 3])
# => Matrix[[1], [2], [3]]
vector.each_with_index { |_, i| vector[i, 0] = 0 }
# => Matrix[[0], [0], [0]]
So you need to use each_with_index instead of each
I work on task about schedule and have class and .yml file where i want to retrieve data as "start" point, "end" point, "price" etc. And in my class I have method, where i want to determine if stations equal to user choice:
class Train
require 'yaml'
def initialize(time)
#time = YAML.load_file(time)
end
def calc(begin:, end:)
ary = #time['time']
start = begin
stop = end
res = []
loop do
tmp = ary.find { |h| h['begin'] == start }
break unless tmp
res << tmp
start = tmp['end']
break if start == stop
end
end
end
But it always fails on condition
break unless tmp
For example if write instance variable
a = Train.new("my_path_to yml")
a.calc(begin: ':washington', end: ':tokyo')
It executes nothing. Even if I refactor loop block and write "for" iterator it throw "else" condition:
for i in ary
if i['begin'] == 'washington'
puts "good"
else
puts "no way"
end
end
Here is my .yml file
time:
-
begin: :washington
end: :briston
time: 6
price: 3
-
begin: :briston
end: :dallas
time: 4
price: 2
-
begin: :dallas
end: :tokyo
time: 3.5
price: 3
-
begin: :tokyo
end: :chicago
time: 3.5
price: 3
-
begin: :chicago
end: :dellawer
time: 3.5
price: 3
Thanks in advance!
Try this change, check comments in code:
def calc(begin_:, end_:) # <-- don't call variables begin or end, they are reserved words
ary = #time['time']
start = begin_
stop = end_
res = []
loop do
tmp = ary.find { |h| h['begin'] == start }
break unless tmp
res << tmp
start = tmp['end']
break if start == stop
end
res # <-- return something
end
Call as:
train.calc(begin_: :washington, end_: :tokyo)
#=> [{"begin"=>:washington, "end"=>:briston, "time"=>6, "price"=>3}, {"begin"=>:briston, "end"=>:dallas, "time"=>4, "price"=>2}, {"begin"=>:dallas, "end"=>:tokyo, "time"=>3.5, "price"=>3}]
Take care not messing up strings with symbols.
ary.each do |i| # for i in ary <-- pythonic! :)
if i['begin'] == :washington # <-- should be a symbol to pass, not a string
puts "good"
else
puts "no way"
end
end
I am making a Ruby REPL to be used inside an application. I made code:
a = 1
b = 2
currentScope = []
Kernel.local_variables.each do |var|
currentScope << [var,Kernel.eval(var.to_s)]
end
launchREPL(currentScope)
Inside the REPL, I can execute the following code:
#a #=>1
#a+#b #=>3
Ideally I wouldn't have to write the four lines of code before I launch the REPL, and instead I would like to run them inside the launchREPL function. However this would require access to the previous scope from inside the launchREPL function.
Test1
Most notably I tried:
launchREPL(Kernel)
When I do the following:
def launchREPL(scope)
F = 0
puts scope.local_variables # => [:F]
end
it is apparent that this method is not valid.
Test2
launchREPL(Kernel.binding)
def launchREPL(scope)
Kernel.binding.local_variables #= Error: private method 'local_variables' called for #<Binding>
end
Is there any way to do what I'm trying to do?
Edit: P.S. This is currently the code inside launchREPL:
def launchREPL(scope=nil,winName="Ruby REPL")
# ICM RB file Begin:
puts "\"Starting REPL...\""
__b = binding #Evaluating in a binding, keeps track of local variables
__s = ""
###############################################################################
# SEND INSTANCE VARIABLES TO REPL
###############################################################################
#
#How to prepare scope
# currentScope = []
# Kernel.local_variables.each do |var|
# currentScope << [var,Kernel.eval(var.to_s)]
# end
# launchREPL(currentScope)
if scope != nil
scope.each do |varDef|
__b.instance_variable_set "##{varDef[0].to_s}" , varDef[1]
__b.eval("##{varDef[0].to_s} = __b.instance_variable_get(:##{varDef[0].to_s})")
end
end
# to get instance variables: __b.instance_variable_get(__b.instance_variables[0])
# or better: __b.instance_variable_get(:#pipe1)
#
###############################################################################
bStartup = true
while bStartup || __s != ""
# If startup required skip evaluation step
if !bStartup
#Evaluate command
begin
__ret = __s + "\n>" + __b.eval(__s).to_s
rescue
__ret = __s + "\n> Error: " + $!.to_s
end
puts __ret
else
#REPL is already running
bStartup = false
end
#Read user input & print previous output
__s = WSApplication.input_box(__ret,winName,"")
__s == nil ? __s = "" : nil
end
end
Although what you are trying to achieve is unclear and there are definitely many ways to do it properly, every ruby method might be called with Object#send approach:
def launchREPL(scope)
scope.send :local_variables #⇒ here you go
end
a = 42
launchREPL(binding).include?(:a)
#⇒ true
Sidenote: this is how your “4 lines” are usually written in ruby:
local_variables.map { |var| [var, eval(var.to_s)] }
And this is how they should be written (note Binding#local_variable_get):
local_variables.map { |var| [var, binding.local_variable_get(var)] }
The summing up:
def launchREPL(scope)
vars = scope.send(:local_variables).map do |var|
[var, scope.local_variable_get(var)]
end
# some other code
end
a = 42
launchREPL(binding).to_h[:a]
#⇒ 42
This won’t fit the comment, so I would post it as an answer.
def launchREPL(scope = nil, winName = "Ruby REPL")
puts '"Starting REPL..."'
scope.eval('local_variables').each do |var|
instance_variable_set "##{var}", scope.eval(var.to_s)
end if scope
s = ""
loop do
ret = begin
"#{s}\n> #{eval(s)}"
rescue => e
"#{s}\n> Error: #{e.message}"
end
puts ret
# s = WSApplication.input_box(ret, winName, "")
# break if s.empty?
s = "100 * #a" # remove this line and uncomment 2 above
end
end
a = 42
launchREPL(binding)
This is how your function should be written (I have just make it looking as ruby code.) The above works (currently it has no break at all, but you can see as it’s calculating 4200 infinitely.)
I have a function which gets an array of element, then it iterates over the array, when expected element is found it breaks and return.
The function is this:
def get_expected_element(id:, name:)
# I am sure there are 3 elements got
elem_array = get_all_elements(id)
element = nil
elem_array.each { |elem|
# I see this log
puts "elem = #{elem}"
if elem == name
element = elem
# I see this log too
puts "Found element"
break
end
}
# I see this log too, and program is hanging
puts "=== return ==="
element
end
When I invoke the function, the program is hanging after puts "=== return ===":
service = MyService.new
element_got = service.get_expected_element(id:3, name:"apple")
# I don't see the below log
puts "#{element_got}, I don't see this, why?"
The log in console is this:
elem = orange
elem = apple
Found element
=== return ===
<it is hanging>
I cannot understand why the invoked function doesn't return?
Leaving out MyService I ran this:
def get_expected_element(id:, name:)
# I am sure there are 3 elements got
# elem_array = get_all_elements(id)
elem_array = ["elem1", "apple", "elem3"]
element = nil
elem_array.each { |elem|
# I see this log
puts "elem = #{elem}"
if elem == name
element = elem
# I see this log too
puts "Found element"
break
end
}
# I see this log too, and program is hanging
puts "=== return ==="
element
end
puts get_expected_element(id: 3, name: "apple")
and got this:
elem = elem1
elem = apple
Found element
=== return ===
apple
Your get_expected_element method seems fine.
loop { break } can work fine, but
block = Proc.new { break }
# or
# block = lambda { break }
loop(&block) # => LocalJumpError: break from proc-closure
Is it possible to break in a block variable ?
Update:
A example to explain more:
def odd_loop
i = 1
loop do
yield i
i += 2
end
end
def even_loop
i = 2
loop do
yield i
i += 2
end
end
# This work
odd_loop do |i|
puts i
break if i > 10
end
# This doesn't work
break_greater_10 = Proc.new do |i|
puts i
break if i > 10
end
odd_loop(&break_greater_10) # break from proc-closure (LocalJumpError)
even_loop(&break_greater_10) # break from proc-closure (LocalJumpError)
As my comprehension, Proc.new should work same as block (it can return a function from block), but I don't understand why can't break a loop.
P.S. Sorry for my bad english >~<
To solve this problem you could
raise StopIteration
this worked for me.
To return from a block you can use the next keyword.
def foo
f = Proc.new {next ; p 1}
f.call
return 'hello'
end
puts foo # => 'hello' , without 1