Anatomizing lua code with lua itself - lua

I have a config file written in lua with kind of a given structure, that later should dynamically create a GUI:
-- Input config file
package.path = '?.fsl;'
require "init"
global_unit(mm) -- Global unit (m, cm, mm)
pickdist(0.001) -- Snap distance
cosys(polar) -- Set system of coordinates
-- Define model name, for filenames etc.
new_model_force(model_name,"from main.fsl")
-- Define FE Control Data
m.hc_min = 95.000 -- Limit demagnetisa > 0:[%]Hc;<0:[kA/m]
m.con_hdcopy = 1.000 -- Hc-copy:Name:auto:0;intact:1; none:-1
m.b_max = 2.200 -- Max Induction [T] in colorgradation
m.b_min = 0.000 -- Move inside: 0 ; Move outside: > 0
pre_models("FE-contr-data");
pre_models("connect_models");
-- Define the Basic Model Parameter
m.tot_num_slot = QS -- Number of slots (>= 1)
m.num_poles = 2 * p -- Number of poles 2p (>= 2)
m.npols_gen = 2*p*mf -- Number of poles simulated (>= 1) --=m.num_poles * m.num_sl_gen / m.tot_num_slot
m.num_slots = QS*mf -- Number of slots in model
m.arm_length = lFe -- Effect. armature length [mm]
m.fc_radius = (Di-delta)/2 -- Radius air-gap center [mm] --=(m.inside_diam-ag)/2
pre_models("basic_modpar");
...
All m.whatever variables belong to the respective pre_models(...) statement below.
The number and names of the variables for each "pre_models(...) - block" are not known sometimes, same applies for the "pre_models(...) - blocks" itself.
GUI should show sth. like:
Tab1 = General settings: global_unit -> mm, pickdist -> 0.001, etc.
Tab2 = FE-contr-data: m.hc_min -> 95.000, m.con_hdcopy -> 1.000, etc.
Tab3 = connect_models:
Tab4 = basic_modpar: m.tot_num_slot -> 36, m.num_poles -> 30, etc.
..where QS = 36 and p = 15 is defined in the file init.
Wish: Code don't have to know the terms "FE-contr-data", global_unit(...) etc.
Any idea how to approach?

I am only answering b/c this answer has no answer so it can be classified as answered.
You need to intercept (using metatable(_G)) access to pre_models() and run the script. Finally, print a serialized m on every invocation of the intercepted version of pre_models().

Related

no method matching logpdf when sampling from uniform distribution

