Skip to content

Instantly share code, notes, and snippets.

@Rav3nPL
Created January 13, 2015 20:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rav3nPL/a5836333e0b4f3d3b5e4 to your computer and use it in GitHub Desktop.
Save Rav3nPL/a5836333e0b4f3d3b5e4 to your computer and use it in GitHub Desktop.
Foldit GAB v2.2 filters
--[[
GAB - Genetic Algorithm on Bands
by 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 assigning them to critters
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
]]--
-- options:
filters=true --if true filters are enabled only for scoring
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
CapCI=false --false=use maxci as multiplier, true=just cap it to maxci
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
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
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 generations 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. Bastards 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 change of band len according to current distance
maxUp = 6.1, -- maximum change up (push)
maxDn = 6.9, -- maximum change down (pull)
minSkip = 5, --minimum segment distance
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
--{segCnt,segCnt},--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
function filtersOn()
if filters then
behavior.SetSlowFiltersDisabled(false)
end
end
function filtersOff()
if filters then
behavior.SetSlowFiltersDisabled(true)
end
end
segCnt=structure.GetCount()
if useLigand==false then
while structure.GetSecondaryStructure(segCnt)=="M" do segCnt=segCnt-1 end
end
p=print
function CI(c)
if c>maxCI then
if CapCI==true then
c=maxCI
else
c=c*maxCI
end
end
behavior.SetClashImportance(c)
end
function round(x)--cut all after 3-rd place
return x-x%0.001
end
function down(x)
return x-x%1
end
function Score()--return score, exploration too
filtersOn()
local s=0
if energy then
s=current.GetEnergyScore()
else
s=current.GetScore()
end
filtersOff()
return s
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)
function Wiggle(how, iters, minppi)
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 mutateAlwas==true then structure.MutateSidechainsSelected(1)
else structure.ShakeSidechainsSelected(1) 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
end
function SaveBest()
local g=Score()-bestScore
if g>0 then
if g>0.01 then p("Gained another "..round(g).." pts.") end
bestScore=Score()
save.Quicksave(3)
end
end
function SaveRB()
local rb=0
filtersOn()
if energy==true then
rb= recentbest.GetEnergyScore()
else
rb= recentbest.GetScore()
end
if rb>bestScore then
save.Quicksave(4)
recentbest.Restore()
SaveBest()
save.Quickload(4)
end
filtersOff()
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 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()
SaveBest()
end
function Fuze()
p("Fuzing...")
local scr=Score()
selection.SelectAll()
filtersOn()
recentbest.Save()
filtersOff()
Fuze1(0.3,0.6) FuzeEnd()
Fuze2(0.3,1) srb()
Fuze1(0.05,1) srb()
Fuze2(0.7,0.5) FuzeEnd()
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)
end
function AddBand() --create one random band
local cnt=0
local b={}
while true do --try till die
cnt=cnt+1
local s1=random(segCnt)
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)
if len<-bands.minChng or len>bands.minChng then break end
end
b={s1,s2,str,len}
break
end
if cnt>100 then
p("Sorry! Cant create band! Breaking script!")
BreakScript() --there is no such function, so it crashes script
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 ScoreHerd() --score all critters from herd
save.Quickload(3)
p("Scoring "..#critters.." critters...")
save.Quicksave(5)
local herdScore=Score()
for i=1,#critters do
band.DeleteAll()
local crt=critters[i] --critter
local s=Score() --start score
local bnds=crt.bands
for b=1,#bnds do
local bnd=bnds[b]
local a1=5
local a2=5
if bnd[1]== structure.GetCount() then a1=6 end
if bnd[2]== structure.GetCount() then a1=6 end
if structure.GetAminoAcid(bnd[1])=='g' then a1=0 end
if structure.GetAminoAcid(bnd[2])=='g' then a2=0 end
band.AddBetweenSegments(bnd[1],bnd[2],a1,a2)
local bc=band.GetCount()
band.SetStrength(bc,bnd[3])
local len=structure.GetDistance(bnd[1],bnd[2])+bnd[4]
if len<bands.minLen then len=bands.minLen end
band.SetGoalLength(bc,len)
end
selection.SelectAll()
CI(pullCI)
recentbest.Save()
Wiggle("wb",1)
band.DeleteAll()
CI(1)
if math.abs(s-Score()) > qstabThresh then
Qstab()
else
Wiggle()
end
if Score()-bestScore>fuzeThresh then
SaveRB()
Fuze()
else
SaveRB()
end
crt.score=Score()-s
p("Critter "..crt.name.." : "..round(crt.score))
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)
band.DeleteAll()
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)
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()
save.Quicksave(3)
recentbest.Save()
p("Starting Rav3n_pl GAB Start score: "..round(ss))
filtersOff()
critters={}
FillHerd()
badGen=0
while true do --this is (almost) endless script ;]
genScore=Score()
gen=gen+1
p()
p("Generation: "..gen..", score: "..round(Score())..", gain: "..round(Score()-ss))
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
p("Creating fresh random herd...")
critters={}
FillHerd()
badGen=0
else
BreedHerd()
end
end
filtersOn()
p("Final score: "..round(Score()).." Total gain: "..round(Score()-ss))
end
-- main call
GAB()
--end of script
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment