From 8f4210371554f318493f875491159acdb3fedcff Mon Sep 17 00:00:00 2001 From: sanine Date: Fri, 3 Jan 2025 12:27:10 -0600 Subject: implement ddfs --- example.lua | 207 ++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 161 insertions(+), 46 deletions(-) (limited to 'example.lua') 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[""] = { {'0'}, {'1+', ''} } local metagrammar = Grammar.createGrammar(metaproduction, {}) +function baseProduction() + local production = {} + production[""]={{ 'return ',''}} + production[""]={ + {'x'}, {''}, + -- {''}, {''}, + -- {''}, {''}, + {'(','','','',')'}, {'','(','',')'} + } + production[""]={ {'+'}, {'-'}, {'*'}, {'/'} } + production[""]={ {'math.log'}, {'math.exp'}, {'math.sin'}, {'math.cos'}, {'math.tan'}, } + production[""]={ {'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'} } + production[""]={ {'0'}, {'1'}, {'2'} } + production[""]={ + {'high(','',')'}, {'low(','',')'}, + -- {'volume(','',')'}, + {'open(','',')'}, {'close(','',')'} + } + production[""]={ {'','', ''} } + production[""]={ {'0.','','',''} } + 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[""], {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, '') + if i ~= arity then + table.insert(fnExpansion, ', ') + end + end + table.insert(fnExpansion, ')') + table.insert(production[""], fnExpansion) + end -local production = {} -production[""]={{''}} -production[""]={ {''}, {''}, {'(','','','',')'}, {'','(','',')'} } -production[""]={ {'+'}, {'-'}, {'*'}, {'/'} } -production[""]={ {'math.log'}, {'math.exp'}, {'math.sin'}, {'math.cos'}, {'math.tan'}, } -production[""]={ {'0'}, {'1'}, {'2'}, {'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'} } -production[""]={ {'0'}, {'1'}, {'2'} } -production[""]={ - {'high(','',')'}, {'low(','',')'}, - {'volume(','',')'}, - {'open(','',')'}, {'close(','',')'} -} -production[""]={ {'','', ''} } -production[""]={ {'0.','','',''} } + -- 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 -- cgit v1.2.1