Code
--[[
GAB - Genetic Algorythm on Bands, with cuts (Bruno Kestemont)
based on Rav3n_pl
based on CartoonVillan and Crashguard303 scripts
Lua V2
Definitions:
band: randomised: start segment, end segment, length, strength
critter: set of bands
herd: set of critters
1.
- randomize needed bands
- randomly assignig them to criters
2.
- score each critter
3.
- keep critters scoring above score
- breed best critters
- breed bastards (best one + random one)
- forget about rest of critter
- randomize new critters to fill herd
VERSIONS:
2.0.5
2.0.5 Filter => Filter management added Bruno Kestemont 10/10/2013
16/04/2014: only added more score info in the log
3.0 : fuze using cuts 28/05/2014 Bruno Kestemont
3.1: cut bug fixed on deletecut 02/06/2014
3.2: using creditebest
3.3: creditbest bug fixed 02/06/2014 (do not use creditebest)
3.3.1: added Notes management and quicksaves for big gains (for archives when undo's) 4/11/2014
3.3.2: replaced shake by QuickShake 8/11/2014
3.3.3: debugged uncut
3.4.5: generic filter management and debugged segment to itself
3.4.6: detect ligand and always use ligand (optional)
3.4.7: 13/5/2015 changed small possible bugs
18/1/2016 log with archive of gains following jeff101 suggestions
reduced thresholds on Big Steps
Keeps user bands
Mutate once 5 days before the deadline or the 3 latest days for HBond puzzles
GENERICFILTER only latest days of non HBonds puzzles
FILTERMANAGE only on mid game
3.4.8: hide only hydrophobics
3.4.9 undo.SetUndo
3.4.10 fixed unideal loop bug
3.4.11 use ligand on ligand puzzle (not always), new wiggle
3.5 GRRR adapted filter setting to new lua commands: return2GlobalOriginalFilterSetting()
3.5.1 simplified the log
3.6 : added bands to symmetric chains
3.6.1: fixed segMeanScore=10*(800-absolutebest.GetScore())
3.6.2: if badGen<=herd.renew then -- bug fixed thanks to robgee
To Do: Partial filter management, unless end Fuze and end Qstab // to verify
]]--
recipename="Rav3n_pl GAB 3.6.2 filter Cuts"
undo.SetUndo(false)
OriginalFilterSetting = filter.AreAllEnabled() -- new BK 8/4/2013
PROBABLEFILTER=false
HASMUTABLE=false -- NEW BK 10/10/2013
timeLeft=os.difftime(puzzle.GetExpirationTime(),os.time())/86400 -- in days
segCnt=structure.GetCount()
segCnt2=segCnt
SYMMETRIC= structure.GetSymCount () > 0 -- not used yet
--detect ligand
while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2=segCnt2-1 end
HASLIGAND=segCnt2<segCnt
startLigand=segCnt2+1
stopLigand=segCnt
math.randomseed(os.clock()) -- 28/05/2014
math.random() -- 28/05/2014
p=print
userbands=band.GetCount()
p("Starting "..recipename.. " on\n puzzle "..(puzzle.GetName()))
p(' with puzzle ID '..(puzzle.GetPuzzleID())..' and '..userbands..' user-supplied bands.\n ')
-- START Wiggle Power Setting stuff
function DisplayLongWigglePower ()
local PowerSetting = behavior.GetWigglePower()
local result = ""
if PowerSetting == "l" then result = "Low"
elseif PowerSetting == "m" then result = "Medium"
elseif PowerSetting == "h" then result = "High"
elseif PowerSetting == "a" then result = "Auto"
end
return result
end
OriginalWPowerSetting= DisplayLongWigglePower ()
print(OriginalWPowerSetting .. " Wiggle Power")
function CheckWP() -- including Alarm Dialog
if OriginalWPowerSetting == "Low" or OriginalWPowerSetting == "Auto" then
local ask=dialog.CreateDialog("Wiggle Power is ".. OriginalWPowerSetting)
ask.l1=dialog.AddLabel("Are you sure ?")
ask.continue=dialog.AddButton("Continue",1)
ask.stop=dialog.AddButton("Cancel",0)
askresult=dialog.Show(ask)
if askresult < 1 then return false end
end
return true
end
-- STOP Wiggle Power Setting stuff
function return2GlobalOriginalFilterSetting()
if OriginalFilterSetting then -- if true, all filters are default enabled
filter.EnableAll() --Enables all filters
else
filter.DisableAll() --Disables all filters
end
end
--START Generic Filter Management by BitSpawn 21/12/2014
--Source: http://fold.it/portal/node/1998917
--identifying filtered puzzles and all properties
OriginalFilterSetting = filter.AreAllEnabled()
PROBABLEFILTER= false
GENERICFILTER=false
FILTERMANAGE= false
HASMUTABLE= false
IDEALCHECK= false
PROBABLESYM= false
SEPSIS= false
ELECTRON= false
CENTROID= false
HOTSPOT= false
HBOND=false
sym=1
--START extraction of information from puzzle metadata --Extrait des infos
function detectfilterandmut() -- Bruno Kestemont 10/10/2013; 13/2/2015; 5/1/2019
local descrTxt=puzzle.GetDescription()
local puzzletitle=puzzle.GetName()
local function SymetryFinder() -- by Bruno Kestemont 7/2/2013, 25/8/2013
local segMeanScore=10*(800-absolutebest.GetScore()) -- top score pour eviter les debuts de puzzle
--p("Score moyen par segment= "..segMeanScore)
if PROBABLESYM then
if segMeanScore<33.39 then sym=1
PROBABLESYM=false
elseif segMeanScore<85 then sym=2
elseif segMeanScore<132 then sym=3
elseif segMeanScore<197 then sym=4
else sym=5
end
else sym=1
end
return
end
if #descrTxt>0 and (descrTxt:find("filter") or descrTxt:find("filters") or descrTxt:find("bonus") or descrTxt:find("bonuses") and not descrTxt:find("disabled"))then
PROBABLEFILTER=true
FILTERMANAGE=true -- default yes during wiggle (will always be activate when scoring)
GENERICFILTER=false -- to be evaluated
end
if #descrTxt>0 and (descrTxt:find("H-bond networks") or descrTxt:find("Hydrogen Bond Networks") or descrTxt:find("H-bond Networks")
or descrTxt:find("H-bond Network") and not descrTxt:find("disabled"))then
PROBABLEFILTER=true
FILTERMANAGE=false -- default no
GENERICFILTER=false -- to be evaluated
end
if #descrTxt>0 and (descrTxt:find("design") or descrTxt:find("designs")) then
HASMUTABLE=true
IDEALCHECK=true
HANDFOLD=true
end
if #descrTxt>0 and (descrTxt:find("De-novo") or descrTxt:find("de-novo") or descrTxt:find("freestyle")
or descrTxt:find("prediction") or descrTxt:find("predictions")) then
IDEALCHECK=true
HANDFOLD=true
end
if #puzzletitle>0 then
if (puzzletitle:find("Sym") or puzzletitle:find("Symmetry") or puzzletitle:find("Symmetric")
or puzzletitle:find("Dimer") or puzzletitle:find("Trimer") or puzzletitle:find("Tetramer")
or puzzletitle:find("Pentamer")) then
PROBABLESYM=true
if puzzletitle:find("Dimer") and not puzzletitle:find("Dimer of Dimers") then sym=2
elseif puzzletitle:find("Trimer") or puzzletitle:find("trimer") then sym=3
elseif puzzletitle:find("Dimer of Dimers") or puzzletitle:find("Tetramer") then sym=4
elseif puzzletitle:find("Pentamer") then sym=5
else SymetryFinder()
end
end
end
if #descrTxt>0 and (descrTxt:find("Sym") or descrTxt:find("Symmetry") or descrTxt:find("Symmetric")
or descrTxt:find("sym") or descrTxt:find("symmetry") or descrTxt:find("symmetric")) then
PROBABLESYM=true
if (descrTxt:find("Dimer") or descrTxt:find("dimer") or descrTxt:find("C2 symmetry") or descrTxt:find("twoo symmetric"))
and not (descrTxt:find("Dimer of Dimers") or descrTxt:find("dimer of dimers")) then sym=2
elseif descrTxt:find("Trimer") or descrTxt:find("trimer") or descrTxt:find("C3 symmetry") or descrTxt:find("three symmetric") then sym=3
elseif (descrTxt:find("Dimer of Dimers") or descrTxt:find("Tetramer") or descrTxt:find("C4 symmetry") or descrTxt:find("four symmetric"))
and not (descrTxt:find("dimer of dimers") or descrTxt:find("tetramer"))then sym=4
elseif descrTxt:find("Pentamer") or descrTxt:find("pentamer") or descrTxt:find("C5 symmetry") or descrTxt:find("five symmetric") then sym=5
else SymetryFinder()
end
end
--print resulting sym info
if PROBABLESYM then
print("Symmetric")
if sym==2 then
print("Dimer")
elseif sym==3 then
print("Trimer")
elseif sym==4 then
print("Tetramer")
elseif sym==5 then
print("Pentamer")
elseif sym>5 then
print("Terrible polymer")
end
else print("Monomer")
end
if #puzzletitle>0 and puzzletitle:find("Sepsis") then -- new BK 17/6/2013
SEPSIS=true
HANDFOLD=true
--p(true,"-Sepsis")
print("Sepsis")
end
if #puzzletitle>0 and puzzletitle:find("Electron Density") then -- for Electron Density
--p(true,"-Electron Density")
ELECTRON=true
HANDFOLD=true
print("Electron density")
end
if #puzzletitle>0 and puzzletitle:find("Centroid") then -- New BK 20/10/2013
--p(true,"-Centroid")
CENTROID=true
print("Centroid")
end
if #puzzletitle>0 and puzzletitle:find("Hotspot") then -- New BK 21/01/2014
HOTSPOT=true
print("Hotspot")
end
return
end
detectfilterandmut()
--END extraction of information from puzzle metadata --Extrait des infos
-- function to copy class/table
function CopyTable(orig)
local copy = {}
for orig_key, orig_value in pairs(orig) do
copy[orig_key] = orig_value
end
return copy
end
-- functions for filters
function FiltersOn()
if filter.AreAllEnabled() then
filter.EnableAll()
end
end
function FiltersOff()
if filter.AreAllEnabled() and GENERICFILTER then -- 18/1/2016
filter.DisableAll()
end
end
-- function to overload a funtion
function mutFunction(func)
local currentfunc = func
local function mutate(func, newfunc)
local lastfunc = currentfunc
currentfunc = function(...) return newfunc(lastfunc, ...) end
end
local wrapper = function(...) return currentfunc(...) end
return wrapper, mutate
end
-- function to overload a class
-- to do: set the name of function
classes_copied = 0
myclcp = {}
function MutClass(cl, filters)
classes_copied = classes_copied+1
myclcp[classes_copied] = CopyTable(cl)
local mycl =myclcp[classes_copied]
for orig_key, orig_value in pairs(cl) do
myfunc, mutate = mutFunction(mycl[orig_key])
if filters==true then
mutate(myfunc, function(...)
FiltersOn()
if table.getn(arg)>1 then
-- first arg is self (function pointer), we pack from second argument
local arguments = {}
for i=2,table.getn(arg) do
arguments[i-1]=arg[i]
end
return mycl[orig_key](unpack(arguments))
else
--print("No arguments")
return mycl[orig_key]()
end
end)
cl[orig_key] = myfunc
else
mutate(myfunc, function(...)
FiltersOff()
if table.getn(arg)>1 then
local arguments = {}
for i=2, table.getn(arg) do
arguments[i-1]=arg[i]
end
return mycl[orig_key](unpack(arguments))
else
return mycl[orig_key]()
end
end)
cl[orig_key] = myfunc
end
end
end
-- how to use:
--setting default options if filters BK 4/2/2015
--MutClass(structure, false)
--MutClass(band, false)
--MutClass(current, true)
if GENERICFILTER then -- WARNING: TO VERIFY !! (may be it's irreversible for several funtions bellow)
MutClass(structure, false)
MutClass(band, true)
MutClass(current, true)
MutClass(recentbest, true) -- otherwise, it remembers cut solutions
MutClass(save, true) -- better to save with full score
end
--STOP Generic Filter Management
-- options:
energy = false --set true to seek energy in exploration puzzles; false works on all puzzles
pullCI = 0.9 --Clash Importance during pull
maxCI = 1 --maximum CI used by script
fastQstab = true -- only 1s1w after pull if true
fuzeThresh = 1 -- run fuze if we are close to best score (negative=new best score)
qstabThresh = 1 -- run qstab if score drops more than... wiggle only in other case
useLigand = false --use ligand if true
AlwaysUseLigand=false -- Warning: don't set true by default because there are some erroneous ligands
onlyMutable = false --if true use ONLY all mutable aas, no matter of always use
mutateOnce = false --if true use mutate(1) instead of shake in qstab
mutateOnceCI = 0.21 --mutate on what clashing importance
mutateAlwas = false --if true use mutate(1) instead of all shakes
mingps= 80 -- in wiggle sequence, this is the minimum gain per iteration needed to do the wiggle again (not zure it's very usefull to save time).
cut=structure.InsertCut -- 28/05/2014
--uncut=structure.DeleteCut -- 28/05/2014
if HASMUTABLE and not HBOND and timeLeft>4 and timeLeft<6 then mutateOnce = true print ("Option: mutate(1) instead of shake in qstab") end -- It's an option !
--if HASMUTABLE and not HBOND and timeLeft>4 then mutateAlwas = true print ("Option: mutate(1) instead of all shakes") end -- It's an option !
--Don't mutate just after hand fold (because of filters on AAs, better to mutate by purpose using recipes like MNW or Maaa)
--Don't mutate the last 4 days, it's slow and it will not gain.
if HASMUTABLE and HBOND and timeLeft<4 then mutateOnce = true print ("Option: mutate(1) instead of shake in qstab") end
--with HBonds, mutate a little bit later
if HASMUTABLE and HBOND and timeLeft<3 then FILTERMANAGE = true print ("Option: wiggle with filter disabled") end
--SLOTS:
--[[
3 is best
4 used in recipe
5 used in recipe
50-100 used to record each big steps for movie at the end
]]--
SlotStepStart=50 -- New 4/11/2014
SlotStep=SlotStepStart
herd= --herd options
{
breedBest = 5, --breed best 4 critters - all combinations => 6 kids form 4 critters, 3 form 3, 1 form 2, 9 form 5 ;]
keepBest = 3, --save up to 3 best scoring critters, rest are forgotten
breedBastards = 8, --number of best will have one random bastard
newRandom = 10, --adding new random ones each generation
maxGen= 100, --maximum generations
shuffle = true, --set true to run critters in random order
renew=4, --create totally fresh herd after that many gens w/o improvement
}
critter= --critter options
{
minBands=2, --minimum bands
maxBands=7, --maximum bands
keepScore = 0 , --survive to next gen only if score higher than
breedScore= -20, --will breed kids only if score higher. Basttards always breed
maxLoss=30, --maximum loss by critter. set 0 to disable
}
bands= --bands options
{
minStr=0.3, --minimum band str
maxStr=1.1, --maximum band str
minChng = 3, -- minimum length change of band (negative length pull or positive length push)
maxUp = 6.1, -- maximum length change up (push)
maxDn = 6.9, -- maximum length change down (pull)(will be used negative)
minSkip = 5, --minimum segment distance (not banding segments that are too proximate)
minDist = 4, --minimum spatial distance
minLen = 2, --minimum length of created band
}
DoNotUse={--just comment lines below or add more areas to avoid
--{segCnt,segCnt}, --ligand cant be used
--{120,134},
--{1,10},
}
AlwaysUse={ --areas should be always used
--{236,236}--ligand need to be at one end
--{308,311}, --loopy
--{272,319}, --loopy
}
UseSegments= --use ONLY this segments
{
--2,3,4,5
}
-- bands by secondary structure
use=
{
Sheet=true, --set false to not band sheets
Helix=true, --set false to not band helices
Loop=true, --set false to not band loops
}
checkBoth=false --check both ends to above, if false only one end need to be true
--end of options
if HASLIGAND then useLigand=true end
if useLigand==false then
segCnt=segCnt2
end
if HASLIGAND and AlwaysUseLigand then
AlwaysUse={ --areas should be always used
{startLigand,stopLigand}--ligand need to be at one end
--{308,311}, --loopy
--{272,319}, --loopy
}
end
function uncut(seg) -- new BK 02/06/2014
for i=1, structure.GetCount() do
structure.DeleteCut(i)
end
end
function CI(c)
if c>maxCI then c=maxCI end
behavior.SetClashImportance(c)
end
function round(x)--cut all afer 3-rd place
return x-x%0.001
end
function down(x)
return x-x%1
end
function Score()--return score, exploration too
if energy==true then
return current.GetEnergyScore()
else
return current.GetScore()
end
end
--local seed=recipe.GetRandomSeed() --NOT WORKING on windowz!!!
--calculate REALLY good seed from current score
seed=os.time()
seed=1/seed
while seed<10000000 do seed=seed*10 end
seed=seed-seed%1
p("Seed is: "..seed)
math.randomseed(seed)
math.random(100) -- Because the first is not random
format=string.format
--START Archive in Notes, -- New 4/11/2014
function SelectNote(recipename)
store={}
store.label=recipename or "" -- edit here the recipe name
store.note_number=structure.GetCount()
for seg=structure.GetCount(),1,-1 do
if structure.GetNote(seg)~="" then break end
store.note_number=seg
end
print(string.format("Recording results in Note for segment %i",store.note_number))
store.starting_score=current.GetScore()
--structure.SetNote(store.note_number,string.format("(%s) %.3f + FSP",user.GetPlayerName(),store.starting_score))
end
SelectNote(recipename)
function WhriteNote(loop_nb) -- all inits are in SelectNote function
local loop_count= loop_nb or 1
structure.SetNote(store.note_number,string.format("(%s) %.3f + %s(%i) %.3f",user.GetPlayerName(),store.starting_score,store.label,loop_count,current.GetScore()))
end
--END Archive in Notes
--START quick save algorithm
function QuickShake()
--[[------------------------------------------------------------------------------------------------
-- Algorithm for faster shake
REFERENCES
1. N/A
Copyright (C) 2014 Seagat2011 <http://fold.it/port/user/1992490>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
$Id$
------------------------------------------------------------------------------------------------]]--
--[[
v1
- Inception
1.2
- Loops until nogain
]]--
local idx = 1
local idx2 = structure.GetCount ()
local hash = {}
local cs = current.GetScore ()
--print ( 'Quick Shake Algorithm v1.2 SG2011 - Current Score: '..cs )
local function New ( obj )
return obj -- pass-new-obj-by-value
end
local _gses = New ( current.GetSegmentEnergySubscore )
local function SmartShake ( iters )
local gain = true
while (gain) do
gain = false
for i=idx,idx2 do
local ci = _gses ( i,'clashing' )
if ci < _gses ( i,'hiding' ) and
ci < _gses ( i,'packing' ) and
ci < _gses ( i,'ideality' ) and
ci < _gses ( i,'sidechain') and
ci < _gses ( i,'bonding' ) and
ci < _gses ( i,'other' ) and
ci < _gses ( i,'reference') then
selection.Select ( i )
end -- test ci --
end -- loop --
if selection.GetCount () then
local css = current.GetScore ()
structure.ShakeSidechainsSelected ( iters )
selection.DeselectAll ()
if current.GetScore () > css then
gain = true
end -- test --
end -- test --
end -- loopf --
end
structure.SmartShake = SmartShake
structure.SmartShake ( 1 )
--print ( 'Done.' )
end
--END quick save algorithm
function WiggleOld(how, iters, minppi)
if FILTERMANAGE then filter.DisableAll() end-- new BK 8/4/2013, always disable filter here
if how==nil then how="wa" end
if iters==nil then iters=6 end
if minppi==nil then minppi=0.1 end
if iters>0 then
iters=iters-1
sp=Score()
if how == "s" then
if FILTERMANAGE then return2GlobalOriginalFilterSetting() end -- new BK 8/4/2013, always back to user settings
if mutateAlwas==true then structure.MutateSidechainsSelected(1)
--else structure.ShakeSidechainsSelected(1) end
else QuickShake() end
elseif how == "wb" then structure.WiggleAll(2, true,false)
elseif how == "ws" then structure.WiggleAll(2, false,true)
elseif how == "wa" then structure.WiggleAll(2)
end
ep = Score()
ig=ep-sp
if how~="s" then
if ig > minppi then return Wiggle(how, iters, minppi) end --tail call
end
end
if FILTERMANAGE then return2GlobalOriginalFilterSetting() end -- new BK 10/10/2013, always back to user settings
end
function Wiggle(how, iters, minppi, valit, mingps) -- NEW one, with filter management, 17/4/2016
if FILTERMANAGE then filter.DisableAll() end-- new BK 8/4/2013, always disable filter here
if how==nil then how="wa" end
if iters==nil then iters=6 end
if minppi==nil then minppi=0.1 end
if valit==nil then valit= 1 end
if mingps==nil then mingps= 80 end -- the goal here is to save time
local loops = 0 -- only for log, no other use
if iters>0 then
startRecTime=os.clock ()
iters=iters-1
loops=loops+1 -- only for log, no other use
sp=Score()
if how == "s" then
if FILTERMANAGE then return2GlobalOriginalFilterSetting() end -- new BK 8/4/2013, always back to user settings
if mutateAlwas==true then structure.MutateSidechainsSelected(1)
--else structure.ShakeSidechainsSelected(1) end
else QuickShake() end
elseif how == "wb" then structure.WiggleAll(valit, true,false)
elseif how == "ws" then structure.WiggleAll(valit, false,true)
elseif how == "wa" then structure.WiggleAll(valit)
end
ep = Score()
ig=ep-sp
timeperiteration =os.clock ()-startRecTime
tppii=ig/timeperiteration
--print("g/s: "..ig.." / "..timeperiteration.." = "..tppii)
if how~="s" then
if ig > minppi
--and tppii > mingps --Test DEBUG for gaining time, but is this loosing gains ?
then
--print("Repeating Wiggle. Gain per second was "..tppii)
return Wiggle(how, iters, minppi, valit) end --tail call
end
end
if loops > 1 then
print("Wiggled "..loops.." times") -- for DEBUG
end
if FILTERMANAGE then return2GlobalOriginalFilterSetting() end -- new BK 10/10/2013, always back to user settings
end
wiggle=structure.WiggleAll -- 28/05/2014 No filter management
function SaveBest()
local g=Score()-bestScore
if g>0 then
if g>0.01 then p("Gained another "..round(g).." pts. Score: "..round(Score()).. " from "..round(ss)) end
bestScore=Score()
save.Quicksave(3)
end
end
function SaveRB()
if Score()>bestScore then
save.Quicksave(4)
recentbest.Restore() -- WARNING: it took the best including cuts
SaveBest()
save.Quickload(4)
end
end
function SaveCB() -- cut version 02/06/2014 , recent save no increment
if Score()>bestScore then
save.Quicksave(4)
recentbest.Restore() -- OK only is recentbest saved after deleting cuts
SaveBest()
save.Quickload(4)
end
end
function Qstab()
selection.SelectAll()
CI(0.1)
if mutateOnce==true then
CI(mutateOnceCI)
structure.MutateSidechainsSelected(1)
else
Wiggle("s",1)
end
if fastQstab==false then
CI(0.4)
Wiggle("wa",1)
CI(1)
Wiggle("s",1)
end
CI(1)
Wiggle()
end
function FuzeCuts(ci1) -- 28/05/2014 by pauldunn NB: no filter management here . 02/06/2014 recentbest bug fixed
local seg=math.random(structure.GetCount())
cut(seg)
CI(1)
wiggle(15,true,true)
CI(ci1) --ci(0.01)
wiggle(1,true,true)
CI(1)
wiggle(25,true,true)
uncut(seg)
recentbest.Save() -- NEW 02/06/2014 important to avoid recentbest in cut bug
wiggle(25,true,true)
CI(ci1) --ci(0.01)
wiggle(2,true,true)
CI(1)
wiggle(25,true,true)
end
function FuzeEnd()
CI(1)
Wiggle("wa",1)
Wiggle("s",1)
Wiggle()
srb()
end
function Fuze1(ci1,ci2)
CI(ci1)
Wiggle("s",1)
CI(ci2)
Wiggle("wa",1)
end
function Fuze2(ci1,ci2)
CI(ci1)
Wiggle("wa",1)
CI(1)
Wiggle("wa",1)
CI(ci2)
Wiggle("wa",1)
end
function srb()
recentbest.Restore() -- IMPORTANT: recentbest must be saved after deleting cut
SaveBest()
end
function scb()
recentbest.Restore() -- IMPORTANT: recentbest must be saved after deleting cut
SaveBest()
end
function FuzeWithCuts()
p("Fuzing with cuts...")
local scr=Score()
selection.SelectAll()
recentbest.Save()
Fuze1(0.3,0.6) FuzeEnd()
FuzeCuts(0.01) scb() -- NEW 28/05/2014, 02/06/2014
Fuze2(0.3,1) srb()
Fuze1(0.05,1) srb()
Fuze2(0.7,0.5) FuzeEnd()
FuzeCuts(0.1) scb() -- NEW 28/05/2014, 02/06/2014
Fuze1(0.07,1)
srb()
end
function random(n1,n2) --random function returns int or float depends on input vars
if n2==nil and n1==nil then
return math.random() --float
else
if n2==nil then
if n1%1==0 then
return math.random(n1) --integer
else
return math.random()*n1 --float
end
else
if n1%1==0 and n2%1==0 then
return math.random(n1,n2) --integer between
else
return math.random()*(n2-n1)+n1 --float between
end
end
end
end
function FillHerd() --fill up herd
local n=#critters
if n>0 then --fill up
n=herd.newRandom
else --fresh herd
n=herd.breedBest + herd.keepBest + herd.breedBastards
end
p("Randomizing "..n.." new critters...")
for i=1,n do
AddCritter()
end
end
function AddCritter() --create new random critter
local c={}
critterID=critterID+1
c.no=critterID
c.name=c.no..'-rnd'
c.bands={}
local r=random(critter.minBands, critter.maxBands)
for i=1,r do
c.bands[#c.bands+1]=AddBand()
end
critters[#critters+1]=c
--p(c.name.." bands: "..#c.bands) -- suppressed from the log, I don't see the use of this
end
function AddBand() --create one random band (random push or pull)
local cnt=0
local b={}
while true do --try till die
cnt=cnt+1
local s1=random(segCnt)
local branch= random(structure.GetSymCount ()+1)-1 -- 0 if monomer, equal probability for each branch
if onlyMutable==true or #UseSegments>0 then
s1=UseSegments[random(#UseSegments)]
end
local s2=random(segCnt)
if s1>s2 then s1,s2=s2,s1 end --swap
if #UseSegments>0 or CanBeUsed(s1,s2) then
local str=random(bands.minStr,bands.maxStr)
local len=0
while true do --randomize correct distance
len=random(-bands.maxDn,bands.maxUp) -- the goal change from pull to push
if len<-bands.minChng or len>bands.minChng then break end
end
b={s1,s2,str,len, branch}
break
end
if cnt>100 then
p("Sorry! Cant create band! Breaking script!")
--BreakScript() --there is no such function, so it crashes script
break
end
end
return b
end
function CanBeUsed(sg1,sg2) --checking end of bands
function ssCheck(ss)
local good=false
if use.Sheet and ss=="E" then good=true end
if use.Helix and ss=="H" then good=true end
if use.Loop and ss=="L" then good=true end
return good
end
function AreGood(s1,s2) --check that s1 and s2 can be used
local ok=true
if s2-s1<bands.minSkip then ok=false end
if ok==true and structure.GetDistance(s1,s2)<bands.minDist then ok=false end
return ok
end
local ok=AreGood(sg1,sg2)
if ok==true and #DoNotUse>0 then --none of 2 can be in that area
for i=1, #DoNotUse do
local r=DoNotUse[i]
for x=r[1],r[2] do
if x==sg1 or x==sg2 then
ok=false
break
end
end
if ok==false then break end
end
end
if ok==false then
return false --if false can`t be used
else
ok=false
if #AlwaysUse>0 then --at least one have to be there
for i=1, #AlwaysUse do
local r=AlwaysUse[i]
for x=r[1],r[2] do
if x==sg1 or x==sg2 then
ok=true
break
end
end
if ok==true then break end
end
else
ok=true
end
end
if ok==true then --check structure
ok=false
local ss1=structure.GetSecondaryStructure(sg1)
local ss2=structure.GetSecondaryStructure(sg2)
if checkBoth then
if ssCheck(ss1) and ssCheck(ss2) then ok=true end
else
if ssCheck(ss1) or ssCheck(ss2) then ok=true end
end
end
return ok
end
function deletebands() --leave user bands intact
nbands=band.GetCount()
if nbands>userbands then
for i=nbands,userbands+1,-1 do -- count down from nbands to userbands+1
band.Delete(i)
end -- for i
end -- if nbands
end -- function
function ScoreHerd() --makes the bands and score all critters from herd
save.Quickload(3)
p("Scoring "..#critters.." critters...")
save.Quicksave(5)
local herdScore=Score()
for i=1,#critters do
deletebands()
local crt=critters[i] --critter
local s=Score() --start score
local bnds=crt.bands -- b={s1,s2,str,len, branch} (len is the random push or pull difference of length)
for b=1,#bnds do
local bnd=bnds[b]
if bnd[1] ~= bnd[2] then -- new debugging, no band to itself
local a1=5
local a2=5
if bnd[1]== structure.GetCount() then a1=6 end
if bnd[2]== structure.GetCount() then a2=6 end -- changed a1 to a2 13/5/2015
if structure.GetAminoAcid(bnd[1])=='g' then a1=0 end
if structure.GetAminoAcid(bnd[2])=='g' then a2=0 end
if not structure.IsHydrophobic(bnd[1]) and bnd[4]<0 then a1=0 end -- only hiding hydrophobics
if not structure.IsHydrophobic(bnd[2]) and bnd[4]<0 then a2=0 end
if structure.IsHydrophobic(bnd[1]) and bnd[4]>0 then a1=0 end -- don't push hydropobics to water
if structure.IsHydrophobic(bnd[2]) and bnd[4]>0 then a2=0 end
band.AddBetweenSegments(bnd[1],bnd[2],a1,a2, bnd[5]) -- 5 is the branch for symmetrics
local bc=band.GetCount()
band.SetStrength(bc,bnd[3])
local len=structure.GetDistance(bnd[1],bnd[2])+bnd[4] -- distance between segments + band length change (+ or -)
if len<bands.minLen then len=bands.minLen end
band.SetGoalLength(bc,len)
--print("Band: "..bnd[1].."-"..bnd[2].." a1: "..a1.." a2: "..a2.." str: "..round3(bnd[3]).." length= "..round3(length))
end
end
selection.SelectAll()
CI(pullCI)
recentbest.Save()
local seg=math.random(structure.GetCount()) -- new 28/05/2014
cut(seg) -- new 28/05/2014
Wiggle("wb",1)
uncut(seg)-- new 28/05/2014 PROBLEM here, recentbest includes cuts
recentbest.Save() -- NEW 02/06/2014 to avoid recent best in cuts
deletebands()
CI(1)
if math.abs(s-Score()) > qstabThresh then
Qstab()
else
Wiggle()
end
if Score()-bestScore>fuzeThresh then
SaveRB()
FuzeWithCuts() -- new 02/06/2014
else
SaveRB()
end
crt.score=Score()-s
-- p("Critter "..crt.name.." : "..round(crt.score)) -- eliminated ! I don't see the use of publishing this !
if critter.maxLoss>0 then
if Score()>herdScore-critter.maxLoss then
save.Quicksave(5)
herdScore=Score()
else
save.Quickload(5)
end
else
save.Quickload(3)
end
end
save.Quickload(3)
if band.GetCount()>0 then --clean bands from best solution (if any)
deletebands()
save.Quicksave(3)
end
end
function BreedCritters(mom,dad,t) --breed 2 critters. bands are taken randomly
local kid={}
critterID=critterID+1
kid.no=critterID
kid.name=kid.no.."-"..t..mom.no..'/'..dad.no
kid.bands={}
local mb=#mom.bands
local db=#dad.bands
if mb>db then mb,db=db,mb end --kid have bands count between mom and dad bands
local bn=random(mb,db)
for i=1,bn,2 do
kid.bands[#kid.bands+1]=mom.bands[random(#mom.bands)]
kid.bands[#kid.bands+1]=dad.bands[random(#dad.bands)]
end
--p(kid.name.." bands: "..#kid.bands) -- suppressed, I don't see the use of this info
return kid
end
function KeepGood() --copy best scoring critters form last gen if score above
local newHerd={}
for i=1,herd.keepBest do
if critters[i].score>critter.keepScore and (math.abs(critters[i].score)>0.1 or critters[i].score>0) then
newHerd[#newHerd+1]=critters[i]
end
end
return newHerd
end
function SortCritters() --bubble sort
for i=1,#critters do
for j=i+1,#critters do
if critters[i].score<critters[j].score then
critters[i],critters[j]=critters[j],critters[i] --love lua :)
end
end
end
end
function BreedHerd()
p("Breeding...")
SortCritters()
newHerd=KeepGood()
for i=1, herd.breedBest do
local mom=critters[i]
if mom.score>critter.breedScore or i<2 then --breed only good ones, 1st is always breed anyway
for j=i+1, herd.breedBest do
local dad=critters[j]
newHerd[#newHerd+1]=BreedCritters(mom,dad,"kid-")
newHerd[#newHerd+1]=BreedCritters(dad,mom,"kid-")
end
end
end
for i=1, herd.breedBastards do --they will always appear ;]
local mom=critters[i]
local j=random(herd.breedBastards+1,#critters)
local dad=critters[j]
newHerd[#newHerd+1]=BreedCritters(mom,dad,"bas-")
newHerd[#newHerd+1]=BreedCritters(dad,mom,"bas-")
end
critters=newHerd
FillHerd()
end
function ShuffleHerd()
if herd.shuffle==true then
for i=1,#critters do
local r=random(#critters)
if r~=i then
critters[i],critters[r]=critters[r],critters[i]
end
end
end
end
function GAB()
if onlyMutable==true then
for i=1,segCnt do
if structure.IsMutable(i) then
UseSegments[#UseSegments+1]=i
end
end
end
if #AlwaysUse>0 then
for i=1,#AlwaysUse do
local ss=AlwaysUse[i][1]
local se=AlwaysUse[i][2]
if ss>se then ss,se=se,ss end
for j=ss,se do
UseSegments[#UseSegments+1]=j
end
end
AlwaysUse={} --added to list, no need to check later
end
bestScore=Score()
critterID=0
gen=0
ss=Score()
ssstr=(round(ss))
save.Quicksave(3)
recentbest.Save()
p("Starting "..recipename.." score: "..round(ss))
critters={}
FillHerd()
badGen=0
while true do --this is (almost) endless script ;]
undo.SetUndo(false) -- reset if gain before end of loop
genScore=Score()
gen=gen+1
p()
p("Generation: "..gen..", score: "..round(Score())..", gain: "..round(Score()-ss).." ("..(os.date())..")")
ShuffleHerd()
ScoreHerd()
save.Quickload(3)
if gen==herd.maxGen then break end --end of script
if genScore<=Score() then badGen=badGen+1 else badGen=0 end
if badGen<=herd.renew then -- bug fixed thanks to robgee
p("Creating fresh random herd...")
critters={}
FillHerd()
badGen=0
else
BreedHerd()
end
genEndScore=Score()
genGain=genEndScore-genScore
if gen>1 and (gen-1)==5*down((gen-1)/5) then -- New 18/1/2016 jeff101 log display
ssstr=(ssstr..'\n ') -- start new line every 5 generations
end
if genGain>=0 then
ssstr=(ssstr..' + '..round(genGain))
undo.SetUndo(true)
else
ssstr=(ssstr..' - '..(-round(genGain)))
end
p(ssstr..' = '..round(genEndScore))
WhriteNote(gen) -- New 4/11/2014
SaveBigSteps() -- New 4/11/2014 for movie at the end
end
p("Final score: "..round(Score()).." Total gain: "..round(Score()-ss))
end
--START Movie store big steps
StepScore= Score() -- New 4/11/2014
function StoreBigStep()
StepScore= Score()
save.Quicksave(SlotStep)
SlotStep=SlotStep+1
end
function SaveBigSteps() -- in order to be able to display big steps afterwards in undos
local g=Score()-StepScore
local s= Score()
if s >0 and ( (s <7000 and g>500) or (s <9000 and g>200) or (s <10000 and g>100) or (s >10000 and g>50)) then
StoreBigStep()
end
end
function MovieSteps()
undo.SetUndo(true)
for i= SlotStepStart, SlotStep do
save.Quickload(SlotStep)
end
--save.Quickload(3)
print("See remembering of big steps in undos")
end
--END Movie store big steps
function Cleanup(err) -- NEW BK 10/10/2013
print("Restoring CI, best result, filter and structures")
CI(1)
undo.SetUndo(true)
if FILTERMANAGE then return2GlobalOriginalFilterSetting() end -- new BK 8/4/2013, always back to user settings
MovieSteps() -- New 4/11/2014
save.Quickload(3)
MovieSteps()
WhriteNote(gen) -- New 4/11/2014
deletebands()
print(err)
end
-- main call
--GAB()
xpcall(GAB,Cleanup) -- NEW BK 10/10/2013
--end of script