I am trying to use reinforcement learning in julia to teach a car that is constantly being accelerated backwards (but with a positive initial velocity) to apply brakes so that it gets as close to a target distance as possible before moving backwards.
To do this, I am making use of POMDPs.jl and crux.jl which has many solvers (I'm using DQN). I will list what I believe to be the relevant parts of the script first, and then more of it towards the end.
To define the MDP, I set the initial position, velocity, and force from the brakes as a uniform distribution over some values.
#with_kw struct SliderMDP <: MDP{Array{Float32}, Array{Float32}}
x0 = Distributions.Uniform(0., 80.)# Distribution to sample initial position
v0 = Distributions.Uniform(0., 25.) # Distribution to sample initial velocity
d0 = Distributions.Uniform(0., 2.) # Distribution to sample brake force
...
end
My state holds the values of (position, velocity, brake force), and the initial state is given as:
function POMDPs.initialstate(mdp::SliderMDP)
ImplicitDistribution((rng) -> Float32.([rand(rng, mdp.x0), rand(rng, mdp.v0), rand(rng, mdp.d0)]))
end
Then, I set up my DQN solver using crux.jl and called a function to solve for the policy
solver_dqn = DQN(π=Q_network(), S=s, N=30000)
policy_dqn = solve(solver_dqn, mdp)
calling solve() gives me the error MethodError: no method matching logpdf(::Distributions.Categorical{Float64, Vector{Float64}}, ::Nothing). I am quite sure that this comes from the initial state sampling, but I am not sure why or how to fix it. I have only been learning RL from various books and online lectures for a very short time, so any help regarding the error or my the model I set up (or anything else I'm oblivious to) would be appreciated.
More comprehensive code:
Packages:
using POMDPs
using POMDPModelTools
using POMDPPolicies
using POMDPSimulators
using Parameters
using Random
using Crux
using Flux
using Distributions
Rest of it:
#with_kw struct SliderMDP <: MDP{Array{Float32}, Array{Float32}}
x0 = Distributions.Uniform(0., 80.)# Distribution to sample initial position
v0 = Distributions.Uniform(0., 25.) # Distribution to sample initial velocity
d0 = Distributions.Uniform(0., 2.) # Distribution to sample brake force
m::Float64 = 1.
tension::Float64 = 3.
dmax::Float64 = 2.
target::Float64 = 80.
dt::Float64 = .05
γ::Float32 = 1.
actions::Vector{Float64} = [-.1, 0., .1]
end
function POMDPs.gen(env::SliderMDP, s, a, rng::AbstractRNG = Random.GLOBAL_RNG)
x, ẋ, d = s
if x >= env.target
a = .1
end
if d+a >= env.dmax || d+a <= 0
a = 0.
end
force = (d + env.tension) * -1
ẍ = force/env.m
# Simulation
x_ = x + env.dt * ẋ
ẋ_ = ẋ + env.dt * ẍ
d_ = d + a
sp = vcat(x_, ẋ_, d_)
reward = abs(env.target - x) * -1
return (sp=sp, r=reward)
end
function POMDPs.initialstate(mdp::SliderMDP)
ImplicitDistribution((rng) -> Float32.([rand(rng, mdp.x0), rand(rng, mdp.v0), rand(rng, mdp.d0)]))
end
POMDPs.isterminal(mdp::SliderMDP, s) = s[2] <= 0
POMDPs.discount(mdp::SliderMDP) = mdp.γ
mdp = SliderMDP();
s = state_space(mdp); # Using Crux.jl
function Q_network()
layer1 = Dense(3, 64, relu)
layer2 = Dense(64, 64, relu)
layer3 = Dense(64, length(3))
return DiscreteNetwork(Chain(layer1, layer2, layer3), [-.1, 0, .1])
end
solver_dqn = DQN(π=Q_network(), S=s, N=30000) # Using Crux.jl
policy_dqn = solve(solver_dqn, mdp) # Error comes here
Stacktrace:
policy_dqn
MethodError: no method matching logpdf(::Distributions.Categorical{Float64, Vector{Float64}}, ::Nothing)
Closest candidates are:
logpdf(::Distributions.DiscreteNonParametric, !Matched::Real) at C:\Users\name\.julia\packages\Distributions\Xrm9e\src\univariate\discrete\discretenonparametric.jl:106
logpdf(::Distributions.UnivariateDistribution{S} where S<:Distributions.ValueSupport, !Matched::AbstractArray) at deprecated.jl:70
logpdf(!Matched::POMDPPolicies.PlaybackPolicy, ::Any) at C:\Users\name\.julia\packages\POMDPPolicies\wMOK3\src\playback.jl:34
...
logpdf(::Crux.ObjectCategorical, ::Float32)#utils.jl:16
logpdf(::Crux.DistributionPolicy, ::Vector{Float64}, ::Float32)#policies.jl:305
var"#exploration#133"(::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, ::typeof(Crux.exploration), ::Crux.DistributionPolicy, ::Vector{Float64})#policies.jl:302
exploration#policies.jl:297[inlined]
action(::Crux.DistributionPolicy, ::Vector{Float64})#policies.jl:294
var"#exploration#136"(::Crux.DiscreteNetwork, ::Int64, ::typeof(Crux.exploration), ::Crux.MixedPolicy, ::Vector{Float64})#policies.jl:326
var"#step!#173"(::Bool, ::Int64, ::typeof(Crux.step!), ::Dict{Symbol, Array}, ::Int64, ::Crux.Sampler{Main.workspace#2.SliderMDP, Vector{Float32}, Crux.DiscreteNetwork, Crux.ContinuousSpace{Tuple{Int64}}, Crux.DiscreteSpace})#sampler.jl:55
var"#steps!#174"(::Int64, ::Bool, ::Int64, ::Bool, ::Bool, ::Bool, ::typeof(Crux.steps!), ::Crux.Sampler{Main.workspace#2.SliderMDP, Vector{Float32}, Crux.DiscreteNetwork, Crux.ContinuousSpace{Tuple{Int64}}, Crux.DiscreteSpace})#sampler.jl:108
var"#fillto!#177"(::Int64, ::Bool, ::typeof(Crux.fillto!), ::Crux.ExperienceBuffer{Array}, ::Crux.Sampler{Main.workspace#2.SliderMDP, Vector{Float32}, Crux.DiscreteNetwork, Crux.ContinuousSpace{Tuple{Int64}}, Crux.DiscreteSpace}, ::Int64)#sampler.jl:156
solve(::Crux.OffPolicySolver, ::Main.workspace#2.SliderMDP)#off_policy.jl:86
top-level scope#Local: 1[inlined]
Short answer:
Change your output vector to Float32 i.e. Float32[-.1, 0, .1].
Long answer:
Crux creates a Distribution over your network's output values, and at some point (policies.jl:298) samples a random value from it. It then converts this value to a Float32. Later (utils.jl:15) it does a findfirst to find the index of this value in the original output array (stored as objs within the distribution), but because the original array is still Float64, this fails and returns a nothing. Hence the error.
I believe this (converting the sampled value but not the objs array and/or not using approximate equality check i.e. findfirst(isapprox(x), d.objs)) to be a bug in the package, and would encourage you to raise this as an issue on Github.

LUA: Looking for a specific table by its variable

I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!

Lua: Creating tables

I'm attempting to use a table as a means to do two things at once. For example:
s = passengers -- user input
t = {[3] = car, [7] = bus, [24] = plane, [45] = train}
for k,v in ipairs t do
if s = k then
z = v * 10 -- cost per person
end
end
Now this is extremely basic for what I'm trying to do. I have a list of about 12 items that each have their own number. I want to know if I can do what I did above with the table and provide each of the 12 items with their own key value and then use that ? This key value would represent each items particular, unique number. Also, can I then use that key's value in a later equation, such as above?
If your keys are unique, your data structure. The point of a table key is direct access to the corresponding value.
This has the same effect as your loop:
local v = t[s] -- value for s or nil if s is not a key
if v != nil then
z = v * 10
end
(Or, more exactly the same: local v = rawget(t,s) to account for cases where t has an __index metamethod.)
If we can assume that v will never be false (which would cause an error at false * 10) then it can be written more naturally (which skips that error):
local v = t[s]
if v then
z = v * 10
end

Slplit IPv4 address to minimum and maximum range

Using Lua how do I split a given IP address to get the minimum and maximum range for example:
94.19.21.119
I have a csv like this:
18087936,18153471,"AU"
18153472,18219007,"JP"
18219008,18350079,"IN"
18350080,18874367,"CN"
thats read to 3 tables and the csv is min,max,country code:
IPfrom = {}
IPto = {}
IPCountry = {}
they get populated like this:
IPfrom[18087936] = L
IPto[L] = 18153471
IPCountry[L] = "AU"
with L being the line number of the io.read, what Im then trying to do is get the minimum range so I can without looping check if it exists then if it does that key holds the index of the maximum range and if the ip is within the min/max I get the country code. Probably a different way of doing things but the tables are over 100000 entries so looping is taking some time.
Perhaps something like the following will work for you:
--
-- Converts an IPv4 address into its integer value
--
function iptoint(ip)
local ipint = 0
local iter = string.gmatch(ip, "%d+")
for i = 3, 0, -1 do
local piece = tonumber(iter())
if piece == nil or piece < 0 or piece > 255 then
return nil
end
ipint = bit32.bor(ipint, bit32.lshift(piece, 8 * i))
end
return ipint
end
--
-- Looks up an IPv4 address in a multidimensional table, with the entries:
-- {start_address, end_address, country}
-- and returns the matching country
--
function iptocountry(ip, tbl)
local ipint = iptoint(ip)
if ipint == nil then
return nil
end
for _,v in pairs(tbl) do
if ipint >= v[1] and ipint <= v[2] then
return v[3]
end
end
return nil
end
Example usage:
local countries = {
{16777216, 17367039, "US"},
{1578300000, 1678300000, "CAN"}
-- ... rest of entries loaded from CSV file
}
local ip = "94.19.21.119"
print (iptocountry(ip, countries)) -- prints CAN
A hash table (the basic type in Lua) will give you O(N). An array (a table with no holes with indices from someMinAddr to someMaxAddr) will give you O(1), but use a significant amount of memory. A binary search through a properly sorted structured table could give you O(log N), which for 100000 addresses is probably worth the effort. I imagine you could have a structure like this:
IPfrom = {
{line=L1, addFrom=from1, addrTo=to1, c=country1},
{line=L2, addFrom=from2, addrTo=to2, c=country2},
{line=L3, addFrom=from3, addrTo=to3, c=country3},
{line=L4, addFrom=from4, addrTo=to4, c=country4},
...
}
because I don't see the point of separating the to and country fields from the other info, just means more table lookup. Anyways if you really do want to separate them the following is not affected:
-- init:
create table from CSV file
sort IPFrom on addFrom field
-- as many times as required:
function findIP(addr)
is addr smaller than IPfrom[middle].addrTo3?
if yes, is addr smaller than IPfrom[middle of middle]?
etc
end
This is recursive so if you structure it properly you can use tail calls and not worry about stack overflow (;), something like
function findIPRecurs(addr, ipTbl, indxMin, indxMax)
local middle = (indxMin + indxMax )/2
local midAddr = ipTbl[middle].addrFrom
if addr < midAddr then
return findIPRecurs(addr, ipTbl, indxMin, middle)
else if addr > midAddr then
return findIPRecurs(addr, ipTbl, middle, indxMax)
else -- have entry:
return middle
end
end
function findIP(addr)
return findIPRecurs(addr, ipTbl, 1, #ipTbl)
end
I have not tested this so there might be some fixing up to do but you get the idea. This will use the same memory as O(N) method but for large arrays will be considerably faster; much less memory than O(1) method, and probably acceptably slower.

How Lua tables work

I am starting to learn Lua from Programming in Lua (2nd edition)
I didn't understand the following in the book. Its very vaguely explained.
a.) w={x=0,y=0,label="console"}
b.) x={math.sin(0),math.sin(1),math.sin(2)}
c.) w[1]="another field"
d.) x.f=w
e.) print (w["x"])
f.) print (w[1])
g.) print x.f[1]
When I do print(w[1]) after a.), why doesn't it print x=0
What does c.) do?
What is the difference between e.) and print (w.x)?
What is the role of b.) and g.)?
You have to realize that this:
t = {3, 4, "eggplant"}
is the same as this:
t = {}
t[1] = 3
t[2] = 4
t[3] = "eggplant"
And that this:
t = {x = 0, y = 2}
is the same as this:
t = {}
t["x"] = 0
t["y"] = 2
Or this:
t = {}
t.x = 0
t.y = 2
In Lua, tables are not just lists, they are associative arrays.
When you print w[1], then what really matters is line c.) In fact, w[1] is not defined at all until line c.).
There is no difference between e.) and print (w.x).
b.) creates a new table named x which is separate from w.
d.) places a reference to w inside of x. (NOTE: It does not actually make a copy of w, just a reference. If you've ever worked with pointers, it's similar.)
g.) Can be broken up in two parts. First we get x.f which is just another way to refer to w because of line d.). Then we look up the first element of that table, which is "another field" because of line c.)
There's another way of creating keys in in-line table declarations.
x = {["1st key has spaces!"] = 1}
The advantage here is that you can have keys with spaces and any extended ASCII character.
In fact, a key can be literally anything, even an instanced object.
function Example()
--example function
end
x = {[Example] = "A function."}
Any variable or value or data can go into the square brackets to work as a key. The same goes with the value.
Practically, this can replace features like the in keyword in python, as you can index the table by values to check if they are there.
Getting a value at an undefined part of the table will not cause an error. It will just give you nil. The same goes for using undefined variables.
local w = {
--[1] = "another field"; -- will be set this value
--["1"] = nil; -- not save to this place, different with some other language
x = 0;
y = 0;
label = "console";
}
local x = {
math.sin(0);
math.sin(1);
math.sin(2);
}
w[1] = "another field" --
x.f = w
print (w["x"])
-- because x.f = w
-- x.f and w point one talbe address
-- so value of (x.f)[1] and w[1] and x.f[1] is equal
print (w[1])
print ((x.f)[1])
print (x.f[1])
-- print (x.f)[1] this not follows lua syntax
-- only a function's has one param and type of is a string
-- you can use print "xxxx"
-- so you print x.f[1] will occuur error
-- in table you can use any lua internal type 's value to be a key
-- just like
local t_key = {v=123}
local f_key = function () print("f123") end
local t = {}
t[t_key] = 1
t[f_key] = 2
-- then t' key actualy like use t_key/f_key 's handle
-- when you user t[{}] = 123,
-- value 123 related to this no name table {} 's handle

Resources