summaryrefslogtreecommitdiff
path: root/example.lua
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2025-01-03 12:27:10 -0600
committersanine <sanine.not@pm.me>2025-01-03 12:27:10 -0600
commit8f4210371554f318493f875491159acdb3fedcff (patch)
treeafa529a7817bcd8d83db56be66f9613199edb4b5 /example.lua
parent88a6f54ef3e199f6dfef67f7a6d037f29dd47245 (diff)
implement ddfsmain
Diffstat (limited to 'example.lua')
-rw-r--r--example.lua207
1 files changed, 161 insertions, 46 deletions
diff --git a/example.lua b/example.lua
index 9f4a852..828a2c7 100644
--- a/example.lua
+++ b/example.lua
@@ -3,15 +3,22 @@ local GA = require 'ga'
local data = {}
-local csvFile = io.open('HistoricalData_1735758980544-AAPL.csv')
-local skip = true
+-- local csvFile = io.open('HistoricalData_CRNC.csv')
+local csvFile = io.open('DJI_full_1min.txt')
+local header = true
+local mapping = {}
for line in csvFile:lines() do
- if skip then
- skip = false
+ if header then
+ for lineValue in string.gmatch(line, '[^,]+') do
+ table.insert(mapping, lineValue)
+ end
+ header = false
else
local tbl = {}
+ local i = 1
for lineValue in string.gmatch(line, '[^,]+') do
- table.insert(tbl, lineValue)
+ tbl[mapping[i]] = tonumber(string.match(lineValue, '[^$]+'))
+ i = i+1
end
table.insert(data, tbl)
end
@@ -26,32 +33,119 @@ metaproduction["<arity>"] = { {'0'}, {'1+', '<arity>'} }
local metagrammar = Grammar.createGrammar(metaproduction, {})
+function baseProduction()
+ local production = {}
+ production["<start>"]={{ 'return ','<expr>'}}
+ production["<expr>"]={
+ {'x'}, {'<number>'},
+ -- {'<data>'}, {'<number>'},
+ -- {'<data>'}, {'<number>'},
+ {'(','<expr>','<op>','<expr>',')'}, {'<func>','(','<expr>',')'}
+ }
+ production["<op>"]={ {'+'}, {'-'}, {'*'}, {'/'} }
+ production["<func>"]={ {'math.log'}, {'math.exp'}, {'math.sin'}, {'math.cos'}, {'math.tan'}, }
+ production["<digit>"]={ {'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'} }
+ production["<lowdigit>"]={ {'0'}, {'1'}, {'2'} }
+ production["<data>"]={
+ {'high(','<date>',')'}, {'low(','<date>',')'},
+ -- {'volume(','<date>',')'},
+ {'open(','<date>',')'}, {'close(','<date>',')'}
+ }
+ production["<date>"]={ {'<lowdigit>','<digit>', '<digit>'} }
+ production["<number>"]={ {'0.','<digit>','<digit>','<digit>'} }
+ return production
+end
+
+
+function deepcopy(tbl)
+ local copy = {}
+ for k, v in pairs(tbl) do
+ if type(v) == 'table' then
+ copy[k] = deepcopy(v)
+ else
+ copy[k] = v
+ end
+ end
+ return copy
+end
+
+
+function expandGenome(genome, mainArgs, env)
+ mainArgs = mainArgs or ''
+ env = env or _G
+ local meta, offset = metagrammar:expand(genome)
+ local metafn = assert(loadstring('return function(defun) \n' .. meta .. 'end'))()
+ local fnTbl = {}
+ local defun = function(arity) table.insert(fnTbl, arity) end
+ metafn(defun)
+ local production = baseProduction()
+ for fn, arity in ipairs(fnTbl) do
+ local fnName = string.format("fn%d", fn)
+ local args = {}
+ for i=1,arity do
+ local argName = string.format('arg%d', i)
+ table.insert(args, argName)
+ end
+
+ -- create function body
+ local fnProd = deepcopy(production)
+ local fnPrefix = ' local ' .. fnName .. ' = function('
+ for i=1,#args do
+ table.insert(fnProd["<expr>"], {args[i]})
+ fnPrefix = fnPrefix .. args[i]
+ if i ~= #args then
+ fnPrefix = fnPrefix .. ', '
+ end
+ end
+ fnPrefix = fnPrefix .. ') '
+ local fnGrammar = Grammar.createGrammar(fnProd, {})
+ local fnStr
+ fnStr, offset = fnGrammar:expand(genome, offset)
+ fnStr = fnPrefix .. fnStr .. ' end'
+ fnTbl[fn] = fnStr
+
+ -- add function to production rules
+ local fnExpansion = { fnName, '(' }
+ for i=1,arity do
+ table.insert(fnExpansion, '<expr>')
+ if i ~= arity then
+ table.insert(fnExpansion, ', ')
+ end
+ end
+ table.insert(fnExpansion, ')')
+ table.insert(production["<expr>"], fnExpansion)
+ end
-local production = {}
-production["<start>"]={{'<expr>'}}
-production["<expr>"]={ {'<data>'}, {'<number>'}, {'(','<expr>','<op>','<expr>',')'}, {'<func>','(','<expr>',')'} }
-production["<op>"]={ {'+'}, {'-'}, {'*'}, {'/'} }
-production["<func>"]={ {'math.log'}, {'math.exp'}, {'math.sin'}, {'math.cos'}, {'math.tan'}, }
-production["<digit>"]={ {'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'} }
-production["<lowdigit>"]={ {'0'}, {'1'}, {'2'} }
-production["<data>"]={
- {'high(','<date>',')'}, {'low(','<date>',')'},
- {'volume(','<date>',')'},
- {'open(','<date>',')'}, {'close(','<date>',')'}
-}
-production["<date>"]={ {'<lowdigit>','<digit>', '<digit>'} }
-production["<number>"]={ {'0.','<digit>','<digit>','<digit>'} }
+ -- create main production and compile
+ local grammar = Grammar.createGrammar(production, {})
+ local mainStr = grammar:expand(genome, offset)
+ local funcs = ''
+ for _, fnStr in ipairs(fnTbl) do
+ funcs = funcs .. fnStr .. '\n'
+ end
+ mainStr = 'return function(' .. mainArgs .. ')\n' .. funcs .. ' ' .. mainStr .. '\nend'
+ return mainStr
+end
-local grammar = Grammar.createGrammar(production, {})
+function compileGenome(genome, mainArgs, env)
+ local mainStr = expandGenome(genome, mainArgs, env)
+ -- print(mainStr)
+ local f = assert(loadstring(mainStr))()
+ setfenv(f, env or {})
+ return f
+end
---math.randomseed(0)
-math.randomseed(os.time())
+math.randomseed(0)
+-- math.randomseed(1735920315)
+--local t = os.time()
+--print(t)
+--math.randomseed(t)
function randomGenome()
- local len = math.ceil(math.random() * 300)
+ local len = math.ceil(math.random() * 3000)
local genome = {}
for i=1,len do
table.insert(genome, math.floor(256 * math.random()))
@@ -60,11 +154,6 @@ function randomGenome()
end
-local g = randomGenome()
-print(#g, metagrammar:expand(randomGenome()))
-os.exit(0)
-
-
function randomPop()
local pop = {}
for n=1,1000 do
@@ -74,24 +163,43 @@ function randomPop()
end
function evaluate(genome)
- local s = 'return function(close, volume, open, high, low) return ' .. grammar:expand(genome) .. ' end'
- -- print(s)
- local f = assert(loadstring(s))()
+ local target = function(x) return (x^4) + (x^3) + (x^2) + x end
+ local err, f = pcall(compileGenome, genome, 'x')
+ if err == false then
+ return -1e6
+ end
local cost = 0
for n=1,1000 do
- local start = math.ceil((#data-300) * math.random()) + 300
- local dataView = function(offset, i) return tonumber(string.match(data[1 + start + offset][i], '[^$]+')) end
- local close = function(offset) return dataView(offset, 2) end
- local volume = function(offset) return dataView(offset, 3) end
- local open = function(offset) return dataView(offset, 4) end
- local high = function(offset) return dataView(offset, 5) end
- local low = function(offset) return dataView(offset, 6) end
- ok, y = pcall(f, close, volume, open, high, low)
+ local env = {}
+ local future = 24*60
+ local range = (#data - future - 300)
+ local start = math.ceil((range * math.random())) + future
+ local dataView = function(offset)
+ -- 1 <= k <= #data
+ -- 1 <= 1 + start - future <= #data
+ -- 1 <= 1 + start + 299 <= #delta
+ return data[1 + start + offset]
+ end
+ env.close = function(offset) return dataView(offset).close end
+ env.volume = function(offset) return dataView(offset).volume end
+ env.open = function(offset) return dataView(offset).open end
+ env.high = function(offset) return dataView(offset).high end
+ env.low = function(offset) return dataView(offset).low end
+ env.math = math
+ -- print(#data, start)
+ -- print(data[2].volume, env.volume(-future), env.volume(299))
+ setfenv(f, env)
+ local x = (2*math.random()) - 1
+ ok, y = pcall(f, x)
-- if ok and type(y) == 'table' then for k,v in pairs(y) do print(k, v) end end
- if (not ok) or (y ~= y) then
+ if (not ok) or (y == nil) or (y ~= y) then
+ -- print('fail', y)
+ -- print(expandGenome(genome))
cost = cost + 100
else
- cost = cost + math.abs(y - high(-30))
+ -- local delta = env.high(-future) - env.high(0)
+ local delta = target(x)
+ cost = cost + (0.01 * (y - delta)^2)
end
end
return -(cost)
@@ -100,13 +208,18 @@ end
local ga = GA.createGA(randomPop(), {
evaluate=evaluate,
crossover=function(a, b)
- local crossoverPoint = math.ceil(#a * math.random())
+ local pointA = math.floor(#a * math.random())
+ local pointB = math.ceil(#b * math.random())
local new = {}
- for i=1,#b do
- table.insert(new, (i>=crossoverPoint and b[i]) or a[i])
+ for i=1,pointA do
+ table.insert(new, a[i])
+ end
+ for i=pointB,#b do
+ table.insert(new, b[i])
end
return new
end,
+ crossoverWeight = 10,
mutate=function(a)
local new = {}
for i,v in ipairs(a) do new[i] = v end
@@ -114,12 +227,14 @@ local ga = GA.createGA(randomPop(), {
new[mutationPoint] = math.floor(256 * math.random())
return new
end,
+ mutationWeight = 10,
+ reproductionWeight = 0.1,
})
for n=1,100 do
- print(ga:step())
- print(grammar:expand(ga.population[ga.bestMember]))
+ print(ga:step(8))
+ print(expandGenome(ga.population[ga.bestMember]))
end
-- for k,v in ipairs(ga.population) do